是否可以使用模型管理器直接从模板过滤?

时间:2016-07-12 22:53:06

标签: django

我创建了一个模型管理器,可以过滤数据

class BOMVersion_default_active_Manager(models.Manager):
    def get_queryset(self):
        return super(BOMVersion_default_active, self).get_queryset().filter(is_default=True,is_active=True)


@with_author 
class BOMVersion(models.Model): 
    version = IntegerVersionField( )
    name = models.CharField(max_length=200,null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    material =  models.ForeignKey(Material)
    default_active_objects = BOMVersion_default_active_Manager() 

我尝试在模板的嵌套for循环中使用它(因为我无法直接在模板中过滤,这就是我决定克服这个限制的方法)

{% for bomversion in soproduct.product.material.bomversion.default_active_objects_set.all %}

但我没有得到任何输出。可能是什么问题呢?我可以这样做吗?

1 个答案:

答案 0 :(得分:1)

使用自定义Manager不是正确的方法。您需要仔细阅读整篇Django Managers文章。

在这种情况下,您需要的是自定义QuerySet。像这样:

class BOMVersionQuerySet(models.QuerySet):
    def active(self):
        return self.filter(is_active=True)

    def default(self):
        return self.filter(is_default=True)

@with_author 
class BOMVersion(models.Model): 
    version = IntegerVersionField( )
    name = models.CharField(max_length=200,null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    material =  models.ForeignKey(Material)

    objects = BOMVersionQuerySet.as_manager()

现在,您可以使用.active().default()方法过滤任何BOMVersion-QuerySet。这实际上是您使用Material模型中的反向关系时得到的结果,material.bomversion_setBOMVersion-QuerySet,因此您无法访问BOMVersion.objects,但是因为它BOMVersion-QuerySet您可以使用.active().default()

{% for bomversion in soproduct.product.material.bomversion_set.default.active %}

然而,这又是完全错误的,我的建议是不要在模板中这样做。使用视图构建查询集,并仅在模板中迭代它们。

为什么它在模板中不好?因为您现在每个material对象进行1次查询,除非您使用prefetch_related,否则无法对其进行优化,但猜猜是什么?您不能在django模板系统中使用prefetch_related。 (它是故意的,原因是不要在模板中做那样的事情),所以正确的方法是做出类似的东西:

#in the view:
soproduct = SoProduct.objects.select_related('product__material').prefetch_related(
    Prefetch(
        'product__material__bomversion_set',
        queryset=BOMVersion.objects.default().active()
        to_attr='default_active_bomversions'
    )
).get(pk=soproduct_id)

#in the template:
{% for bomversion in soproduct.product.material.default_active_bomversions %}

现在,您将对soproduct及其相关的productmaterial数据进行1次查询,并对请求的default_active_bomversions进行1次查询。