여름의 서재

[Django] 할 일 리스트 만들기_Todo 본문

Skill/Django

[Django] 할 일 리스트 만들기_Todo

엉아_ 2021. 10. 25. 21:50
728x90

💡 todo 리스트

: 기존의 게시판과 비슷하지만 완료 상태를 의미하는 필드가 추가가 된다.

 

🔧 todo 리스트 구현하기

1. 앱생성

: todos라는 새로운 app을 만든다. settings에 등록도 필수!

python manage.py startapp todos
# config/settings.py

INSTALLED_APPS = [
    # Custom apps
    'todos',  # 등록!!
    'accounts',
    
    # Third-party libraries


    # Django core packages
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

 

2. todos/models.py

: Todo라는 모델을 만들어준다. 완료 여부는 True, False이고 처음으로 작성했을 때는 당연히 미완료 상태이므로 default 값은 False 값으로 한다. 만든 사람(author)도 같이 저장한다.

from django.db import models
from django.conf import settings 

# Create your models here.
class Todo(models.Model):
    title = models.TextField()
    completed = models.BooleanField(default=False)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL, 
        on_delete=models.CASCADE, 
    )
    
    def __str__(self):
        return f'{self.title} - {self.completed}'

-> model을 새로 만들었거나 수정했다면 migrate는 필수다!!!

 

3. todos/forms.py

: todo를 작성하는 form을 커스텀하기 위해 TodoForm이라는 모델폼을 만든다.

from django import forms 
from .models import Todo 

class TodoForm(forms.ModelForm):
    
    class Meta:
        model = Todo
        fields = ('title',)

 

4. todos/urls.py

: todo 리스트를 전체 조회하는 url과 완료 상태를 변경하는 url을 만들어 준다. 

(여기선 따로 삭제와 수정은 만들지 않았다🙄 혹시 만들고 싶다면 article을 삭제, 수정하는 방법과 동일하다!)

from django.urls import path 
from . import views 

app_name = 'todos'
urlpatterns = [
    # localhost:8000/todos/
    path('', views.index, name='index'),
    path('<int:pk>/complete/', views.complete, name='complete'),
]

 

5. todos/views.py

 

📌 index 함수

: todo 리스트를 조회하는 함수이다.

 

- completed = request.GET.get('completed') or False

: 쿼리스트링 completed의 값이 True로 온다면 completed는 True가 된다.

그렇게 되면 todo테이블에서 완료된 데이터만 index.html로 보낸다.

 

쿼리스트링 completed의 값이 False로 온다면 completed는 False가 된다.

그렇게 되면 todo테이블에서 미완료된 데이터만 index.html로 보낸다.

 

쿼리스트링 completed의 값이 none으로 온다면 completed는 False가 된다.

그렇게 되면 todo테이블에서 미완료된 데이터만 index.html로 보낸다.

 

📌 complets 함수

: 요청이 왔을 때 해당 할일의 completed 필드를 True 로 바꾼다.

 

from django.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
from .models import Todo 
from .forms import TodoForm

# Create your views here.
@login_required 
def index(request):
    completed = request.GET.get('completed') or False
    todos = Todo.objects.filter(completed=completed)

    if request.method == 'POST':
        form = TodoForm(request.POST)
        if form.is_valid():
            todo = form.save(commit=False)
            todo.author = request.user # 작성자 정보 
            todo.save()
    else:
        form = TodoForm()
    
    context = {
        'form': form,
        'todos': todos,
    }
    return render(request, 'todos/index.html', context)


def complete(request, pk):
    todo = get_object_or_404(Todo, pk=pk)
    todo.completed = True
    todo.save()
    return redirect('todos:index')

 

6. templates

 

📌todos/templates/todos/index.html

: index 함수로부터 받은 todos 데이터를 for문을 돌면서 하나씩 나열하고 만약 완료되지 않았다면 완료 버튼을 누른다.

 

{% extends 'base.html' %}

{% block body %}
<form action="" method="POST">
  {% csrf_token %}
  {{ form }}
  <button>생성</button>
</form>
<hr>

{% for todo in todos %}
  <h2>{{ todo.title }}</h2>
  <p>작성자: {{ todo.author }}</p>
  <p>완료여부: {{ todo.completed }}</p>

  {% if todo.completed == False %}
  <form action="{% url 'todos:complete' todo.id %}" method="POST">
    {% csrf_token %}
    <button>완료</button>
  </form>
  <hr>
  {% endif %}

{% endfor %}

{% endblock %}

📌templates/base.html

: '완료한 일 보기' 글자를 누르면 completed 쿼리스트링의 값에 True가 들어가면서 요청이 보내지게 되고, index 함수에서는 완료된 일만 index에 보내게 된다. 결국 index에는 완료한 일만 출력된다.

 

 '할 일 보기' 글자를 누르면 completed 쿼리스트링의 값에 False가 들어가면서 요청이 보내지게 되고, index 함수에서는 완료된 일만 index에 보내게 된다. 결국 index에는 완료한 일만 출력된다.

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <nav>
    <ul>
      <li><a href="{% url 'accounts:login' %}">로그인</a></li>
      <li><a href="{% url 'accounts:signup' %}">회원가입</a></li>
      <li>
        <a href="{% url 'todos:index' %}?completed=True">완료한 일 보기</a>
      </li>
      <li>  
        <a href="{% url 'todos:index' %}?completed=False">할 일 보기</a>
      </li>
    </ul>
  </nav>
  
  {% block body %}
  {% endblock %}
</body>
</html>

url 주목!

 

Comments