Django - 从django模板访问外键的Manager

Dav*_*idL 5 django django-templates django-models django-managers

我有两个型号:

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)
Run Code Online (Sandbox Code Playgroud)

我想从产品详细信息模板中获取实时照片.

试过了,

{% for photo in product.photos.live %}
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

Chr*_*att 24

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

既然,你定义live,但也没有定义objects,你实际上没有objects这个模型的经理,即这将失败:ProductPhoto.objects.all().请记住,如果您在模型上定义自定义管理器,Django将不再自动添加一个名为objects.

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

{% for photo in product.photos.all %}
Run Code Online (Sandbox Code Playgroud)

而且,你只会获得"实时"对象.坏消息是,这将打破很多其他依赖于默认管理器作为完整对象集合的东西(例如管理员).你实际上是隐藏了"非实时"对象的块.

你应该拥有的是:

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()
Run Code Online (Sandbox Code Playgroud)

请注意,这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)
Run Code Online (Sandbox Code Playgroud)

在这里,我们实际上是对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()
Run Code Online (Sandbox Code Playgroud)

最后,您将能够在模板中使用它:

{% for photo in product.photos.live %}
Run Code Online (Sandbox Code Playgroud)

  • 在Django 1.6中,方法`get_query_set`被重命名为`get_queryset`. (6认同)
  • 谢谢克里斯最好的答案和详尽的解释.我学到了很多. (2认同)