FastAPI can return more than JSON. Jinja2Templates renders HTML, while
StaticFiles serves CSS and images. A regular HTML form uses
application/x-www-form-urlencoded; a file form uses multipart/form-data.
This is useful when a separate frontend is unnecessary: FastAPI reads data, Jinja
places it into a template, and the browser receives complete HTML. Forms send changes
back to the same application.
A small site needs only templates, static, and GET/POST routes. Render one page
successfully first, then connect its form.
Build paths relative to the application file, not the shell working directory:
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
BASE_DIR = Path(__file__).resolve().parent
app = FastAPI()
app.mount("/static", StaticFiles(directory=BASE_DIR / "static"), name="static")
templates = Jinja2Templates(directory=BASE_DIR / "templates")
@app.get("/")
def home(request: Request):
return templates.TemplateResponse(
request=request, name="index.html", context={"projects": []}
)
Use {{ url_for('static', path='/style.css') }} in the template. Accept fields with
Form, keep <input name> values aligned with route parameters, add
enctype="multipart/form-data" for files, and redirect with 303 after a successful
POST. Browser validation helps users, but the server must validate every field again.
The friendly GET โ POST โ redirect cycle
- GET displays the form and current data.
- POST validates fields and saves changes.
- On failure, render the form again with a useful explanation.
- On success, return a
303redirect to a GET page.
This prevents a browser refresh from submitting the form twice. If CSS is missing,
open DevTools โ Network: a 404 usually points to a wrong directory or mount name.
๐ฌ Comments (0)
No comments yet
Be the first to share your opinion about this article!