快要結尾了,稍微喘口氣,來做個簡單的Todolist頁面吧!
會參考以下兩篇文章進行
稍微以這兩個為基底下去修改和融合~
首先先建立django project 和 app,然後把一些基礎的設定弄完再做一個簡單的hello world吧!相信大家都很熟了~
django-admin startproject todolist
cd todolist
python manage.py startapp todoapp
settings.py
# 在installed apps裡面加上剛剛新增的app name
INSTALLED_APPS = [
'todoapp',
# ...
]
# templates 中的 dirs 加上
TEMPLATES = [
{
# ...
'DIRS' : ['templates'],
# ...
}
]
mkdir templates
,在裡面丟個index.html
備用urls.py
內容如下from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
views.py
稍微加上from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
def index(request):
return JsonResponse({'hello': 'world'})
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todoapp.urls'))
]
如此一來python manage.py migrate
後 python manage.py runserver
,就能看到json格式的hello world囉~
models.py
加上from django.db import models
# Create your models here.
class Todo(models.Model):
title=models.CharField(max_length=350)
complete=models.BooleanField(default=False)
def __str__(self):
return self.title
python manage.py makemigrations
後 python manage.py migrate
views.py
from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.forms.models import model_to_dict
from .models import Todo
import json
# Create your views here.
def index(request):
return render(request, 'base.html')
def api(request):
todos = Todo.objects.all()
return JsonResponse({"data":list(todos.values())})
@require_http_methods(["POST"])
def add(request):
body = request.body.decode("utf-8")
body = json.loads(body)
title = body.get("title", "")
todo = Todo(title=title)
todo.save()
return JsonResponse({"todo_id": todo.id, "complete": todo.complete, "todo_title": todo.title})
def update(request, todo_id):
todo = Todo.objects.get(id=todo_id)
todo.complete = not todo.complete
todo.save()
return JsonResponse({"todo_id": todo_id, "complete": todo.complete})
def delete(request, todo_id):
todo = Todo.objects.get(id=todo_id)
todo.delete()
return JsonResponse({"todo_id": todo_id})
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name="index"),
path('api/', views.api, name="api"),
path('api/add/', views.add, name="add"),
path('api/delete/<int:todo_id>', views.delete, name="delete"),
path('api/update/<int:todo_id>', views.update, name="update"),
]
index.html
修改<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<script src="https://code.jquery.com/jquery-3.7.0.js" integrity="sha256-JlqSTELeR4TLqP0OG9dxM7yDPqX1ox/HfgiSLBj8+kM=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body onload="get_all_list()">
<div style="margin-top: 50px;" class="ui container">
<h1 class="ui center aligned header">To Do App</h1>
<form class="ui form">
<div class="field">
<label>Todo Title</label>
<input class="input-todo" name="title" id="title" placeholder="Enter Todo..." value=""><br>
</div>
<button class="ui blue button btn-add" type="button" >Add</button>
</form>
<hr>
<div class="todos">
</div>
<script>
let state = {
todos: []
}
function get_all_list(){
axios.get("/api/")
.then(response => {
response.data.data.forEach(todo => {
state = {
todos: [...state.todos, {
id: todo.id,
content: todo.title,
isDone: todo.complete
}]
}
});
updateState(state)
})
}
// 更新 state
function updateState(newState) {
state = newState;
render()
}
// state => UI
function render() {
// 先把畫面清空
$('.todos').empty();
console.log(state.todos)
$('.todos').append(
// 把每個 todo 的 HTML 集合起來放到畫面上
state.todos.map(todo => Todo(todo)).join('')
);
}
// Todo component
function Todo({id, content, isDone}) {
return `
<div class="ui segment todo" data-id="${id}">
<p class="ui big header"> ${id} | ${content} </p>
${Span({
className: isDone ? 'ui green label' : 'ui gray label',
content: isDone ? 'Complete' : 'Not Completed'
})}
${Button({
className: 'blue btn-update',
content: 'Update'
})}
${Button({
className: 'red btn-delete',
content: 'Delete'
})}
</div>
`
}
function Span(props){
return `<span class="${props.className}">${props.content}</span>`
}
// Button component
function Button(props) {
return `
<a class="ui ${props.className} button">${props.content}</a>
`
}
// 新增 todo
$('.btn-add').click(() => {
const content = $('.input-todo').val();
if (!content) return;
$('.input-todo').val('');
axios.post("/api/add/",
{
"title": content
},
{
headers: {
"X-CSRFToken": "{{csrf_token}}",
},
}
)
.then(response => {
todo_id = response.data["todo_id"]
title = response.data["todo_title"]
complete = response.data["complete"]
// 更新 state
updateState({
todos: [...state.todos, {
id: todo_id,
content: title,
isDone: complete
}]
});
})
});
// 刪除 todo
$('.todos').on('click', '.btn-delete', e => {
const id = Number($(e.target).parents('.todo').attr('data-id'));
axios.get("/api/delete/"+id)
.then(response => {
d_id = response.data["todo_id"]
updateState({
todos: state.todos = state.todos.filter(todo => todo.id !== d_id)
});
})
});
// 未完成 -> 已完成
$('.todos').on('click', '.btn-update', e => {
const id = Number($(e.target).parents('.todo').attr('data-id'));
axios.get("/api/update/"+id)
.then(response => {
u_id = response.data["todo_id"]
complete = response.data["complete"]
updateState({
todos: state.todos.map(todo => {
if (todo.id !== u_id) return todo;
return {
...todo,
isDone: complete
}
})
})
});
});
</script>
</div>
</body>
</html>
完成以上步驟後下python manage.py runserver
就能看到簡單的ToDoList囉~
那整體的介面是從上面那個youtube影片摳過來的,我自己對網頁的設計美感有點差而且CSS苦手XD
而JS則是透過下面那篇文章去修改的,當時想要學習React剛好看到這篇,改完就變成純JS的component和state的用法,收穫頗大!以前都是直接打API拿到Json後把html重組,現在知道了component和state後覺得JS那邊的可讀性變高很多~
明天就來試試看對這個簡單的ToDoList寫些test吧!
完整的程式碼在這邊
https://github.com/m124578n/IronMan_ToDoList