【问题标题】:Django - accessing foreign key's Manager from django templatesDjango - 从 Django 模板访问外键管理器
【发布时间】:2012-05-28 05:23:37
【问题描述】:

我有两个模型:

class Product(models.Model):
    name = models.CharField(max_length=255)

class ProductPhoto(models.Model):
    product = models.ForeignKey('Product', related_name='photos')
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1)

    live = LiveManager()

class LiveManager(Manager):
    def get_query_set(self):
        return super(LiveManager, self).get_query_set().filter(is_live=1)

我正在尝试从产品详细信息模板中获取实时照片。

试过了,

{% for photo in product.photos.live %}

这不起作用并查看了文档但找不到示例。是否可以从模板中调用外键的管理器?我应该在产品模型中创建一个返回产品照片查询集的函数吗?

谢谢。

【问题讨论】:

    标签: django django-models django-templates django-managers


    【解决方案1】:

    好吧,无论如何,您使用它的方式是错误的。您只需将管理器传递给 for 循环,而不是可以迭代的查询集。但是,photos 本身是一个“相关管理器”,而不是实际的 ProductPhoto 模型,并且相关管理器基于第一个列出的管理器或 objects(默认管理器)。

    由于您定义了 live,但没有同时定义 objects,因此您实际上在此模型上没有 objects 管理器,即 this 将失败:ProductPhoto.objects.all()。请记住,如果您在模型上定义自定义管理器,Django 将不再自动添加一个名为 objects 的管理器。

    好消息是因为live 现在是默认管理器,您可以像这样使用它:

    {% for photo in product.photos.all %}
    

    而且,您只会获得“活动”对象。坏消息是,这将破坏许多其他依赖于默认管理器的东西是对象的完整集合(例如管理员)。您实际上是在隐藏“非活动”对象块。

    你应该拥有的是:

    class ProductPhoto(models.Model):
        product = models.ForeignKey('Product', related_name='photos')
        is_live = models.IntegerField(choices=LIVE_CHOICES, default=1)
    
        objects = models.Manager()
        live = LiveManager()
    

    注意objects 是手动定义的并且它是第一个,这意味着它将保持默认管理器。但是,这将不再允许您在模板中使用 live 管理器。一般来说,对于这样的事情,最好只使用一个管理器并为其添加一个方法以返回“活动”对象:

    class ProductPhotoQuerySet(models.query.QuerySet):
        def live(self):
            return self.filter(is_live=1)
    
    class ProductPhotoManager(models.Manager):
        use_for_related_fields = True
    
        def get_query_set(self):
            return ProductPhotoQuerySet(self.model)
    
        def live(self, *args, **kwargs):
            return self.get_query_set().live(*args, **kwargs)
    

    在这里,我们实际上是 QuerySet Manager 的子类。这将允许您将live 链接到任何地方,而不仅仅是在前面。例如,如果您只有一个没有自定义查询集的自定义管理器,您将只能执行 ProductPhoto.objects.live().filter(...) 而不是 ProductPhoto.objects.filter(...).live()

    然后,您将其作为objects 添加到您的模型中(代替 Django 提供的默认值):

    class ProductPhoto(models.Model):
        product = models.ForeignKey('Product', related_name='photos')
        is_live = models.IntegerField(choices=LIVE_CHOICES, default=1)
    
        objects = ProductPhotoManager()
    

    最后,您可以在模板中使用它:

    {% for photo in product.photos.live %}
    

    【讨论】:

    • 感谢克里斯的最佳答案和详尽的解释。我学到了很多。
    • 方法get_query_set在Django 1.6中被重命名为get_queryset
    • 在遇到我自己的模板问题时偶然发现了这一点。 +1,高质量的答案。
    猜你喜欢
    • 2013-06-01
    • 2011-06-05
    • 1970-01-01
    • 2021-04-10
    • 2018-02-12
    • 2012-07-02
    • 2016-03-03
    • 1970-01-01
    • 2018-10-22
    相关资源
    最近更新 更多