如何让Django自定义过滤器支持{{ 对象.属性|过滤器 }}的简洁调用?
要实现{{ moderated_object.field_name | approved }}这种简洁的过滤器调用,你可以通过包装字段值为包含上下文信息的对象来实现,具体步骤如下:
- 定义一个包装类,用来存储字段值、所属对象和字段名:
class ModeratedValue: def __init__(self, value, instance, field_name): self.value = value self.instance = instance self.field_name = field_name
- 自定义字段描述符,让模型字段返回包装后的对象:
class ModeratedFieldDescriptor: def __init__(self, original_field): self.original_field = original_field self.field_name = None def __get__(self, instance, owner): if instance is None: return self # 获取原始字段值 raw_value = self.original_field.__get__(instance, owner) # 返回包装后的对象,带上实例和字段名 return ModeratedValue(raw_value, instance, self.field_name) def __set__(self, instance, value): # 保留字段的赋值逻辑 self.original_field.__set__(instance, value)
- 在你的模型中,用这个描述符包装需要审核的字段:
from django.db import models class ModeratedModel(models.Model): # 示例字段,假设对应审核状态字段为`title_approved` title = ModeratedFieldDescriptor(models.CharField(max_length=200)) # 审核状态字段 title_approved = models.BooleanField(default=False) content = ModeratedFieldDescriptor(models.TextField()) content_approved = models.BooleanField(default=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 给每个描述符设置字段名 for name, attr in self.__class__.__dict__.items(): if isinstance(attr, ModeratedFieldDescriptor): attr.field_name = name class Meta: abstract = True
- 最后编写自定义模板过滤器:
from django import template register = template.Library() @register.filter def approved(moderated_value): # 只处理包装后的ModeratedValue对象 if not isinstance(moderated_value, ModeratedValue): return moderated_value # 拼接审核状态字段名(比如title对应title_approved) approval_field = f"{moderated_value.field_name}_approved" # 检查是否通过审核 if getattr(moderated_value.instance, approval_field, False): return moderated_value.value # 未通过则返回空字符串或默认值 return ""
这样一来,在模板里直接写{{ moderated_object.title | approved }}就可以了——过滤器会自动从包装对象里拿到所属实例和字段名,检查对应的审核状态,只有通过时才返回字段值,否则返回空。
如果你的审核状态存储方式不同(比如存在关联模型而非同表字段),只需要修改approved过滤器里的逻辑,比如从关联表中查询审核状态即可。
内容的提问来源于stack exchange,提问作者Homunculus Reticulli
相关产品推荐
相关产品推荐

