Skip to content

Instantly share code, notes, and snippets.

@angelospanag
Last active July 3, 2024 16:13
Show Gist options
  • Save angelospanag/4b875350e72b3241b0ccac18db09567e to your computer and use it in GitHub Desktop.
Save angelospanag/4b875350e72b3241b0ccac18db09567e to your computer and use it in GitHub Desktop.
FastAPI with HTMX partials
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://unpkg.com/htmx.org@1.8.6"></script>
<style>
body {
background-color: #222;
color: #fff;
font-family: Arial, sans-serif;
}
table {
border-collapse: collapse;
margin: 20px auto;
width: 80%;
}
th,
td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #333;
}
tr:nth-child(even) {
background-color: #444;
}
</style>
</head>
<body>
<h1>Sci-Fi Movies</h1>
<button hx-get="/movies" hx-trigger="click" hx-target="#movies" hx-swap="outerHTML">
Get movies table
</button>
<div id="movies"></div>
</body>
</html>
from fastapi import Depends, FastAPI, HTTPException, Query, Request, status
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
async def is_partial_rendering(request: Request):
if "hx-request" in request.headers:
if not request.headers["hx-request"]:
raise HTTPException(
status_code=status.HTTP_307_TEMPORARY_REDIRECT,
headers={"Location": "/"},
)
else:
raise HTTPException(
status_code=status.HTTP_307_TEMPORARY_REDIRECT,
headers={"Location": "/"},
)
@app.get("/movies", response_class=HTMLResponse)
async def get_movies(
request: Request,
_=Depends(is_partial_rendering),
):
return templates.TemplateResponse("movies.html", {"request": request})
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
<table>
<thead>
<tr>
<th>Title</th>
<th>Director</th>
<th>Release Year</th>
<th>IMDb Rating</th>
</tr>
</thead>
<tbody>
<tr>
<td>Blade Runner</td>
<td>Ridley Scott</td>
<td>1982</td>
<td>8.1</td>
</tr>
<tr>
<td>The Matrix</td>
<td>The Wachowskis</td>
<td>1999</td>
<td>8.7</td>
</tr>
<tr>
<td>Inception</td>
<td>Christopher Nolan</td>
<td>2010</td>
<td>8.8</td>
</tr>
<tr>
<td>Interstellar</td>
<td>Christopher Nolan</td>
<td>2014</td>
<td>8.6</td>
</tr>
<tr>
<td>Avatar</td>
<td>James Cameron</td>
<td>2009</td>
<td>7.8</td>
</tr>
</tbody>
</table>
@winniehell
Copy link

@angelospanag I'm not sure if that is intentional but is_partial_rendering could be simplified to this:

def is_partial_rendering(request: Request):
    if not request.headers.get("hx-request", None):
        raise HTTPException(
            status_code=status.HTTP_307_TEMPORARY_REDIRECT,
            headers={"Location": "/"},
        )

or just:

def is_partial_rendering(hx_request: bool | None = Header(default=None)):
    if not hx_request:
        raise HTTPException(
            status_code=status.HTTP_307_TEMPORARY_REDIRECT,
            headers={"Location": "/"},
        )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment