写点什么

FastAPI 快速开发 Web API 项目: 模板和 Jinja 介绍

作者:宇宙之一粟
  • 2023-04-18
    广东
  • 本文字数:4009 字

    阅读完需:约 13 分钟

FastAPI 快速开发 Web API 项目:  模板和 Jinja 介绍

FastAPI 快速开发 Web API 项目学习笔记:



前言

模板是以不同格式显示从 API 获取的数据的过程。模板是 Web 应用程序中的前端组件。模板语言允许你借助变量和有限的编程逻辑来生成 HTML/XML 或其他标记语言。


根据前文的系列文章,我们已经学会了如何处理错误的请求响应,接下来我们可以将请求的响应呈现在网页上。在本文中,我们将学习如何使用由 Python 编写的模板语言 Jinja 来渲染来自 API 的响应至网页上,Jinja 旨在帮助 API 响应的呈现过程。

什么是 Jinja

模板是全栈 Web 开发的重要组成部分。使用 Jinja,您可以构建丰富的模板,为您的 Python Web 应用程序的前端提供支持。


Jinja 是一个用 Python 编写的模板引擎,旨在帮助 API 响应的渲染过程。在每种模板语言中,都有变量被替换为实际传递给它们的值,当模板被渲染时,有控制模板逻辑的标签。


安装 jinja2


pipenv install jinja2
复制代码


安装成功后:



Jinja 模板只是一个文本文件。 Jinja 可以生成任何基于文本的格式(HTML、XML、CSV、LaTeX 等)。 Jinja 模板不需要有特定的扩展名:.html.xml 或任何其他扩展名都可以。


关于模版的扩展名:任何文件都可以作为模板加载,无论文件扩展名如何。添加 .jinja 扩展名,如 user.html.jinja 可能会使某些 IDE 或编辑器插件更容易,但这不是必需的。自动转义可以基于文件扩展名应用,因此在这种情况下您需要考虑额外的后缀。识别模板的另一个很好的启发式方法是它们位于模板 templates 文件夹中,而不管扩展名是什么。这是项目的常见布局。


