- Python Falcon 教程
- Python Falcon - 首页
- Python Falcon - 简介
- Python Falcon - 环境搭建
- Python Falcon - WSGI 与 ASGI
- Python Falcon - Hello World (WSGI)
- Python Falcon - Waitress
- Python Falcon - ASGI
- Python Falcon - Uvicorn
- Python Falcon - API 测试工具
- 请求 & 响应
- Python Falcon - 资源类
- Python Falcon - 应用类
- Python Falcon - 路由
- Falcon - 后缀响应器
- Python Falcon - Inspect 模块
- Python Falcon - Jinja2 模板
- Python Falcon - Cookie
- Python Falcon - 状态码
- Python Falcon - 错误处理
- Python Falcon - Hook
- Python Falcon - 中间件
- Python Falcon - CORS
- Python Falcon - WebSocket
- Python Falcon - SQLAlchemy 模型
- Python Falcon - 测试
- Python Falcon - 部署
- Python Falcon 有用资源
- Python Falcon - 快速指南
- Python Falcon - 有用资源
- Python Falcon - 讨论
Python Falcon - Jinja2 模板
Falcon 库主要用于构建 API 和微服务。因此,默认情况下,Falcon 响应器返回 JSON 响应。但是,如果内容类型更改为 **falcon.MEDIA_HTML**,则可以渲染 HTML 输出。
使用可变数据渲染 HTML 内容非常繁琐。为此,使用 Web 模板库。许多 Python Web 框架都捆绑了特定的模板库。但 Falcon 作为一个极简主义的微框架,并没有预捆绑任何一个。
**Jinja2** 是许多 Python 框架使用的最流行的模板库之一。在本节中,我们将了解如何在 Falcon 应用程序中使用 Jinja2。Jinja2 是一种快速且对设计人员友好的模板语言,易于配置和调试。它的沙箱环境使其易于防止执行不受信任的代码,禁止潜在的不安全数据,并防止跨站点脚本攻击(称为 **XSS 攻击**)。
**Jinja2** 的另一个非常强大的功能是 **模板继承**,您可以在其中定义一个具有通用设计特征的基本模板,子模板可以覆盖该模板。
首先,使用 PIP 工具在当前 Python 环境中安装 **Jinja2**。
pip3 install jinja2
Hello World 模板
**Jinja2** 模块定义了一个 Template 类。通过读取包含 HTML 脚本(带有 .html 扩展名)的文件内容来获得 Template 对象。通过调用此 Template 对象的 **render()** 方法,可以将 HTML 响应渲染到客户端浏览器。Response 对象的 **content_type** 属性必须设置为 **falcon.MEDIA_HTML**。
让我们将以下 HTML 脚本另存为应用程序文件夹中的 **hello.py**。
<html> <body> <h2>Hello World</h2> </body> </html>
示例
下面资源类中的 **on_get()** 响应器读取此文件并将其渲染为 HTML 响应。
import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("hello.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render() app = falcon.asgi.App() hello = HelloResource() app.add_route('/hello', hello) if __name__ == "__main__": uvicorn.run("hello:app", host="0.0.0.0", port=8000, reload=True)
输出
运行上面的 Python 代码,并在浏览器中访问 **https://127.0.0.1:8000/hello** 链接。
模板变量
**Jinja2** 是一个服务器端模板库。网页被构建为一个模板,通过在 HTML 脚本内的适当分隔符内将 Jinja2 模板语言的各种元素作为占位符。模板引擎读取 HTML 脚本,在服务器上用上下文数据替换占位符,重新组装 HTML,并将其渲染到客户端。
**Template.render()** 函数有一个可选的上下文字典参数。此字典的关键属性成为模板变量。这有助于在网页中渲染响应器传递的数据。
示例
在以下示例中,路由 ** /hello/nm** 与资源对象注册,其中 nm 是路径参数。**on_get()** 响应器将其作为上下文传递给从网页获得的模板对象。
import uvicorn import falcon import falcon.asgi from jinja2 import Template class HelloResource: async def on_get(self, req, resp, nm): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("hello.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render({'name':nm}) app = falcon.asgi.App() hello = HelloResource() app.add_route('/hello/{nm}', hello) if __name__ == "__main__": uvicorn.run("hello:app", host="0.0.0.0", port=8000, reload=True)
**hello.html** 在模板变量名称中读取路径参数。它充当 HTML 脚本中的占位符。它放在 **{{** 和 **}}** 符号中,以便其值显示为 HTML 响应。
<html> <body> <h2>Hello {{ name }}</h2> </body> </html>
输出
运行 Python 代码并输入 **https://127.0.0.1:8000/hello/Priya** 作为 URL。浏览器显示以下输出 -
Jinja2 模板中的循环
如果响应器传递任何 Python 可迭代对象,例如列表、元组或字典,则可以使用其循环构造语法在 Jinja2 模板中遍历其元素。
{% for item in collection %} HTML block {% endfor %}
在以下示例中,**on_get()** 响应器将 students 对象(它是 **dict** 对象列表)发送到模板 **list.html**。它依次遍历数据并将其渲染为 HTML 表格。
import falcon import json from waitress import serve from jinja2 import Template students = [ {"id": 1, "name": "Ravi", "percent": 75.50}, {"id": 2, "name": "Mona", "percent": 80.00}, {"id": 3, "name": "Mathews", "percent": 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_HTML fp=open("list.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render({'students':students})
**list.html** 是一个 Jinja2 模板。它接收 students 对象作为字典对象的列表,并将每个键的值放在表格的 <td>..<.td> 元素内。
<html> <body> <table border=1> <thead> <tr> <th>Student ID</th> <th>Student Name</th> <th>percentage</th> <th>Actions</th> </tr> </thead> <tbody> {% for Student in students %} <tr> <td>{{ Student.id }}</td> <td>{{ Student.name }}</td> <td>{{ Student.percent }}</td> <td> <a href="#">Edit</a> <a href="#">Delete</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
在浏览器的地址栏中访问 ** /students** 路由。学生列表将在浏览器中呈现。
HTML 表单模板
在本节中,我们将了解 Falcon 如何从 HTML 表单读取数据。让我们将以下 HTML 脚本另存为 myform.html。我们将使用它来获取 Template 对象并渲染它。
<html> <body> <form method="POST" action="https://127.0.0.1:8000/students"> <p>Student Id: <input type="text" name="id"/> </p> <p>student Name: <input type="text" name="name"/> </p> <p>Percentage: <input type="text" name="percent"/> </p> <p><input type="submit"> </p> </body> </html>
Falcon App 对象在 Hello.py 文件中声明,该文件还具有映射到 ** /adddnew** 路由的资源类。**on_get()** 响应器读取 **myform.html** 并渲染相同的内容。将显示 HTML 表单。表单通过 POST 方法提交到 ** /students** 路由。
为了能够读取表单数据,必须将 **falcon.RequestOptions** 类的 **auto_parse_form_urlencoded** 属性设置为 True。
app = falcon.App() app.req_options.auto_parse_form_urlencoded = True
这里,我们还从 **student.py** 导入 **StudentResource** 类。**on_get()** 响应器呈现学生列表。
当用户填写并提交表单时,将调用 **on_post()** 响应器。此方法在 **req.params** 属性中收集表单数据,这只是一个表单元素及其值的字典。然后追加 **students** 字典。
def on_post(self, req, resp): student=req.params students.append(student)
**hello.py** 的完整代码如下:
import falcon import json from waitress import serve from jinja2 import Template from student import StudentResource class MyResource: def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("myform.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render() app = falcon.App() app.req_options.auto_parse_form_urlencoded = True form = MyResource() app.add_route('/addnew', form) app.add_route("/students", StudentResource()) if __name__ == '__main__': serve(app, host='0.0.0.0', port=8000)
包含 **StudentResource** 类以及 **on_get()** 和 **on_post()** 响应器的 student.py 如下:
import falcon import json from waitress import serve from jinja2 import Template students = [ {"id": 1, "name": "Ravi", "percent": 75.50}, {"id": 2, "name": "Mona", "percent": 80.00}, {"id": 3, "name": "Mathews", "percent": 65.25}, ] class StudentResource: def on_get(self, req, resp): resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_HTML fp=open("list.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render({'students':students}) def on_post(self, req, resp): student = req.params students.append(student) resp.text = "Student added successfully." resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON
从命令行运行 **hello.py**。通过输入 **http://locLhost:8000/addnew** 在浏览器中打开 HTML 表单。
**students** 数据库字典将被追加。访问 ** /students** 路由。您会发现添加了一行新数据。
多部分表单
为了让用户从本地文件系统中选择文件,HTML 表单的 **enctype** 属性必须设置为 multipart/form-data。Falcon 使用 **MultipartFormHandler** 处理 multipart/form-data 媒体类型,允许它遍历表单中的主体部分。
**BodyPart** 类具有以下属性:
**stream** - 仅适用于当前主体部分的流包装器
**data** - 主体部分内容字节
**content_type** 如果未指定,则默认为 text/plain,根据 RFC
**text** - 当前主体部分解码为文本字符串(仅在类型为 text/plain 时提供,否则为 None)
**media** - 通过媒体处理程序自动解析,方式与 req.media 相同
**name, filename** - 来自 Content-Disposition 标头的相关部分
**secure_filename** - 可以安全地用于服务器文件系统的经过清理的文件名。
以下 HTML 脚本(**index.html**)是一个多部分表单。
<html> <body> <form action="https://127.0.0.1:8000/hello" method="POST" enctype="multipart/form-data"> <h3>Enter User name</h3> <p><input type='text' name='name'/></p> <h3>Enter address</h3> <p><input type='text' name='addr'/></p> <p><input type="file" name="file" /></p> <p><input type='submit' value='submit'/></p> </form> </body> </html>
此表单由下面代码中 **HelloResource** 类的 **on_get()** 响应器呈现。表单数据提交到 **on_post()** 方法,该方法遍历各部分并发送表单数据的 JSON 响应。
import waitress import falcon import json from jinja2 import Template class HelloResource: def on_get(self, req, resp): resp.status = falcon.HTTP_200 resp.content_type = 'text/html' fp=open("index.html","r") tempobj=Template(fp.read()) resp.body=tempobj.render() def on_post(self, req, resp): result=[] for part in req.media: data={"name" :part.name, "content type":part.content_type, "value":part.text, "file":part.filename} result.append(data) resp.text = json.dumps(result) resp.status = falcon.HTTP_OK resp.content_type = falcon.MEDIA_JSON app = falcon.App() hello = HelloResource() app.add_route('/hello', hello) if __name__ == '__main__': waitress.serve(app, host='0.0.0.0', port=8000)
运行上述程序并访问 **https://127.0.0.1:8000/hello** 链接以渲染表单,如下所示:
填写数据并提交表单后,JSON 响应将在浏览器中呈现,如下所示:
[ { "name": "name", "content type": "text/plain", "value": "SuyashKumar Khanna", "file": null }, { "name": "addr", "content type": "text/plain", "value": "New Delhi", "file": null }, { "name": "file", "content type": "image/png", "value": null, "file": "hello.png" } ]