Jinja2 템플릿을 사용하는 FastAPI의 ToDo 앱
가상 환경 만들기
virtualenv env
활성화하고
source env/bin/activate
설치
pip install fastapi "uvicorn[standard]" jinja2 python-multipart sqlalchemy
이제 같은 디렉토리(todoapp 디렉토리)에 main.py, database.py 및 model.py를 만들고 템플릿과 정적 디렉토리도 만듭니다. 모양은 다음과 같습니다.
main.py
# main.py
from fastapi import FastAPI, Request, Depends, Form, status
from fastapi.templating import Jinja2Templates
import models
from database import engine, sessionlocal
from sqlalchemy.orm import Session
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
models.Base.metadata.create_all(bind=engine)
templates = Jinja2Templates(directory="templates")
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
def get_db():
db = sessionlocal()
try:
yield db
finally:
db.close()
@app.get("/")
async def home(request: Request, db: Session = Depends(get_db)):
todos = db.query(models.Todo).order_by(models.Todo.id.desc())
return templates.TemplateResponse("index.html", {"request": request, "todos": todos})
@app.post("/add")
async def add(request: Request, task: str = Form(...), db: Session = Depends(get_db)):
todo = models.Todo(task=task)
db.add(todo)
db.commit()
return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)
@app.get("/edit/{todo_id}")
async def add(request: Request, todo_id: int, db: Session = Depends(get_db)):
todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
return templates.TemplateResponse("edit.html", {"request": request, "todo": todo})
@app.post("/edit/{todo_id}")
async def add(request: Request, todo_id: int, task: str = Form(...), completed: bool = Form(False), db: Session = Depends(get_db)):
todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
todo.task = task
todo.completed = completed
db.commit()
return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)
@app.get("/delete/{todo_id}")
async def add(request: Request, todo_id: int, db: Session = Depends(get_db)):
todo = db.query(models.Todo).filter(models.Todo.id == todo_id).first()
db.delete(todo)
db.commit()
return RedirectResponse(url=app.url_path_for("home"), status_code=status.HTTP_303_SEE_OTHER)
데이터베이스.py
# database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
DB_URL = 'sqlite:///todo.sqlite3'
engine = create_engine(DB_URL, connect_args={'check_same_thread': False})
sessionlocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
models.py
# models.py
from sqlalchemy import Column, Integer, Boolean, Text
from database import Base
class Todo(Base):
__tablename__ = 'todos'
id = Column(Integer, primary_key=True)
task = Column(Text)
completed = Column(Boolean, default=False)
def __repr__(self):
return '<Todo %r>' % (self.id)
이제 템플릿 디렉토리 안에 템플릿을 만들어 봅시다
템플릿/base.html
<!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>ToDo App</title>
<link rel="stylesheet" href="{{ url_for('static', path='css/main.css') }}">
</head>
<body>
<main>
<h1>ToDo App</h1>
<br>
{% block content %}
{% endblock content %}
</main>
</body>
</html>
템플릿/index.html
{% extends 'base.html' %}
{% block content %}
<form action="/add" method="post">
<textarea name="task" rows="5" placeholder="Enter your task"></textarea>
<button type="submit">Add</button>
</form>
<br>
<h2>Tasks</h2>
<div>
{% for todo in todos %}
<div class="task">
{% if todo.completed %}
<strike>{{ todo.task }}</strike>
{% else %}
{{ todo.task }}
{% endif %}
<small>
<a href="edit/{{ todo.id }}">Edit</a>
<a href="delete/{{ todo.id }}">Delete</a>
</small>
</div>
{% endfor %}
</div>
{% endblock content %}
템플릿/edit.html
{% extends 'base.html' %}
{% block content %}
<form action="/edit/{{todo.id}}" method="post">
<textarea name="task" rows="5">{{todo.task}}</textarea>
<label for="completed">Done?</label>
<input type="checkbox" name="completed" {% if todo.completed %}checked{% endif %}>
<button type="submit">Save</button>
</form>
{% endblock content %}
정적/css/main.css
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
body{
font-family: 'Roboto', sans-serif;
background: #f5f5f5;
}
main{
width: 100%;
max-width: 520px;
margin: 0 auto;
padding: 0 20px;
}
textarea{
width: 100%;
height: 100px;
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
resize: none;
}
button{
width: 100%;
height: 40px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #eee;
color: #333;
font-size: 16px;
cursor: pointer;
}
.task{
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #ccc;
}
.task:first-child{
border-top: 1px solid #ccc;
}
산출
FastAPI 앱을 실행하려면 다음 명령을 입력하고 Enter 키를 누릅니다.
uvicorn main:app --reload
브라우저에서 링크 열기( http://127.0.0.1:8000 )
색인 페이지
페이지 편집
GitHub의 소스 코드: https://github.com/SoniArpit/simple-todoapp-fastapi
개발자 커뮤니티에 가입하여 감정, 생각, 무작위 항목 공유 -> https://awwsome.dev/ (django에서 제작)
안녕 <3
Reference
이 문제에 관하여(Jinja2 템플릿을 사용하는 FastAPI의 ToDo 앱), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/soniarpit/todo-app-in-fastapi-with-jinja2-template-5a3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)