Jinja 模板引擎使用花括号 {} 来区分其表达式和语法与常规 HTML、文本和模板文件中的任何其他变量。{{}} 语法称为变量块。{% %} 语法包含控制结构,如 if/else 、循环和宏。Jinja 模板语言中使用的三种常见语法块包括以下内容:


  • {% ... %}:这种语法用于控制结构等语句。

  • {{ todo.item }}:这个语法用于打印出传递给它的表达式的值。

  • {# Test #}: 这种语法在写评论时使用,不在网页上显示。


Jinja2 是一种流行的模板语言,被 Flask、Bottle、Pelican 使用,也可被 Django 使用。

渲染第一个 Jinja 模板

导入 Jinja 后,您可以继续加载和渲染您的第一个模板:


>>> import jinja2>>> environment = jinja2.Environment()>>> template = environment.from_string("Hello, {{ name }}!") >>> template.render(name="Yuzhou1su")'Hello, Yuzhou1su!'>>>
复制代码


Jinja 的核心组件是 Environment() 类。在此示例中,您创建了一个不带任何参数的 Jinja 环境。稍后您将更改 Environment 的参数以自定义您的环境。在这里,您正在创建一个普通环境,您可以在其中加载字符串 Hello, {{ name }}! 作为模板。


这个例子显示了你在使用 Jinja 时通常会执行的两个重要步骤:


  1. 加载模板:加载包含占位符变量的源。默认情况下,它们包含在一对大括号 {{ }} 中。

  2. 渲染模板:用内容填充占位符。您可以提供字典或关键字参数作为上下文。在本例中,您已经填充了占位符,因此 Hello, Yuzhou1su! 作为输出。

使用外部文件作为模板

与上述方式同理,我们可以使用外部文件作为我们的模版来源,在我们的项目中创建一个新文件夹。在工作目录中,创建一个名为 templates/ 的文件夹。


然后,您可以在 “template” 目录中创建 index.html 模板文件,并使用 Jinja2 语法来呈现它们。例如,在template/index.html 中写入如下内容:


<!DOCTYPE html><html>  <head>    <title>Welcome</title>    <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">  </head>
<body> <h1>Hello, {{ name }}</h1> </body></html>
复制代码


然后回到我们的 main.py 中:


from fastapi import FastAPI, Requestfrom fastapi.responses import HTMLResponsefrom fastapi.staticfiles import StaticFilesfrom fastapi.templating import Jinja2Templates

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

@app.get("/{name}")async def home(request: Request, name: str): return templates.TemplateResponse("index.html", { "request": request, "name": name })
复制代码


整个文件的目录结构如下:



启动 FastAPI 服务 uvicorn main:app --reload --port 8888, 然后另外打开一个终端,执行 curl 127.0.0.1:8888/Yuzhou1su 命令,可以看到如下 name 被渲染出来的结果:



通过浏览器访问这个 http://127.0.0.1:8888/Yuzhou1su,还能看到 css 渲染的颜色:



Jinja 模板变量可以是任何 Python 类型或对象,只要它们可以转换为字符串。可以将模型、列表或字典类型传递到模板中,并通过将这些属性放置在先前列出的第二个块中来显示其属性。在下一节中,我们将看一下过滤器。过滤器是每个模板引擎的重要组成部分,在 Jinja 中,过滤器使我们能够执行某些函数,例如从列表中连接值和检索对象的长度,等等。Jinja 中常用的功能:变量、过滤器、if 语句、循环、宏和模板继承。

变量

模板变量由传递给模板的上下文字典定义。


在模板中,只要应用程序传递了变量,您就可以随意操作这些变量。变量可能还具有您可以访问的属性或元素。变量具有哪些属性取决于提供该变量的应用程序。


除了标准的 Python __getitem__ “下标”语法( [] )之外,您还可以使用点(. )来访问变量的属性。


以下行执行相同的操作:


{{ foo.bar }}{{ foo['bar'] }}
复制代码

Filters

尽管 Python 和 Jinja 的语法非常相似,但是像连接字符串、将字符串的第一个字符设置为大写等修改操作不能使用 Python 的语法在 Jinja 中完成。因此,为了执行这样的修改操作,我们在 Jinja 中使用过滤器。


变量可以被过滤器修改。过滤器与变量用管道符号(|)分隔,并且可以在括号中包含可选参数。可以链接多个过滤器。一个过滤器的输出应用于下一个。过滤器的定义格式如下:


{{ variable | filter_name(*args) }}
复制代码


不加参数的过滤器:


{{ variable | filter_name }}{{ name|striptags|title }}
复制代码


default 过滤器: 如果该值未定义,它将返回传递的默认值,否则返回变量的值:


{{ my_variable | default('my_variable is not defined') }}
复制代码


escape 过滤器: 这个过滤器用于渲染原始 HTML 输出:将字符串 s 中的字符 & < > ' ” 转换为 HTML 安全序列。如果您需要在 HTML 中显示可能包含此类字符的文本,请使用此选项。将返回值标记为标记字符串。


{{ "<title>Todo Application</title>" | escape }}<title>Todo Application</title>
复制代码


类型转换过滤器: 这些过滤器包括 int 和 float 过滤器,用于从一种数据类型转换到另一种数据类型:


{{ 3.142 | int }}3
{{ 20 | float }}20.0
复制代码


join 过滤器join(*value*, *d=u''* , *attribute=None*)返回一个字符串,它是序列中字符串的串联。元素之间的分隔符默认为空字符串,您可以使用可选参数定义它:


{{ [1, 2, 3] | join('|') }}    -> 1|2|3
{{ [1, 2, 3] | join }} -> 123
复制代码


也可以连接对象的某些属性:


{{ users|join(', ', attribute='username') }}
复制代码


长度 filter: 这个过滤器返回一个序列或集合的长度,它的作用与 Python 中 len() 函数的作用相同:


Todo count: {{ todos | length }}Todo count: 4
复制代码

if 条件

Jinja 中 if 语句的用法与 Python 中的用法类似。在 {% %} 控制块中使用。让我们看一个例子:


{% if todos %}<ul>{% for todo in todos %}    <li>{{ todo.name|e }}</li>{% endfor %}</ul>{% endif %}
复制代码

Loop 条件

我们也可以在 Jinja 中对变量进行迭代。这可以是一个列表或一个一般的函数、 比如说下面这个,例如


{% for todo in todos %}    <li>{{ todo.name|e }}</li>{% endfor %}
复制代码


你可以在 for 循环中访问特殊的变量,比如 loop.index ,它给出了当前迭代的索引。


宏可与常规编程语言中的函数相媲美。它们有助于将常用的习语放入可重用的函数中,以免重复自己(“DRY” 原则)。


{% macro input(name, value='', type='text', size=20) %}    <div class="form">        <input type="{{ type }}" name="{{ name }}"            value="{{ value|escape }}" size="{{ size }}">    </div>{% endmacro %}
复制代码


现在,为了在你的表单中快速创建一个输入,调用了这个宏:


{{ input('item') }}
复制代码


渲染完成后,将会返回:


  <div class="form">    <input type="text" name="item" value="" size="20" />  </div>
复制代码

FastAPI 中的 Jinja

FastAPI 实际上是为构建 API 和微服务而设计的。它可用于构建使用 Jinja 提供 HTML 服务的 Web 应用程序,但这并不是它真正优化的目的。


如果您想构建一个在服务器上呈现大量 HTML 的大型网站,Django 可能是更好的选择。


但是,如果您正在使用 React、Angular 或 Vue 等前端框架构建现代网站,那么从 FastAPI 获取数据是一个不错的选择(我们将在本系列的后面部分讨论)。


因此,在本示例系列中,我们将非常谨慎地使用 Jinja 模板,这也是它们在大多数实际项目中的使用方式。我在本系列的此时介绍 HTML 页面的原因是:这将使示例项目更具吸引力。引人入胜的教程是更好的学习工具。了解如何提供临时 HTML 页面(例如,用于用户登录/密码确认页面)是一项常见要求。


希望本文能对你有所帮助,如果喜欢本文,可以点个关注.


下一篇文章见!宇宙古今无有穷期,一生不过须臾,当思奋争。


参考链接:


发布于: 2023-04-18阅读数: 23
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020-05-07 加入

🏆InfoQ写作平台-签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于外企开发,弹性不加班 热衷分享,执着于阅读写作,佛系不水文 同名公众号:《宇宙之一粟》

评论

发布
暂无评论
FastAPI 快速开发 Web API 项目:  模板和 Jinja 介绍_Python_宇宙之一粟_InfoQ写作社区