跳到主要内容

模板引擎

Flask 使用 Jinja2 作为默认模板引擎,它提供了强大的模板功能。

基本语法

变量输出

<p>Hello, {{ name }}!</p>
<p>{{ user.name }}</p>
<p>{{ items[0] }}</p>

过滤器

<p>{{ name|upper }}</p>
<p>{{ name|lower }}</p>
<p>{{ name|title }}</p>
<p>{{ name|trim }}</p>
<p>{{ html_content|safe }}</p>
<p>{{ users|length }}</p>
<p>{{ price|round(2) }}</p>
<p>{{ date|datetimeformat('%Y-%m-%d') }}</p>

控制结构

<!-- if 语句 -->
{% if user %}
<p>Hello, {{ user.name }}!</p>
{% elif guest %}
<p>Hello, Guest!</p>
{% else %}
<p>Hello, Stranger!</p>
{% endif %}

<!-- for 循环 -->
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% else %}
<li>No items</li>
{% endfor %}
</ul>

<!-- 循环变量 -->
{% for item in items %}
{{ loop.index }} - {{ item }}
{{ loop.index0 }} - 从0开始的索引
{{ loop.first }} - 是否是第一个
{{ loop.last }} - 是否是最后一个
{{ loop.length }} - 总数量
{% endfor %}

模板继承

基础模板

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Default Title{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
<nav>{% block nav %}{% endblock %}</nav>

<main>
{% block content %}{% endblock %}
</main>

<footer>{% block footer %}{% endblock %}</footer>

{% block scripts %}{% endblock %}
</body>
</html>

子模板

<!-- templates/page.html -->
{% extends "base.html" %}

{% block title %}My Page{% endblock %}

{% block content %}
<h1>Welcome</h1>
<p>This is my page content.</p>
{% endblock %}

{% block scripts %}
<script src="app.js"></script>
{% endblock %}

super() 函数

{% block content %}
{{ super() }} <!-- 保留父模板内容 -->
<p>Additional content</p>
{% endblock %}

宏(Macros)

定义宏

<!-- templates/macros.html -->
{% macro input(name, value='', type='text', size=20) %}
<input type="{{ type }}" name="{{ name }}"
value="{{ value }}" size="{{ size }}">
{% endmacro %}

{% macro render_field(field) %}
<div class="field">
{{ field.label }}
{{ field(**kwargs) }}
{% if field.errors %}
<ul class="errors">
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endmacro %}

使用宏

{% from "macros.html" import input, render_field %}

<form>
{{ input('username') }}
{{ input('password', type='password') }}
{{ render_field(form.email) }}
</form>

包含模板

{% include 'header.html' %}

<main>Content here</main>

{% include 'footer.html' %}

<!-- 带条件 -->
{% include 'sidebar.html' ignore missing %}
{% include 'sidebar.html' ignore missing with context %}

上下文处理器

@app.context_processor
def utility_processor():
def format_price(amount):
return f'${amount:.2f}'

return dict(format_price=format_price)

模板中使用:

<p>Price: {{ format_price(29.99) }}</p>

自定义过滤器

@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]

# 或使用装饰器
@app.template_filter()
def datetimeformat(value, format='%Y-%m-%d'):
return value.strftime(format)

模板中使用:

<p>{{ "hello"|reverse }}</p>
<p>{{ post.created_at|datetimeformat }}</p>

自动转义

<!-- 默认转义 HTML -->
<p>{{ user_input }}</p>

<!-- 标记为安全(不转义) -->
<p>{{ html_content|safe }}</p>

<!-- 手动转义 -->
<p>{{ user_input|e }}</p>

<!-- 禁用自动转义块 -->
{% autoescape false %}
<p>{{ html_content }}</p>
{% endautoescape %}

静态文件

<!-- 使用 url_for 生成静态文件 URL -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">

模板测试

{% if users is defined %}
Users is defined
{% endif %}

{% if number is none %}
Number is None
{% endif %}

{% if items is iterable %}
Items is iterable
{% endif %}

{% if users is mapping %}
Users is a dict
{% endif %}

下一步

学习表单处理和验证。