Python Falcon Jinja2模板

Python Falcon Jinja2模板

Falcon库主要用于构建API和微服务。因此,默认情况下,Falcon响应器会返回一个JSON响应。然而,如果将内容类型改为 falcon.MEDIA_HTML,就 有可能渲染HTML输出。

渲染带有可变数据的HTML内容是非常繁琐的。为了这个目的,可以使用网络模板库。许多Python网络框架都捆绑了特定的模板库。但是Falcon作为一个极简的微型框架并没有预先捆绑任何人。

Jinja2 是最流行的模板库之一,被许多Python框架使用。在本节中,我们将看到如何在Falcon应用程序中使用inja2。jinja2是一种快速且对设计师友好的模板语言,易于配置和调试。它的沙盒环境使它很容易防止执行不受信任的代码,禁止潜在的不安全数据,并防止跨站脚本攻击(称为 XSS攻击 )。

jinja2 的另一个非常强大的功能是 模板继承 ,在这里你可以定义一个具有共同设计特征的基础模板,子模板可以覆盖。

首先,使用PIP工具在当前的Python环境中安装 jinja2

pip3 install jinja2

Hello World模板

jinja2 模块定义了一个Template类。Template对象是通过读取包含HTML脚本的文件内容(扩展名为.html的文件)获得的。通过调用这个模板对象的 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

Python Falcon - Jinja2模板

模板变量

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。浏览器显示以下输出 –

Python Falcon - Jinja2模板

jinja2模板的循环

如果响应者传递任何Python可迭代对象,如列表、元组或字典,其元素可以在jinja2模板内使用其循环结构语法进行遍历。

{% for item in collection %}
HTML block
{% endfor %}

在下面的例子中, on_get() 响应器发送学生对象,这是一个 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模板。它接收学生对象作为字典对象的列表,并将每个键的值放在一个表格的

…<.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 路线。学生名单就会在浏览器中呈现。

Python Falcon - Jinja2模板

HTML表格模板

在本节中,我们将看到Falcon如何从HTML表单中读取数据。让我们把下面的HTML脚本保存为myform.html。我们将用它来获取模板对象并渲染它。

<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

在这里,我们也从stud ent.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表单。

Python Falcon - Jinja2模板

学生 数据库的字典将被追加。访问 /students 路线。你会发现一个新的行被追加。

Python Falcon - Jinja2模板

多部分表格

为了让用户从本地文件系统中选择文件,HTML表单的 enctype 属性必须被设置为multipart/form-data。Falcon使用 MultipartFormHandler 来处理multipart/form-data媒体类型,允许它遍历表单中的主体部分。

BodyPart 类有以下属性—

  • stream – 当前身体部分的流包装器

  • data – 身体部分的内容字节

  • 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)

Run the above program and visit http://localhost:8000/hello link to render the form as shown below −

Python Falcon - Jinja2模板

当填写完数据后提交表单时,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"
   }
]

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程