[예제] TODO LIST

김주언·2022년 7월 3일
0

Django

목록 보기
4/9
post-thumbnail

Django로 TODO LIST 구현하기

지긋지긋한 투두리스트
하지만 클래식이즈베스트
CRUD구현이다.. 늘 그렇듯이... ^^..

1. 프로젝트 기본 설정

1.1 가상 환경 세팅

난 아나콘다로 가상환경 생성했드아아 파이참 프로젝트 열면 된다하ㅏㅏㅏ

conda create -n [가상환경 이름]
conda activate [가상환경 이름]

1.2 장고 프로젝트 & 앱 생성

프로젝트 생성 & 앱 생성

django-admin startproject todoapp

python manage.py startapp todo

1.3 프로젝트 설정

앱을 추가했기 때문에 settings.py에 추가해준다.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'todo'		# todo 앱을 추가해준다 (todoapp은 프로젝트고 todo는 프로젝트 내부의 앱!)
]

1.3 Todo 모델

Todo 모델은 다음과 같이 정의한다.

필드타입
titleCHAR
descriptionCHAR
created_atDATE
completedboolean
importantboolean

위와 같은 스키마(?)를 코드로 변환하면 아래와 같다 ( 모델 클래스 작성 )
todo/models.py

from django.db import models

# Create your models here.
class Todo(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    completed = models.BooleanField(default=False)
    important = models.BooleanField(default=False)

    def __str__(self):
        return self.title

이 때 장고가 기본적으로 기본키 (pk) 필드를 제공하기 때문에 따로 선언하지 않아도 된다

모델을 생성했으면 이를 사용하기 위해서는 마이그레이션 과정을 거쳐야한다.

1.3.1 마이그레이션

python manage.py makemigrations   
python manage.py migrate          

모델을 생성하고 마이그레이션까지 해주었으면 관리자 페이지에서 이를 확인할 수 있다.

1.3.2 관리자 페이지 설정

  1. todo/admin.py 파일에서 Todo 모델을 등록하는 코드를 작성한다.

    from django.contrib import admin
    from .models import Todo
    # Register your models here.
    
    admin.site.register(Todo)
  2. 관리자 페이지 접속을 위한 url 설정 - todoapp/urls.py

    urlpatterns = [
        path('admin/', admin.site.urls),
    ]
  3. 관리자 계정 생성

    python manage.py createsuperuser 

위 절차가 끝난 후 서버를 실행하여 관리자 페이지로 접속하면 Todo 모델이 추가되어 있다.


2. Todo 목록 조회

할일 전체 목록을 조회한다.
진행중인 todo만 보여주고 완료된 todo는 다른 페이지에서 보여주도록 구현한다.

템플릿 > 뷰 > url 순서로 작성한다.

템플릿

todo/templates/todo 폴더내에 todo_list.html 파일을 생성하고 코드를 작성한다.


<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
        integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">

  <title>TODO LIST</title>
</head>
<body>
<div class="container">
  <h1>TODO LIST</h1>
  <p>
    <a href=""><i class="bi-plus"></i>ADD TODO</a>
    <a href="" class="btn btn-primary" style="float:right">완료한 TODO 목록</a>
  </p>
  <ul class="list-group">
    {% for todo in todos %}
      <li class="list-group-item">
        <a href="">{{ todo.title }}</a>
        {% if todo.important %}
          <span class="badge badge-danger">!</span>
        {% endif %}
        <div style="float:right">
          <a href="" class="btn btn-danger">완료</a>
          <a href="" class="btn btn-outline-primary">수정하기</a>
        </div>
      </li>
    {% endfor %}
  </ul>
</div>
<!-- Optional JavaScript; choose one of the two! -->

<!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
        crossorigin="anonymous"></script>

</body>
</html>

todo/viewes.py

def todo_list(request):
    todos = Todo.objects.filter(completed=False)
    return render(request, 'todo/todo_list.html', {'todos': todos})

완료되지 않은 todo만 필터링하여 todos 변수에 담아서 템플릿으로 전달한다.

url

todo/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.todo_list, name='todo_list'),
]

todo앱에서 목록 화면에 대한 url을 설정해준다.
그 후 todoapp 프로젝트에 todo 앱에 대한 url을 설정해줘야 정상적으로 접근가능

