- Python Falcon教程
- Python Falcon - 主页
- Python Falcon - 简介
- Python Falcon - 环境设置
- Python Falcon - WSGI 与 ASGI
- Python Falcon - Hello World(WSGI)
- Python Falcon - 女服务员
- Python Falcon - ASGI
- 蟒蛇Falcon - Uvicorn
- Python Falcon - API 测试工具
- 请求与响应
- Python Falcon - 资源类
- Python Falcon - 应用程序类
- Python Falcon - 路由
- Falcon - 后缀响应者
- Python Falcon - 检查模块
- Python Falcon - Jinja2 模板
- Python Falcon - cookie
- Python Falcon - 状态代码
- Python Falcon - 错误处理
- Python Falcon - 钩子
- 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 框架使用的最流行的模板库之一。在本节中,我们将了解如何将 inja2 与 Falcon 应用程序一起使用。jinja2 是一种快速且设计人员友好的模板语言,易于配置和调试。其沙盒环境可以轻松防止不受信任的代码执行、禁止潜在的不安全数据以及防止跨站脚本攻击(称为XSS 攻击)。
jinja2的另一个非常强大的功能是模板继承,其中您可以定义具有公共设计功能的基本模板,子模板可以覆盖这些功能。
首先,使用 PIP 实用程序在当前 Python 环境中安装jinja2 。
pip3 install jinja2
你好世界模板
jinja2模块定义了一个 Template 类。Template 对象是通过读取包含 HTML 脚本(扩展名为 .html)的文件的内容来获取的。通过调用此 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代码并在浏览器中访问http://localhost:8000/hello链接。
模板变量
jinja2是一个服务器端模板库。通过将 jinja2 模板语言的各种元素作为占位符放置在 HTML 脚本内的适当分隔符内,将网页构建为模板。模板引擎读取 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 代码并输入http://localhost:8000/hello/Priya作为 URL。浏览器显示以下输出 -
jinja2 模板中的循环
如果响应者传递任何 Python 可迭代对象(例如列表、元组或字典),则可以使用其循环构造语法在 jinja2 模板内遍历其元素。
{% for item in collection %} HTML block {% endfor %}
在以下示例中,on_get()响应程序将作为dict对象列表的 Students 对象发送到模板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 模板。它接收作为字典对象列表的学生对象,并将每个键的值放入表的 <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="http://localhost: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属性中的表单数据,该属性只不过是表单元素及其值的字典。然后添加学生词典。
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路线。您会发现附加了一个新行。
多部分表格
为了让用户从本地文件系统中选择文件, HTML 表单的enctype属性必须设置为 multipart/form-data。Falcon 使用MultipartFormHandler来处理 multipart/form-data 媒体类型,允许它迭代表单中的正文部分。
BodyPart类具有以下属性 -
Stream - 仅用于当前主体部分的流包装器
数据- 主体部分内容字节
如果未指定, content_type将默认为 text/plain,根据 RFC
text - 当前正文部分解码为文本字符串(仅当其类型为 text/plain 时,否则无)
media - 由媒体处理程序以与 req.media 相同的方式自动解析
name, filename - Content-Disposition 标头中的相关部分
secure_filename - 可以在服务器文件系统上安全使用的清理文件名。
以下 HTML 脚本 ( index.html ) 是一个多部分表单。
<html> <body> <form action="http://localhost: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)
运行上面的程序并访问http://localhost: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" } ]