必须手动注册自定义过滤器:在应用的templatetags/目录下创建Python文件,以@register.filter装饰函数,确保应用已加入INSTALLED_APPS;过滤器仅接受value和可选arg两个参数,返回值需为字符串或安全类型。

怎么注册自定义过滤器到 Django 模板
必须手动注册,Django 不会自动发现 templatetags 目录下的函数。漏掉注册步骤,模板里用 |my_filter 会静默失败(不报错,但没效果)。
实操建议:
- 在应用目录下建
templatetags/子目录(含__init__.py) - 新建 Python 文件如
text_extras.py,开头必须写from django import template+register = template.Library() - 每个过滤器函数前加
@register.filter装饰器(不能漏@,也不能写成@register.simple_tag) - 确保该应用已添加到
INSTALLED_APPS(否则load text_extras会报Invalid template library)
过滤器函数的参数和返回值怎么写才安全
Django 过滤器只接受**一个或两个参数**:第一个是待处理对象(value),第二个是可选参数(arg)。多于两个参数会直接报 TypeError;返回值必须是字符串或能被模板安全转义的类型(否则可能触发 SafeText 问题)。
常见错误现象:|truncatechars:10:True 报错 —— 因为 truncatechars 是内置过滤器,支持两个参数,但自定义过滤器默认只认一个额外参数(即 arg),想支持多个得用 @register.filter(needs_autoescape=True) 配合手动处理,一般不推荐。
示例(安全写法):
@register.filter
def ellipsize(value, length=15):
if not isinstance(value, str):
return value
if len(value) <= length:
return value
return value[:length] + '…'
注意:ellipsize 在模板中调用为 {{ post.title|ellipsize:20 }},length 是唯一允许的额外参数。
为什么模板里 load 了还是提示 “Invalid filter”
最常见原因是路径或命名冲突:Django 要求 templatetags 必须在某个已注册的 app 内,且 load 语句中的名字必须和 Python 文件名完全一致(不含 .py)。
使用场景:你在 blog/templatetags/text_extras.py 里写了过滤器,那模板里必须写 {% load text_extras %},而不是 {% load blog.text_extras %} 或 {% load text_extras.py %}。
容易踩的坑:
- 文件名含下划线但
load时用了中划线(text-extras❌) - Python 文件里有语法错误,导致整个模块导入失败(此时
load会报错,但错误信息不提示具体哪行) - 过滤器函数名和内置过滤器重名(如叫
default),Django 会优先用内置的,你的函数被忽略 - 开发时改了过滤器逻辑但没重启 Django 开发服务器(
runserver缓存了模板标签模块)
要不要对输入做 escape?什么时候关 autoescape
默认情况下,Django 会对过滤器返回值再做一次 HTML 转义。如果你的过滤器本意就是输出 HTML(比如把 Markdown 转成带 <p> 的片段),就必须显式声明 @register.filter(is_safe=True),否则尖括号会被变成 。
但更关键的是:如果返回值已经含 HTML 标签,又没标 is_safe=True,结果就是页面显示源码而非渲染效果;反之,若你处理的是纯文本却标了 is_safe=True,可能引发 XSS。
实操建议:
- 纯文本处理(截断、大小写、替换)→ 不用管
is_safe,保持默认即可 - 返回 HTML 字符串(如
<strong>xxx</strong>)→ 加@register.filter(is_safe=True) - 不确定是否安全?用
mark_safe()包裹返回值(但仅限你 100% 确认内容可信)
性能影响很小,但安全边界必须卡准 —— 模板层的 autoescape 是最后一道防线,别绕过它除非真有必要。
复杂点在于:同一个过滤器在不同上下文中可能需要不同 escape 行为,这时候就得拆成两个函数,或者加个布尔参数控制(但别让参数逻辑变重,模板调用越简单越好)。










