Rust web 框架 axum (三): 使用 askama html 模板

更新日期: 2023-11-11 阅读次数: 1674 字数: 1273 分类: rust

askama 是什么

Askama implements a template rendering engine based on Jinja. It generates Rust code from your templates at compile time based on a user-defined struct to hold the template's context.

askama 即一套模板系统,可以集成到 rust 项目中,并不局限于 axum 中,也不局限于 HTML,任何的模板使用场景都是可以的。

类似 golang 内置的模板系统,及 php laravel 中的 blade,python django 的模板。语法都非常类似。

项目地址:

https://github.com/djc/askama

为何要使用 askama 这里的模板系统

  • 可以将 HTML 代码写在独立的文件中,这样就不需要像上一篇 axum 介绍中 axum 返回 HTML form 表单,并处理 post 请求,将 HTML 代码混在 rust 代码中。这样不方便编辑,也无法高效利用编辑器或 IDE 的增强功能。
  • 可以基于 base 模板做继承,方便保证一个网站所有页面的风格统一,及 HTML 代码的模块化,及复用。
  • 在代码中实现一些 if,及 for 逻辑。

askama V.S. minijinja

  • 2.6K https://github.com/djc/askama
  • 1.1K https://github.com/mitsuhiko/minijinja

添加 askama 依赖

编辑 Cargo.toml 配置文件,增加 askama 及 askama_axum 依赖

[dependencies]
askama = { version = "0.12", features = ["with-axum", "mime", "mime_guess"] }
askama_axum = "0.3.0"
axum = "0.6"

新增模板目录

mkdir templates

新增 html 模板

例如,base.html

内容可以随便写,即一个简单的 HTML 文件。

<h1>Hello </h1>

axum 中使用

use askama::Template;

#[derive(Template)]
#[template(path = "base.html")]
struct HelloTemplate<'a> {
    name: &'a str,
}

async fn hello_template() -> HelloTemplate<'static> {
    HelloTemplate { name: "world" }
}

然后 route 中使用这个 hello_template 即可

let app = Router::new()
    .route("/some_path", get(hello_template))
    ;

到此,axum 与 askama 的集成完成。以下是测试过程中遇到的问题。

单引号 a 与生命周期

下面 rust 代码中,单引号 a 的作用是什么:

struct HelloTemplate<'a> {
    name: &'a str,
}

在 Rust 代码中,单引号 'a 用于定义一个生命周期参数。在这个特定的代码片段中,'a 是用于泛型结构体 HelloTemplate 的生命周期参数。

生命周期参数用于描述引用的有效期,以确保在引用的数据不再有效之前,引用本身仍然有效。在这种情况下,'a 表示 name 字段的引用的生命周期。

HelloTemplate 结构体中的 name 字段的类型是 &'a str,意味着它是一个指向字符串的引用,该引用的生命周期与结构体的生命周期参数 'a 相关联。这意味着 name 字段的引用不能超过 'a 所表示的生命周期。

通过使用生命周期参数,Rust 的借用检查器可以在编译时验证引用的有效性,防止悬垂引用或无效引用的出现,从而提供内存安全性和避免潜在的错误。

askama 模板继承

https://djc.github.io/askama/template_syntax.html#child-template

{% extends "base.html" %}

{% block title %}Index{% endblock %}

{% block head %}
  <style>
  </style>
{% endblock %}

{% block content %}
  <h1>Index</h1>
  <p>Hello, world!</p>
  {% call super() %}
{% endblock %}

askama 官方依赖配置示例

https://djc.github.io/askama/integrations.html#axum-integration

Enabling the with-axum feature appends an implementation of Axum's IntoResponse trait for each template type. This makes it easy to trivially return a value of that type in a Axum handler. See the example from the Askama test suite for more on how to integrate.

如官方 github 的 axum 整合示例中的 Cargo.toml 依赖配置

https://github.com/djc/askama/blob/main/askama_axum/Cargo.toml

[dependencies]
askama = { version = "0.12", path = "../askama", default-features = false, features = ["with-axum", "mime", "mime_guess"] }

需要 enable with-axum feature。

而,我之前配置的是:

[dependencies]
askama = "0.12.1"

于是我参考官方配置修改成了

askama = { version = "0.12", default-features = false, features = ["with-axum", "mime", "mime_guess"] }

askama 官方代码示例

https://github.com/djc/askama/blob/main/askama_axum/tests/basic.rs

could not find askama_axum in the list of imported crates

error[E0433]: failed to resolve: could not find `askama_axum` in the list of imported crates
   --> src/main.rs:101:10
    |
101 | #[derive(Template)]
    |          ^^^^^^^^ could not find `askama_axum` in the list of imported crates
    |
    = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

在 Cargo.toml 中添加了 askama_axum 之后,就可以了。

[dependencies]
askama = { version = "0.12", features = ["with-axum", "mime", "mime_guess"] }
askama_axum = "0.3.0"
axum = "0.6"

unknown field

error[E0609]: no field `title` on type `&HelloTemplate<'a>`
   --> src/main.rs:101:10
    |
101 | #[derive(Template)]
    |          ^^^^^^^^ unknown field
    |
    = note: available fields are: `name`
    = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

将模板文件中的 title 改为 name,就可以编译通过了。

rust 三方依赖包,为何会有 features 的概念

在 Rust 的第三方依赖包中,features 的概念用于启用或禁用库的特定功能或选项。 这允许你根据你的项目需求,在构建依赖包时进行选择性地启用或禁用功能。

许多依赖包提供了一些可选的功能,但不是所有用户都需要或希望使用这些功能。 为了保持库的灵活性和轻量性,开发人员将这些功能作为可选项提供,而不是默认包含在库中。

查看合集

📖 Rust web 框架 axum 教程:从入门到遥遥领先

参考

  • https://www.reddit.com/r/rust/comments/11gizhc/axum_sqlite_minijinja_htmx_winning_website_combo/
  • bootstrap 模板: https://getbootstrap.com/docs/5.3/examples/jumbotron/
  • askama 的官方整合教程: https://github.com/djc/askama/blob/main/askama_axum/tests/basic.rs
  • 基于 axum/askama/htmx 的教程: https://www.joeymckenzie.tech/blog/templates-with-rust-axum-htmx-askama/

tags: axum

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式