How to get the updated list of items in Jinja2 template using FastAPI?

This sounds like a use case for WebSockets. The below is based on the example given in the documentation above, and can handle multiple connections, broadcasting the newly added comment to all the connected clients. Thus, if you open http://127.0.0.1:8000/ in multiple tabs in your browser, and add a new comment using one of these connections, every other will also receive the new comment. If you don’t want to broadcast the message, then you could instead use await manager.send_personal_message(data, websocket).

app.py

from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
from fastapi.templating import Jinja2Templates
import uvicorn

class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        await websocket.send_json(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_json(message)

class Comment:
    def __init__(self, author, content): 
        self.author = author 
        self.content = content

app = FastAPI()
templates = Jinja2Templates(directory="templates")
manager = ConnectionManager()
comments = [] 
comments.append( Comment("author 1 ", "content 1") )
comments.append( Comment("author 2 ", "content 2") )
comments.append( Comment("author 3 ", "content 3") )

@app.get("/")
def main(request: Request):
    return templates.TemplateResponse("index.html", {"request": request, "comments": comments})

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            data = await websocket.receive_json()
            comments.append(Comment(data['author'], data['content']))
            await manager.broadcast(data)
    except WebSocketDisconnect:
        manager.disconnect(websocket)
        
if __name__ == '__main__':
    uvicorn.run(app, host="127.0.0.1", port=8000)

templates/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>Add new comment</h1>
        <form action="" onsubmit="addComment(event)">
            <input type="text" id="author" autocomplete="off"/>
            <input type="text" id="content" autocomplete="off"/>
            <button>Add comment</button>
        </form>
        <h2>Comments</h2>
        <ul id='comments'>
            {% for comment in comments %}
                <li>
                  <h3> {{comment.author}} </h3>
                  <p> {{comment.content}} </p>
               </li>
            {% endfor %}
        </ul>
        <script>
            var ws = new WebSocket("ws://localhost:8000/ws");
            ws.onmessage = function(event) {
                var comments = document.getElementById('comments')
                var comment = document.createElement('li')
                var jsonObj  = JSON.parse(event.data);
                var authorNode = document.createElement('h3');
                authorNode.innerHTML = jsonObj.author;
                var contentNode = document.createElement('p');
                contentNode.innerHTML = jsonObj.content;
                comment.appendChild(authorNode);
                comment.appendChild(contentNode);
                comments.appendChild(comment)
            };
            function addComment(event) {
                var author = document.getElementById("author")
                var content = document.getElementById("content")
                ws.send(JSON.stringify({"author": author.value, "content": content.value}))
                author.value=""
                content.value=""
                event.preventDefault()
            }
        </script>
    </body>
</html>

Leave a Comment