Django模板循环中自定义filter返回值不更新是什么原因
问题成因
- Django原生QuerySet仅支持存放同一模型的实例,如果你是通过
QuerySet.union()方法拼接多个不同模型的查询集来得到links,union返回的所有实例都会被强制转换为首个调用union的查询集所属的模型类型,调用_meta.verbose_name时自然全部返回第一个模型的别名。 - 如果你是用通用外键关联不同模型,直接传通用外键的中间模型实例给过滤器,而没有取到实际关联的业务模型实例,也会出现返回值不符合预期的情况。
解决方案
- 调整视图层的
links构造逻辑:不要使用union拼接不同模型的查询集,改为将查询集转为普通Python列表后再合并,保留每个实例的原始模型类型:
# 视图代码示例 from your_app.models import Unit, OtherModel def your_view(request): # 分别查询不同模型的实例,转为列表后合并 unit_list = list(Unit.objects.filter(your_condition=xxx)) other_list = list(OtherModel.objects.filter(your_condition=xxx)) links = unit_list + other_list return render(request, "your_template.html", {"links": links})
- 优化自定义过滤器的健壮性,兼容更多传参场景:
from django import template register = template.Library() @register.filter def verbose_name(obj): # 优先取实例对应模型的verbose_name if hasattr(obj, "_meta"): return obj._meta.verbose_name # 兼容直接传入模型类的场景 if hasattr(obj, "__class__") and hasattr(obj.__class__, "_meta"): return obj.__class__._meta.verbose_name return ""
- 如果使用了通用外键,模板调用过滤器时要传入实际的关联对象:
{% load to_and %} {% for link in links %} <!-- content_object才是实际关联的不同模型的实例 --> {% if link.content_object|verbose_name == "Unit" %} {{ link.content_object|verbose_name }} {{ link.content_object.id }} {% endif %} {% endfor %}
内容的提问来源于stack exchange,提问作者Habib Ur Rehman
相关产品推荐
相关产品推荐

