Flask模板引擎——Jinja2

本文介绍了Flask应用中Jinja2模板引擎的基本用法,包括变量、控制结构、宏及模板继承等内容,并演示了如何使用Flask-Moment进行日期和时间的本地化处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体指只在请求的上下文中才能知道。使用真是只替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask使用了一个名为Jinja2的强大模板引擎。

1. 渲染模板

默认情况下,Flask在程序文件夹中的templates子文件夹中寻找模板。

from flask import Flask, render_template

    app = Flask(__name__)

    @app.route('/')
    def index():
        return render_template('index.html')

    @app.route('/user/<name>')
    def user(name):
        return render_template('user.html', name=name)

render_template 函数的第一个参数是模板的文件名(index.html,user.html),随后的参数都是键值对(name=name),表示模板中变量的真实值。

2. 变量

template/user.html:Jinja2模板

<h1>Hello,{{ name }}!<h1>

{{ name }}结构表示一个变量,告诉模板引擎这个位置的值从渲染模板时使用的数据中获取。
可以使用过滤器修改变量,过滤器名称添加在变量名之后,中间使用竖线分割。

Hello,{{ name|capitalize }}

Jinja2变量过滤器:
safe: 渲染时不转义
capitalize:把值的首字母转换成大写,其他字母转换成小写
lower: 把值转换成小写形式
upper: 把值转换成大写形式
title: 把值中每个单词的首字母都转换成大写
trim: 把值的首尾空格都去掉
striptags: 渲染之前把值中所有的HTML标签都删掉

3.控制结构

if循环

例:

{%if user %}
    Hello, {{ user }}!
{% else %}
    Hello, Stranger!
{% endif %}

for循环

<ul>
    {% for comment in comments %}
        <li>{{ comment }}<li>
    {% endfor %}
</ul>

宏类似于函数。需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复。另一种重复使用代码的强大方式是模板继承。
例:
首先创建一个名为base.html的基模板。

<html>
<head>
    {% block head %}
    <title>{% block title %}{% endblock %} - My Application</titel>
    {% endblock %}
</head>
<body>
    {% block body %}
    {% endblock %}
</body>
<html>

由block标签定义的元素可以在衍生模板中修改。head,title,body,注意title包含在head中
下面示例是基模板的衍生模板。

{% extends "base.html" %}
{% block title %}index{% endblock %}
{% block head %}
    {{ super }}
    <style>
    </style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}

extends指令声明这个模板衍生自base.html。基模板中的三个块被重新定义,模板引擎会将其插入适当的位置。**注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容。

4.自定义错误页面

最常见的错误代码有两个:404,客户端请求未知页面或路由时显示;500,有未处理的异常时显示。
示例:自定义错误页面

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

错误处理程序中引用的模板也需要编写。这些模板应该和常规页面使用相同的布局,因此要有一个导航条和显示错误消息的页面头部。
Flask-Bootstrap提供了一个具有页面基本布局的基模板。
示例:

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
    {% block page_content %}{% endblock %}
</div>
{% endblock %}

这是一个继承自bootstrap/base.html的新模板,其中定义了导航条。content块中只有个div容器,其中包含了一个名为page_content的新的空块,块中的内容由衍生模板定义。
通过继承base.html模板写404.html。示例:

{% extends "base.html" %}

