代码结构
. #根目录
└── todo #module名称
├── static # 静态文件
│ ├── logo.png # 测试用logo
│ └── style.css # 代码样式
├── templates
│ └── todo.html# 前端页面
├── main.py # 系统入口及API接口
└── models.py # 实体映射
前端样式
#todo_list{
border :solid 1px #0b2e13;
border-collapse:collapse;
}
#todo_list #header{
background-color:#1e7e34;
color:#white;
}
#todo_list #header th{
padding: 5px 10px;
border:solid 1px #0b2e13;
}
#todo_list #th{
padding: 5px 10px;
border:solid 1px #0b2e13;
}
Jinja2的前端html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo List</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<h1>todo list</h1>
<form action="/addTodo" method="post">
<div>
<label for="name">待办名称:</label>
<input type="text" name="name" required>
</div>
<div>
<label for="priority">优先级:</label>
<select name="priority" required>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>
<button type="submit">添加</button>
</form>
<table id = "todo_list">
<thead>
<tr id="header">
<th>id</th>
<th>名称</th>
<th>是否完成</th>
<th>优先级</th>
<th>创建日期</th>
</tr>
</thead>
<tbody>
{% for todo in todos %}
<tr>
<td>{{ todo.id }}</td>
<td>{{ todo.name }}</td>
<td>{{ todo.is_completed }}</td>
<td>{{ todo.priority }}</td>
<td>{{ todo.created_at }}</td>
<td>
{% if not todo.is_completed %}
<form action="/todo/{{ todo.id }}/complete" method="post">
<button type="submit">标记为完成</button>
</form>
{% else %}
<a href="/completeTodo/{{ todo.id }}">已完成</a>
{% endif %}
<form action="/todo/{{ todo.id }}/delete" style="display:inline" method="post">
<button type="submit">删除</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
main函数
from datetime import datetime
import uvicorn
from fastapi import FastAPI, Request, Form
from starlette.responses import HTMLResponse,RedirectResponse
from tortoise.contrib.fastapi import register_tortoise
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from tortoise.exceptions import DoesNotExist
from todo.models import Todo
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
try:
register_tortoise(
app,
db_url="mysql://root:[PWD]@[IP]:3306/tortoise_fast_api",
modules={"models": ["todo.models"]},
generate_schemas=False,
add_exception_handlers=True
)
print("Tortoise ORM registered successfully.")
except Exception as e:
print(f"Failed to register Tortoise ORM: {e}")
@app.get("/todos",response_class=HTMLResponse)
async def get_todo_list(request:Request):
"""
使用 await Todo.all().order_by("-created_at") 获取所有待办事项并按创建时间降序排序。
使用 templates.TemplateResponse 渲染 todo.html 模板,并传递请求对象和待办事项列表。
"""
todos:list[Todo] = await Todo.all().order_by("-created_at")
return templates.TemplateResponse("todo.html",{"request":request,"todos":todos})
@app.post("/addTodo",response_class=HTMLResponse)
async def add_todo(request:Request,name:str =Form(...),priority:str =Form(...)):
await Todo.create(name=name,priority=priority,created_at = datetime.now())
return RedirectResponse("/todos",status_code=303)
@app.post("/todo/{id}/complete", response_class=RedirectResponse)
async def complete_todo(id: int):
todo = await Todo.get(id=id)
if not todo:
return RedirectResponse("/todos", status_code=303)
todo.is_completed = True
await todo.save()
return RedirectResponse("/todos", status_code=303)
@app.post("/todo/{id}/delete", response_class=RedirectResponse)
async def delete_todo(id: int):
try:
todo = await Todo.get(id=id)
await todo.delete()
except DoesNotExist:
pass
return RedirectResponse("/todos", status_code=303)
if __name__ == "__main__":
uvicorn.run(app,port=8888)
models 定义实体
from tortoise import fields
from tortoise import Model
class Todo(Model):
id = fields.IntField(pk=True,description="待办ID")
name = fields.CharField(max_length=255,description="待办名称")
is_completed = fields.BooleanField(default=False,description="是否完成")
priority = fields.CharField(max_length=10,description="优先级")
created_at = fields.DatetimeField(description="创建时间")
class Meta:
table = "todo"
table_description = "待办表"