bigywater.tech
Flask · 55

自定义 Template Filter

怎么给模板加一个自己的过滤器?过滤器返回 HTML 为什么容易出 XSS?能读模板变量吗?什么时候注册才合法?这篇把每个坑都跑一遍。

54
Flask 环境里内置过滤器的个数(不含自己加的)
Markup.format
过滤器返回 HTML 时安全的写法
AssertionError
第一个请求之后再注册过滤器时的报错

四种注册方式

实测 · 本机执行输出
  {{ 1234567.891|money }}                → ¥1,234,567.89
  {{ 1234567.891|money("$", 0) }}        → $1,234,568
  {{ "hi"|shout }}                       → HI!
  {{ "a b c"|rw }}                       → c b a
  {{ 21|double }}                        → 42
  {{ "x"|bpf }}                          → bp:x
  {{ 3|money(digits=1)|shout }}          → ¥3.0!

上一篇:Context Processor;下一篇:自定义 Template Global;自动转义详见自动转义与 XSS 防护。

参数与链式

实测 · 本机执行输出
  filters 里自定义的与内置的总数: 67 | 内置 54 个

自动转义与返回值

实测 · 本机执行输出
  x|bold        (x=<script>alert(1)</script>) → &lt;b&gt;&lt;script&gt;alert(1)&lt;/script&gt;&lt;/b&gt;
  x|bold_safe   (x=<script>alert(1)</script>) → <b>&lt;script&gt;alert(1)&lt;/script&gt;</b>
  x|bold_wrong  (x=<script>alert(1)</script>) → <b><script>alert(1)</script></b>

带上下文的过滤器

实测 · 本机执行输出
  {{ "a"|who }}(模板里有 user=ann)→ a@ann
  没有 user → a@匿名
  {{ "a"|ctx_path }} → a:/path
  {{ "a"|envname }} → a|autoescape=select_jinja_autoescape

边界

实测 · 本机执行输出
  None 传给过滤器 → type=NoneType
  没定义的变量传给过滤器 → type=Undefined
  过滤器里抛异常 → ValueError: 过滤器里出错了
  模板里写了不存在的过滤器 → TemplateAssertionError: No filter named 'nope'.

注册时机

实测 · 本机执行输出
  还没处理过请求时 add_template_filter('late') → 成功(test_request_context 与渲染不算「第一个请求」)
  第一个请求之后 add_template_filter → AssertionError: The setup method 'add_template_filter' can no longer be called on the application. It has already handled its 
  直接写 jinja_env.filters["direct"] 之后 → direct:1

内置过滤器

实测 · 本机执行输出
   54 个: abs attr batch capitalize center count d default dictsort e escape filesizeformat first float forceescape format groupby indent int items join last length list lower map max min pprint random reject rejectattr replace reverse round safe select selectattr slice sort string striptags sum title tojson trim truncate unique upper urlencode urlize wordcount wordwrap xmlattr

分步演示

自定义过滤器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:异步过滤器(enable_async)、pass_eval_context 的用法、过滤器在 {% macro %} 里与 import 之后的可见性、国际化(Babel)提供的过滤器
    京ICP备2026067502号-1京公网安备11010502063487号