ํ๋ก์ ํธ ๊ตฌ์กฐ
ํ๋ก์ ํธ ์์ฑ
django-admin startproject todolist
cd todolist
Bash
๋ณต์ฌ
์ฑ ์์ฑ
python manage.py startapp todo
Bash
๋ณต์ฌ
์ฑ ๋ฑ๋ก (settings.py)
# Application definition
## todo ์ฑ ๋ฑ๋ก
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo'
]
Python
๋ณต์ฌ
๋ชจ๋ธ ์ ์ (models.py)
from django.db import models
# Create your models here.
class Todo(models.Model):
STATUS_CHOICE = [
('WAIT', '๋๊ธฐ'),
('ING', '์งํ'),
('DONE', '์๋ฃ')
]
no = models.AutoField(primary_key=True) # ์๋ ์ฆ๊ฐ ํ๋(PK)
title = models.CharField(max_length=255)
status = models.CharField(
max_length=20,
choices=STATUS_CHOICE,
default='WAIT'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return "{} : {}".format(self.title, self.status)
Python
๋ณต์ฌ
๋ง์ด๊ทธ๋ ์ด์
# ๋ง์ด๊ทธ๋ ์ด์
ํ์ผ ์์ฑ
python manage.py makemigrations
# ๋ง์ด๊ทธ๋ ์ด์
์คํ
python manage.py migrate
Bash
๋ณต์ฌ
URL ๋งคํ (urls.py)
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('todo', views.todo, name='todo'),
path('create', views.create, name='create'),
path('delete', views.delete, name='delete'),
path('ing', views.ing, name='ing'),
path('done', views.done, name='done'),
path('wait', views.wait, name='wait'),
]
Python
๋ณต์ฌ
View ์ ์ (views.py)
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.db.models import Q
from .models import * # models ์ ๋ชจ๋ ๋ชจ๋ธ import
# Create your views here.
def index(request):
print('๋ฉ์ธ ํ๋ฉด...')
return render(request, 'todo/index.html', {})
def todo(request):
print('ํ ์ผ ๋ชฉ๋ก ํ๋ฉด...')
# ํ ์ผ ๋ชฉ๋ก ์กฐํ
# Todo ๋ชจ๋ธ์ ๋๊ธฐ ๋ชฉ๋ก ์กฐํ
wait_list = Todo.objects.filter(status='WAIT')
# Todo ๋ชจ๋ธ์ ์งํ ๋ชฉ๋ก ์กฐํ
ing_list = Todo.objects.filter(Q(status='ING') | Q(status='DONE')).order_by('-status')
content = {'wait_list': wait_list, 'ing_list': ing_list}
# render(request, ํ
ํ๋ฆฟ ๊ฒฝ๋ก, ๋ฐ์ดํฐ{})
# - ๋ฐ์ดํฐ{} : ํ
ํ๋ฆฟ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ
return render(request, 'todo/todo.html', content)
def create(request):
print('ํ ์ผ ๋ฑ๋ก...')
# POST ๋ฐฉ์์ ํ๋ผ๋ฏธํฐ
title = request.POST['title']
# ๋ฑ๋ก ์์ฒญ
new_todo = Todo(title = title)
new_todo.save() # DB์ ์ ์ฅ
# ํ ์ผ ๋ชฉ๋ก(todo)์ผ๋ก ๋ฆฌ๋ค์ด๋ ํธ
return HttpResponseRedirect(reverse('todo'))
def delete(request):
print("์ญ์ ์์ฒญ...")
# ํ๋ผ๋ฏธํฐ
no = request.POST['no']
print('no : {}'.format(no))
try:
todo = Todo.objects.get(no=no)
todo.delete() # ํ ์ผ ์ญ์ ์์ฒญ
except Todo.DoesNotExist:
print('์ญ์ ํ ํ ์ผ์ด ์์ต๋๋ค.')
return HttpResponseRedirect(reverse('todo'))
def ing(request):
print('์งํ ์ํ๋ก ๋ณ๊ฒฝ...')
no = request.POST['no']
print('no : {}'.format(no))
try:
todo = Todo.objects.get(no=no)
# ํ ์ผ ์ํ ์์
todo.status = 'ING'
todo.save()
except Todo.DoesNotExist:
print('์์ ํ ํ ์ผ์ด ์์ต๋๋ค.')
return HttpResponseRedirect(reverse('todo'))
def done(request):
print('์๋ฃ ์ํ๋ก ๋ณ๊ฒฝ...')
no = request.POST['no']
print('no : {}'.format(no))
try:
todo = Todo.objects.get(no=no)
# ํ ์ผ ์ํ ์์
if todo.status == 'DONE':
todo.status = 'ING'
else:
todo.status = 'DONE'
todo.save()
except Todo.DoesNotExist:
print('์์ ํ ํ ์ผ์ด ์์ต๋๋ค.')
return HttpResponseRedirect(reverse('todo'))
def wait(request):
print('๋๊ธฐ ์ํ๋ก ๋ณ๊ฒฝ...')
no = request.POST['no']
print('no : {}'.format(no))
try:
todo = Todo.objects.get(no=no)
# ํ ์ผ ์ํ ์์
todo.status = 'WAIT'
todo.save()
except Todo.DoesNotExist:
print('์์ ํ ํ ์ผ์ด ์์ต๋๋ค.')
return HttpResponseRedirect(reverse('todo'))
Python
๋ณต์ฌ
Template ์์ฑ
โโโ templates/
โโโ todo/
โ โโโ index.html
โ โโโ todo.html
Plain Text
๋ณต์ฌ
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>๋ฉ์ธ ํ๋ฉด</title>
</head>
<body>
<h1>๋ฉ์ธ ํ๋ฉด</h1>
<h3>Hello Django~!</h3>
<a href="./todo">To Do List</a>
</body>
</html>
HTML
๋ณต์ฌ
todo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ํ ์ผ ๋ชฉ๋ก</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<style>
input[type='checkbox'] {
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-8 col-lg-6">
<h1>ํ ์ผ ๋ชฉ๋ก</h1>
<hr>
<form action="./create" method="post">
{% csrf_token %}
<div class="input-group mb-3">
<label for="todo" class="input-group-text">ํ ์ผ</label>
<input type="text" name="title" class="form-control" id="todo"
placeholder="ํ ์ผ์ ์
๋ ฅํด์ฃผ์ธ์."
autofocus
>
<button type="submit" class="btn btn-outline-primary">๋ฑ๋ก</button>
</div>
</form>
<hr>
<h3>์งํ ๋ชฉ๋ก</h3>
<table class="table table-bordered text-center align-middle">
<thead>
<tr class="table-dark">
<th>โ
</th>
<th class="text-start">ํ ์ผ</th>
<th>โญ</th>
</tr>
</thead>
<tbody>
{% for todo in ing_list %}
<tr {% if todo.status == 'DONE' %}class="table-success"{% endif %}>
<td>
<form action="./done" method="post">
{% csrf_token %}
<input type="hidden" name="no" value="{{ todo.no }}">
<input type="checkbox" class="form-check-input"
onchange="this.form.submit()"
{% if todo.status == 'DONE' %}checked{% endif %}>
</form>
</td>
<td class="text-start">
{{ todo.title }}
</td>
<td>
<div class="d-flex justify-content-center gap-2">
<form action="./wait" method="post">
{% csrf_token %}
<input type="hidden" name="no" value="{{ todo.no }}">
<button class="btn btn-success">
<i class="bi bi-arrow-down-square"></i>
</button>
</form>
<form action="./delete" method="post">
{% csrf_token %}
<input type="hidden" name="no" value="{{ todo.no }}">
<button class="btn btn-danger">
<i class="bi bi-trash2"></i>
</button>
</form>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center text-muted">
์กฐํ๋ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.
</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr>
<h3>๋๊ธฐ ๋ชฉ๋ก</h3>
<table class="table table-bordered text-center align-middle">
<thead>
<tr class="table-dark">
<th>โ
</th>
<th class="text-start">ํ ์ผ</th>
<th>โญ</th>
</tr>
</thead>
<tbody>
{% for todo in wait_list %}
<tr>
<td>
<form action="./ing" method="post">
{% csrf_token %}
<input type="hidden" name="no" value="{{ todo.no }}">
<button type="submit" class="btn btn-outline-primary">
<i class="bi bi-arrow-up-square"></i>
</button>
</form>
</td>
<td class="text-start">
{{ todo.title }}
</td>
<td>
<form action="./delete" method="post">
{% csrf_token %}
<input type="hidden" name="no" value="{{ todo.no }}">
<button class="btn btn-danger">
<i class="bi bi-trash2"></i>
</button>
</form>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center text-muted">
์กฐํ๋ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js" integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO" crossorigin="anonymous"></script>
</body>
</html>
HTML
๋ณต์ฌ