能否用CurrentSiteManager检查关联对象的站点而非对象自身?
能否通过CurrentSiteManager检查关联对象的站点?
你说得没错,默认的CurrentSiteManager确实不支持直接使用双下划线的关联路径(比如a__site)来过滤关联对象的站点——它要求指定的字段必须是当前模型(这里是B)自身的直接字段,而不是通过外键关联到其他模型的字段。
不过你完全不用放弃,只需要自定义一个扩展版的管理器就能实现需求,不用在B里重复添加site外键。下面给你两种可行的方案:
方案一:扩展CurrentSiteManager
继承原生的CurrentSiteManager,重写get_queryset方法,让它支持解析关联字段路径:
from django.contrib.sites.models import Site from django.contrib.sites.managers import CurrentSiteManager class RelatedSiteManager(CurrentSiteManager): def __init__(self, related_site_field, *args, **kwargs): self.related_site_field = related_site_field # 这里传入原生site字段名占位,我们自己处理关联逻辑 super().__init__('site', *args, **kwargs) def get_queryset(self): current_site = Site.objects.get_current() # 用指定的关联字段路径构建过滤条件 return super().get_queryset().filter(**{self.related_site_field: current_site})
然后在B模型中使用这个自定义管理器:
class B(models.Model): a = models.ForeignKey(A, on_delete=models.CASCADE) # 保留默认的模型管理器 objects = models.Manager() # 使用自定义的关联站点管理器 on_site = RelatedSiteManager('a__site')
方案二:直接自定义极简管理器
如果不想继承CurrentSiteManager,也可以写一个逻辑更直白的轻量管理器:
from django.contrib.sites.models import Site from django.db import models class BOnSiteManager(models.Manager): def get_queryset(self): # 直接过滤关联的A模型的site等于当前站点 return super().get_queryset().filter(a__site=Site.objects.get_current()) class B(models.Model): a = models.ForeignKey(A, on_delete=models.CASCADE) objects = models.Manager() on_site = BOnSiteManager()
为什么默认的CurrentSiteManager不行?
看原生CurrentSiteManager的源码就能明白:它在get_queryset里是直接用你传入的字段名作为当前模型的字段来构建过滤条件(filter(**{self._site_field_name: current_site})),不会解析双下划线的跨表关联路径。所以你直接传a__site的话,它会去B模型里找名为a__site的字段,自然会报错。
这两种方案都能完美实现你的需求,不用处理重复site外键带来的冗余和数据一致性问题。
内容的提问来源于stack exchange,提问作者bodger
相关产品推荐
相关产品推荐