{% block title %}Flasky - Page Not Found{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Not Found</h1>
</div>
{% endblock %}

505.html:

{% extends "base.html" %}

{% block title %}Flasky - Internal Server Error{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Internal Server Error</h1>
</div>
{% endblock %}

user.html:

{% extends "base.html" %}

{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {{ name }}!</h1>
</div>
{% endblock %}

5.链接

Flask提供了url_for()辅助函数,它可以使用程序URL映射中保存的信息生成URL。
使用url_for()生成动态地址时,将动态部分作为关键字参数传入。例如:url_for(‘user’, name = ‘john’, _external = True)的返回结果时http://localhost:5000/user/john.
传入url_for()的关键字参数不仅限于动态路由中的参数。函数能将任何额为参数添加到查询字符中。

6.静态文件

默认设置下,Flask在程序根目录中名为static的子目录中寻找静态文件。
示例展示了如何在程序的基模板中放置favicon.ico图标(此图标就是Flask的logo)。这个图标会显示在浏览器的地址栏中。
示例:

...
{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
{% endblock %}
...

图标的声明会插入head块的末尾。使用super()保留基模板中定义的块的原始内容。

7.使用Flask-Moment本地化日期和时间

Flask-Moments时一个Flask扩展,用于把moment.js集成到jinjia2模板中。
引入moment.js库(在base.html模板底部):

...
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}

在hello.py中加入一个datetime变量:

...
from datetime import datetime
...
moment = Moment(app)
...
@app.route('/')
def index():
    return render_template('index.html',
                           current_time=datetime.utcnow())

使用Flask-Moment渲染时间戳(在index.html中加入):

...
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}.</p>
你提供的是一个简洁美观的登录页面 HTML 模板,使用了 Bootstrap 样式框架。你想 **保留它的样式和结构**,但希望它能与 Flask 后端配合工作 —— 比如实现登录验证、表单提交等功能。 --- ## ✅ 目标 - 保持你提供的登录页外观不变 - 添加 Flask 表单提交功能(POST 请求) - 使用 Flask模板引擎 Jinja2 实现动态内容(如错误提示) - 确保安全性(CSRF 保护) --- ## 🧱 Flask 登录逻辑说明 我们假设你在 Flask 中有如下路由: ```python from flask import Flask, render_template, request, redirect, url_for, flash from flask_wtf.csrf import CSRFProtect app = Flask(__name__) app.secret_key = 'your_secret_key_here' csrf = CSRFProtect(app) csrf.init_app(app) # 模拟数据库用户 users = { 'admin': '123456' } @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] if users.get(username) == password: flash('登录成功!', 'success') return redirect(url_for('index')) else: flash('用户名或密码错误', 'danger') return render_template('login.html') ``` --- ## 📄 修改后的 `templates/login.html` 文件(适用于 Flask) ```html <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <title>登录页</title> <style> form { margin: 150px auto; width: 35%; } .card { padding-left: 50px; padding-right: 50px; } </style> </head> <body> <div class="container"> <form method="post" action="{{ url_for('login') }}" class="text-center"> {{ form.csrf_token }} <img class="mb-4" src="{{ url_for('static', filename='logo.svg') }}" alt="" width="120" height="120"> <h1 class="h3 mb-4 fw-normal">登录</h1> <!-- 错误提示 --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }} alert-dismissible fade show" role="alert"> {{ message }} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> {% endfor %} {% endif %} {% endwith %} <!-- 用户名输入框 --> <div class="mb-4 form-floating"> <input type="text" class="form-control" id="username" name="username" placeholder="用户名" required> <label for="username">用户名</label> </div> <!-- 密码输入框 --> <div class="mb-4 form-floating"> <input type="password" class="form-control" id="password" name="password" placeholder="密码" required> <label for="password">密码</label> </div> <!-- 提交按钮 --> <button class="w-100 btn btn-lg btn-dark" type="submit">登录</button> <p class="mt-5 mb-3 text-muted">© 2025–2035</p> </form> </div> <!-- 引入 Bootstrap JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </body> </html> ``` --- ## 🔍 代码解释 ### 1. 表单方法和动作 ```html <form method="post" action="{{ url_for('login') }}"> ``` - `method="post"`:使用 POST 方法提交登录数据 - `action="{{ url_for('login') }}"`:提交到 Flask 的 `/login` 路由 ### 2. 使用 Flash 显示消息 ```jinja2 {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }} alert-dismissible fade show" role="alert"> {{ message }} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> </div> {% endfor %} {% endif %} {% endwith %} ``` - 使用 Flask 的 `flash()` 函数来显示登录失败/成功的提示信息 - 支持多种类别(success/danger/warning) ### 3. 输入框结构优化 ```html <div class="mb-4 form-floating"> <input type="text" class="form-control" id="username" name="username" placeholder="用户名" required> <label for="username">用户名</label> </div> ``` - 使用 Bootstrap 的浮动标签(Floating Label)组件,提升用户体验 - `required` 属性防止空提交 ### 4. 图片路径处理 ```html <img src="{{ url_for('static', filename='logo.svg') }}" alt=""> ``` - 假设你的图片放在项目目录下的 `static/` 文件夹中 - 使用 Flask 的 `url_for()` 函数确保正确加载资源 --- ## ✅ 效果对比 | 原始 HTML 页面 | 修改后的 Flask 模板 | |----------------|--------------------| | 静态页面 | 可以接收 POST 数据并做判断 | | 无提示机制 | 支持登录成功/失败提示 | | 不支持 CSRF | 使用 Flask-WTF 或手动加入 CSRF Token | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值