【问题标题】:How to update Jinja variable in loop using FastAPI?如何使用 FastAPI 在循环中更新 Jinja 变量?
【发布时间】:2022-08-08 01:04:26
【问题描述】:

我正在我的博客上建立一个评论系统,我正在渲染现有的 cmets,如下所示:

{% for comment in comments %}

                    <div id=\"task-comments\" class=\"pt-4\">
                        <!--     comment-->
                        <div
                            class=\"bg-white rounded-lg p-3  flex flex-col justify-center items-center md:items-start shadow-lg mb-4\">
                            <div class=\"flex flex-row justify-center mr-2\">
                                <img alt=\"avatar\" width=\"48\" height=\"48\"
                                    class=\"rounded-full w-10 h-10 mr-4 shadow-lg mb-4\"
                                    src=\"https://cdn1.iconfinder.com/data/icons/technology-devices-2/100/Profile-512.png\">
                                <h3 class=\"text-purple-600 font-semibold text-lg text-center md:text-left \">{{
                                    comment.author[\'name\']|e }}</h3>
                            </div>


                            <p style=\"width: 90%\" class=\"text-gray-600 text-lg text-center md:text-left \">{{
                                comment.content|e }} </p>

                        </div>
                        <!--  comment end-->
                        <!--     comment-->

                        <!--  comment end-->
                    </div>
                    {% endfor %}

这里的问题是,当我发表评论时(使用 FastAPI 路由),我不知道如何获取更新的 cmets 列表!我知道 Jinja 可能不是最好的工具,并且考虑过使用 Alpine JS x-for 循环,但我很想知道 Jinja 是否有办法在本地执行此操作。

谢谢!!

  • 实际问题是什么?评论在传递到 url 时不保存,或者 jinja 在页面刷新后不显示它们?
  • Jinja 在页面刷新后显示它们,但我想知道如何通过我的 FastAPI 路由手动触发刷新,或者有一种优雅的方式将发布的评论添加为 dom 中的元素而不刷新
  • 这是使用 success 回调函数向服务器发出 javascript 和 ajax(或普通 xhr)请求的要点,该回调函数将触发页面刷新或在给定的响应数据上重建 dom
  • 现在这就是我要返回的 \' return { \"status\" : \"SUCCESS\", \"data\" : req_info } \' 我应该改变它来触发刷新吗?
  • 我说的不是后端。您的前端部分(发送给客户端的 Jinja 模板)必须调用 api 端点来创建评论。如果您正在回答数据,那么您可以使用 javascript 更新您的 dom 而无需刷新页面。或者您可以在获得成功代码时触发刷新页面(再次使用 javascript)

标签: python jinja2 fastapi


【解决方案1】:

这听起来像是WebSockets 的用例。下面是基于上面文档中给出的示例,并且可以处理多个连接,将新添加的评论广播到所有连接的客户端。因此,如果您在浏览器的多个选项卡中打开http://127.0.0.1:8000/,并使用其中一个连接添加新评论,则其他所有连接也将收到新评论。如果您不想广播消息,则可以改用await manager.send_personal_message(data, websocket)

应用程序.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)

模板/索引.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>

【讨论】:

  • 哇,我从来不知道 websockets !这太酷了,而且有效!我应该注意什么安全问题?另外,当我推送到 heroku @chris 时,代码会起作用吗?
  • 看看this
  • 另一个快速的问题 - 我如何控制“document.createElement”位的样式?评论在页面角落显示为未格式化,但我希望它出现在我创建的 div 中。有什么建议吗?
猜你喜欢
  • 2020-05-11
  • 2021-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 2018-11-03
  • 2018-12-25
相关资源
最近更新 更多