Django 및 Alpine의 간단한 작업 목록입니다.Js, Tailwidcss 및 Axios

돌아왔을 때, 나는 알프스 산의 Django로 todo 응용 프로그램을 만드는 방법에 관한 강좌를 썼다.그러나 js와 Axios는 아직 개선된 공간이 있습니다. 제가 Alpine를 사용하기 시작했기 때문에 새로운 버전을 작성하기로 결정했습니다.
이 강좌에서, 나는 당신에게 어떻게 사용하는지 보여 드리겠습니다
  • Django
  • 후미풍 CSS
  • 알프스 산.js
  • Axios
  • 우리는 그것을 두 부분으로 나눌 것이다
  • Django
  • 를 사용하여 백엔드 구축
  • TailwindCSS를 사용하여 Alpine이 프런트엔드를 구축하고 백엔드에 연결합니다.js 및 Axios
  • 검사GitHub의 완료된 항목

    백엔드


    먼저 새 프로젝트와 가상 환경을 만들고 Django를 설치합니다.
    pip install Django
    
    그리고 Django 프로젝트, tasks라는 프로그램을 만듭니다.
    django-admin startproject todo_list .
    django-admin startapp tasks
    
    INSTALLED_APPS 파일에 작업 응용 프로그램 settings.py 을 추가합니다.
    INSTALLED_APPS = [
        django.contrib.admin,
        django.contrib.auth,
        django.contrib.contenttypes,
        django.contrib.sessions,
        django.contrib.messages,
        django.contrib.staticfiles,
        tasks # Add newly created app
    ]
    
    현재 tasks 응용 프로그램과 models.py 파일로 이동하여 우리의 작업에 모델을 만듭니다
    from django.db import models
    
    class Task(models.Model):
        title = models.CharField(max_length=255)
        completed = models.BooleanField(default=False)
    
    간단하게 보기 위해서, 우리는 단지 두 필드 titlecompleted 를 사용해야 한다
    다음은 작업 상태를 읽기, 만들기, 삭제, 업데이트하는 보기를 만듭니다.
    from django.http import JsonResponse
    from django.shortcuts import get_object_or_404
    
    from tasks.models import Task
    
    def task_list(request):
        tasks = [{id: task.id,
                  title: task.title,
                  completed: task.completed} for task in Task.objects.all()]
        return JsonResponse(status=200, data=tasks, safe=False)
    
    def create_task(request):
        title = request.POST.get(title)
        if not title:
            return JsonResponse(status=400, data={error: title is required})
        task = Task.objects.create(title=title)
        return JsonResponse(status=201, data={title: task.title,
                                              completed: task.completed,
                                              id: task.id}, safe=False)
    
    def delete_task(request, task_id):
        task = get_object_or_404(Task, pk=task_id)
        task.delete()
        return JsonResponse(status=204, data={message: task deleted})
    
    def update_task_status(request, task_id):
        task = get_object_or_404(Task, pk=task_id)
        status = request.POST.get(status)
        if not status:
            return JsonResponse(status=400, data={error: status is required})
        task.completed = int(status)
        task.save()
        return JsonResponse(status=204, data={message: task status updated})
    
    현재, urls.py 프로그램에서 tasks 파일을 만들고, 보기를 위한 URL 루트를 만듭니다.
    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        path(tasks/, views.task_list, name=task_list),
        path(tasks/create/, views.create_task, name=create_task),
        path(tasks/<int:task_id>/delete/, views.delete_task, name=delete_task),
        path(task/<int:task_id>/update/, views.update_task_status, name=update_task)
    ]
    
    이제 응용 프로그램의 마스터urls.py 파일로 이동하고 작업 응용 프로그램 URL을 포함합니다.
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path(admin/, admin.site.urls),
        path(, include(tasks.urls)),
    ]
    
    마이그레이션을 실행하고 어플리케이션을 시작합니다.
    python manage.py makemigratinos
    python manage.py migrate
    python manage.py runserver
    
    현재 HTTP 클라이언트를 사용하고 있습니다 httpie. 그러나 다른 도구를 사용할 수 있습니다 (예: postman 또는 insomia.
    우리의 단점을 테스트하다.다음은 제가 사용하고 있는 httpie 명령입니다.
    # Making Get request to retrive task list
    http http://127.0.0.1:8000/tasks
    
    # To test the POST/DELETE request you will need to add @csrf_exempt 
    # decorator to the views, to bypass the csrf token check, 
    # so you don’t need to pass csrf token in http client.
    # Once we will be building front-end part you can delete the decorator
    
    # Making POST request to create a task 
    http -f POST http://127.0.0.1:8000/tasks/create/ title=Clean the dishes
    
    # Making task Delete request 
    http -f DELETE http://127.0.0.1:8000/tasks/1/delete/
    
    # Making POST request to update a task status
    http -f POST http://127.0.0.1:8000/tasks/2/update/ status=1
    
    데이터베이스를 채우기 위한 작업을 만듭니다.
    앞쪽으로 가기 전에 홈페이지를 위한 마지막 보기를 만듭니다.views.py 파일로 이동하여 간단한 보기를 만듭니다.
    def index(request):
        return render(request, index.html)
    
    마지막으로 urls.py 응용 프로그램의 tasks에 추가합니다.
    urlpatterns = [
        path(, views.index, name=index),
        path(tasks/, views.task_list, name=task_list),
        path(tasks/create/, views.create_task, name=create_task),
        path(tasks/<int:task_id>/delete/, views.delete_task, name=delete_task),
        path(tasks/<int:task_id>/update/, views.update_task_status, name=update_task)
    ]
    

    프런트 엔드

    tasks 응용 프로그램에서 templates 라는 디렉터리를 만들고 index.html 라는 파일에서 만듭니다.
    TailwindCSS, Alpine을 포함한 CDN<head>의 js 및 Axios
    <!DOCTYPE html>
    <html lang=“en”>
      <head>
        <meta charset=“UTF-8”>
        <meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
        <meta http-equiv=“X-UA-Compatible” content=“ie=edge”>
        <title>Simple ToDo List</title>
    
        <link href=“https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css” rel=“stylesheet”>
        <script src=“https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js” defer></script>
        <script src=“https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js” defer></script>
    
      </head>
    
      <body>
    
      </body>
    </html>
    
    작업과 작업 목록 구성 요소를 추가하기 위한 간단한 폼을 만들어야 합니다.
    표부터 시작합시다.본문에 작업을 추가하기 위한 입력 및 단추 추가
    <div class=“max-w-4xl mx-auto mt-6>
    
          <div class=“text-5xl font-extrabold leading-none tracking-tight text-center>
              <h1 class=“bg-clip-text text-transparent bg-gradient-to-r from-indigo-500 via-pink-600 to-purple-900>Simple To-Do List</h1>
          </div>
    
          <!-- Task Input -->
          <div id=“task-input” class=“mt-4 flex justify-center>
              <div class=“m-4 flex>
                  <input class=“rounded-l-lg p-4 border-t mr-0 border-b border-l text-gray-800 border-gray-200 placeholder=“Task Title/>
                  <button class=“px-8 rounded-r-lg bg-purple-800 text-gray-100 font-bold p-4 uppercase>Add Task</button>
              </div>
          </div>
    
      </div>
    

    이제 작업 구성 요소를 만듭니다. 완성할 작업이 필요하고, 완성하지 않은 작업이 필요합니다.
    <!-- Task Input -->
    <div id=“task-input” class=“mt-4 flex justify-center>
        <div class=“m-4 flex>
            <input class=“rounded-l-lg p-4 border-t mr-0 border-b border-l text-gray-800 border-gray-200 placeholder=“Task Title/>
            <button class=“px-8 rounded-r-lg bg-purple-800 text-gray-100 font-bold p-4 uppercase>Add Task</button>
        </div>
    </div>
    
    <!-- Task List -->
    <div id=“task-list” class=“max-w-md mx-auto grid grid-cols-1 gap-2 mt-6>
    
        <!-- Task in progress -->
        <div class=“p-4 bg-white hover:bg-gray-100 cursor-pointer flex justify-between items-center border rounded-md>
            <p>Uncompleted Task</p>
            <button type=“button”>
                <svg class=“h-6 w-6 text-gray-500 hover:text-green-500 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
                    <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z />
                </svg>
            </button>
        </div>
    
        <!-- Completed Task -->
        <div class=“p-4 bg-white hover:bg-gray-100 cursor-pointer flex justify-between items-center border rounded-md>
            <p class=“line-through”>Completed Task</p>
            <svg class=“h-6 w-6 text-green-500 xmlns=“http://www.w3.org/2000/svg” viewBox=“0 0 20 20” fill=“currentColor”>
                <path fill-rule=“evenodd” d=“M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z clip-rule=“evenodd” />
            </svg>
        </div>
    
    </div>
    

    자, 이제 HTML이 생겼습니다. 준비가 됐습니다. 알파인을 사용해서 연결합시다.js 및 Axios
    우리는 먼저 앞에서 만든 초기 작업으로 목록을 채웁니다.
    바디 태그를 닫기 전에 <script> 태그를 열고 Alpine 구성 요소에 대한 기능을 만듭니다.
    우리는 우리의 임무를 수용하기 위해 tasks 수조를 만들 것이며, 함수를 우리가 앞views.py에서 만든 단점과 같게 할 것이다
    <script>
        function todos() {
            return {
                tasks: [],
                loadTasks() {},
                addTask() {},
                deleteTask(taskId) {},
                updateTask() {},
            }
        }
      </script>
    </body>
    
    loadTasks()부터 시작하겠습니다.
    loadTasks() {
        let self = this;
        axios.get(http://127.0.0.1:8000/tasks/’)
          .then(function (response) {
            // handle success
            self.tasks = response.data;
          })
          .catch(function (error) {
            // handle error
            console.log(error);
          });
    }
    
    이제 HTML로 돌아가서 x-data 속성과 x-init 을 작업 입력과 작업 목록을 포함하는 div에 추가합니다.
    <div x-data=“todos()” x-init=“loadTasks()” class=“max-w-4xl mx-auto mt-6>
    
    x-init는 구성 요소가 초기화된 후에 함수를 실행하는 데 사용되기 때문에 우리가 가지고 있는 작업 목록을 얻을 수 있습니다.현재tasklistdiv로 넘어가서 내부에 <template> 태그를 만들어서 작업 구성 요소를 봉인하고 x-for 속성을 추가해서 목록의 모든 작업을 교체합니다
    <!-- Task List -->
    <div id=“task-list” class=“max-w-md mx-auto grid grid-cols-1 gap-2 mt-6>
        <template x-for=“task in tasks>
            <div class=“p-4 bg-white hover:bg-gray-100 cursor-pointer flex justify-between items-center border rounded-md>
                <p>Uncompleted Task</p>
                <button type=“button”>
                    <svg class=“h-6 w-6 text-gray-500 hover:text-green-500 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
                        <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z />
                    </svg>
                </button>
            </div>
        </template>
    </div>
    
    현재 페이지를 다시 불러올 때 두 개의 작업이 있어야 합니다. 작업 구성 요소를 수정하고 /tasks/ 단점에서 온 데이터로 채워야 합니다.<p> 태그에서 우리는 x-text 속성과 :class 임무 상태에 따라 귀속line-through 클래스를 사용하고 마지막으로 x-show 임무 상태에 따라 정확한 임무 아이콘을 표시합니다.
    너의 새로운 임무 목록은 이렇다
    <!-- Task List -->
    <div id=“task-list” class=“max-w-md mx-auto grid grid-cols-1 gap-2 mt-6>
        <template x-for=“task in tasks>
            <div class=“p-4 bg-white hover:bg-gray-100 cursor-pointer flex justify-between items-center border rounded-md>
                <p :class=“{ line-through: task.completed }” x-text=“task.title”></p>
                <button type=“button”>
                    <svg x-show=“!task.completed” class=“h-6 w-6 text-gray-500 hover:text-green-500 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
                        <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z />
                    </svg>
                    <svg x-show=“task.completed” class=“h-6 w-6 text-green-500 hover:text-gray-500 xmlns=“http://www.w3.org/2000/svg” viewBox=“0 0 20 20” fill=“currentColor”>
                        <path fill-rule=“evenodd” d=“M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z clip-rule=“evenodd” />
                    </svg>
                </button>
            </div>
        </template>
    </div>
    

    이제 입력 작업을 하도록 하겠습니다.스크립트 태그를 되돌려주고 addTask() 함수를 완성하며 taskTitle 에 새 변수를 추가합니다
    taskTitle: ,
    addTask() {
        let self = this;
        let params = new URLSearchParams();
        params.append(title, this.taskTitle );
        axios.post(http://127.0.0.1:8000/tasks/create/’, params,
            {
                headers: { X-CSRFToken: {{ csrf_token }} },
            }
            )
            .then(function (response) {
                self.tasks.push(response.data);
                self.taskTitle = ;
            }).catch(function (error) {
            // handle error
            console.log(error);
          });
    },
    
    이 함수에서 새 작업을 만들고 tasks 그룹에 작업을 추가하고 taskTitle 변수를 재설정하여 DOM이 업데이트됩니다.현재, 우리는 taskTitle 속성을 사용하여 x-model 입력과 귀속시키고, addTask() 단추를 눌렀을 때 @click 함수를 시작합니다
    <!-- Task Input -->
    <div id=“task-input” class=“mt-4 flex justify-center>
        <div class=“m-4 flex>
            <input x-model=“taskTitle” class=“rounded-l-lg p-4 border-t mr-0 border-b border-l text-gray-800 border-gray-200 placeholder=“Task Title/>
            <button @click=“if (taskTitle) { addTask() } else { alert(‘task title cannot be empty’)}” 
                                    class=“px-8 rounded-r-lg bg-purple-800 text-gray-100 font-bold p-4 uppercase>Add Task</button>
        </div>
    </div>
    
    이제 두 가지 퀘스트를 추가해 볼게요. 신기해요!
    작업 삭제
    이제 삭제 작업이 작용할 수 있도록 하겠습니다.우선, 작업 구성 요소를 수정합니다. 작업을 삭제하는 단추를 추가하면 @click deleteTask 함수를 터치할 수 있습니다.
    <!-- Task List -->
    <div id=“task-list” class=“max-w-md mx-auto grid grid-cols-1 gap-2 mt-6>
        <template x-for=“task in tasks>
            <div class=“p-4 bg-white hover:bg-gray-100 cursor-pointer flex justify-between items-center border rounded-md>
                <p :class=“{ line-through: task.completed }” x-text=“task.title”></p>
                <div class=“flex”>
                    <button  class=“mr-4” type=“button”>
                        <svg x-show=“!task.completed” class=“h-6 w-6 text-gray-500 hover:text-green-500 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
                            <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z />
                        </svg>
                        <svg x-show=“task.completed” class=“h-6 w-6 text-green-500 hover:text-gray-500 xmlns=“http://www.w3.org/2000/svg” viewBox=“0 0 20 20” fill=“currentColor”>
                            <path fill-rule=“evenodd” d=“M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z clip-rule=“evenodd” />
                        </svg>
                    </button> 
                    <button @click=“deleteTask(task.id)” type=“button”>
                        <svg class=“h-6 w-6 text-red-400 hover:text-red-600 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
                            <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16 />
                        </svg>
                    </button>
                </div>
            </div>
        </template>
    </div>
    
    이제 아래로 스크롤하여 deleteTask(taskId) 기능을 완성합니다.
    deleteTask(taskId) {
      let self = this;
      axios.post(http://127.0.0.1:8000/tasks/’ + taskId +  ‘/delete/’, {},
      { headers: { X-CSRFToken: {{ csrf_token }} }})
          .then(function (response) {
              let removeIndex = self.tasks.map(item => item.id).indexOf(taskId);
              ~removeIndex && self.tasks.splice(removeIndex, 1);
          }).catch(function (error) {
          // handle error
          console.log(error);
          });
    },
    
    이제 목록에서 작업을 삭제할 수 있습니다.
    작업 상태 업데이트
    함수 완성 updateTask(task)
    updateTask(task) {
        let self = this;
        let params = new URLSearchParams();
        if (task.completed) {
            params.append(status, 0);
        } else {
            params.append(status, 1);
        }
        axios.post(http://127.0.0.1:8000/tasks/’ + task.id + ‘/update/’, params,
            { headers: { X-CSRFToken: {{ csrf_token }} }})
        .then(function (response) {
            task.completed = !task.completed;
        }).catch(function (error) {
            // handle error
            console.log(error);
        });
    }
    
    업데이트 버튼에 등록 정보 추가@click
    <button @click=“updateTask(task)”  class=“mr-4” type=“button”>
        <svg x-show=“!task.completed” class=“h-6 w-6 text-gray-500 hover:text-green-500 xmlns=“http://www.w3.org/2000/svg” fill=“none” viewBox=“0 0 24 24” stroke=“currentColor”>
            <path stroke-linecap=“round” stroke-linejoin=“round” stroke-width=“2” d=“M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z />
        </svg>
        <svg x-show=“task.completed” class=“h-6 w-6 text-green-500 hover:text-gray-500 xmlns=“http://www.w3.org/2000/svg” viewBox=“0 0 20 20” fill=“currentColor”>
            <path fill-rule=“evenodd” d=“M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z clip-rule=“evenodd” />
        </svg>
    </button>
    
    그것을 테스트하면 퀘스트 상태가 업데이트되고 퀘스트가 외관을 업데이트하는 것을 볼 수 있습니다!
    이 강좌에서 Django와 Alpine을 사용하여 간단한 업무 목록을 만드는 방법을 배웠습니다.js.
    나에게 따라가서 나의 최신 문장을 따라가라.

    좋은 웹페이지 즐겨찾기