todoapp/urls/py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('todo/', include('todo.urls'))	# 추가
]

/todo 경로로 접근하면 todo앱의 urls.py 파일을 사용하여 하위 경로에 대해 작동한다.


3. 상세 목록 조회

템플릿

todo_detail.html

<!doctype html>
<html lang="en">
<head>
  <!-- Required meta tags -->
  <!-- Bootstrap CSS  생략-->
  
  <title>TODO LIST</title>
</head>
<body>
<div class="container">
  <h1>TODO 상세보기</h1>
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <div class="card">
          <div class="card-body">
            <h5 class="card-title">{{ todo.title }}</h5>
            <p class="card-text">{{ todo.description }}</p>
            <a href="{% url 'todo_list' %}" class="btn btn-primary">목록으로</a>
<!-- 닫는 태그 생략 , 스크립트 생략-->
</html>


뷰 정의 파일에 함수 추가

def todo_detail(request, pk):
    todo = Todo.objects.get(id=pk)
    return render(request, 'todo/todo_detail.html', {'todo': todo})

아이디, 즉 기본키를 사용하여 상세 내용을 보려고 하는 todo를 DB에서 가져와서 상세내용 페이지에 데이터를 전달한다.

url
todo/urls.py에 경로 추가해준다.

path('<int:pk>/', views.todo_detail, name='todo_detail')

4. Todo 생성과 수정

생성과 수정을 위해서 입력 폼이 필요하기 때문에 폼 클래스를 생성해준다.

TodoForm

todo/forms.py 파일을 생성하고 코드를 작성한다.

from django import forms
from .models import Todo


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

템플릿

중복되는 부분은 생략했음. 수정은 todo_post.html 템플릿을 그대로 사용한다.
todo_post.html

<!DOCTYPE html>
<html lang="en">

<body>
<div class="container">
  <h1>TODO 추가하기</h1>
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <div class="card">
          <div class="card-body">
            <form method="POST">
              {% csrf_token %} {{ form.as_p }}
              <button type="submit" class="btn btn-primary">등록</button>

def todo_post(request):
    if request.method == "POST":
        form = TodoForm(request.POST)
        if form.is_valid():
            todo = form.save(commit=False)
            todo.save()
            return redirect('todo_list')
    else:
        form = TodoForm()
    return render(request, 'todo/todo_post.html', {'form': form})


def todo_edit(request, pk):
    todo = Todo.objects.get(id=pk)
    if request.method == "POST":
        form = TodoForm(request.POST, instance=todo)
        if form.is_valid():
            todo = form.save(commit=False)
            todo.save()
            return redirect('todo_list')
    else:
        form = TodoForm(instance=todo)
    return render(request, 'todo/todo_post.html', {'form': form})

생성과 수정 시 차이점은 수정의 경우는 instane=todo 로 설정하여 수정 대상을 받아오는 점이다.

url

생성과 수정을 위한 url 연결

path('post/', views.todo_post, name='todo_post'),
path('<int:pk>/edit/', views.todo_edit, name='todo_edit'),

5. Todo 완료

완료 버튼 클릭 시 Todo의 completed 를 True로 바꿔준다.
또한 완료된 todo들만 조회하기 위해 필터링하여 렌더링한다.

템플릿

템플릿은 목록 템플릿과 유사하니까 생략..

완료된 목록을 보여주는 함수와 todo의 completed를 True, 즉 완료 상태로 바꿔주는 함수 두가지를 작성한다.


def todo_done(request, pk):
    todo = Todo.objects.get(id=pk)
    todo.completed = True
    todo.save()
    return redirect('todo_list')


def todo_done_list(request):
    dones = Todo.objects.filter(completed=True)
    return render(request, 'todo/todo_done_lilst.html', {'dones': dones})

url

path('done/', views.todo_done_list, name='todo_done_list'),
path('done/<int:pk>', views.todo_done, name='todo_done')

여기까지 작성하고 todo_list.html에 <a href={% %}> 에 각 url을 연결해주면 된다.

기본뼈대... CRUD 구현.. 끝..

profile
학생 점심을 좀 차리시길 바랍니다

0개의 댓글