[Fixed]-Is it possible to use Model manager to filter directly from template?

1👍

Using a custom Manager is not the right way to go. You need to carefully read the whole Django Managers article.

In this situation what you need is a custom QuerySet. Something like this:

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()

Now you can use .active() and .default() methods to filter any BOMVersion-QuerySet. This is actually what you got when you use the reverse relation from Material model, material.bomversion_set is a BOMVersion-QuerySet and thus you don’t have access to BOMVersion.objects, but since its a BOMVersion-QuerySet you can use .active() and .default()

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

However, again this is completely wrong and my advice is not to do it in the template. Use the view to build you querysets, and only iterate them in the template.

Why its bad in the template? Because right now you are making 1 query per material object, and there is no way to optimize it unless you use prefetch_related, but guess what? You can’t use prefetch_related in the django template system. (Its on purpose, and the reason is to not do stuff like that in the template), so the correct approach is to make something similar to this:

#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 %}

Now you are gonna make 1 query for the soproduct with its related product and material data and 1 more query for the requested default_active_bomversions.

👤Todor

Leave a comment