Fork me on GitHub

Instead of filtering data in the view, we can filter data in the template. For example with:

{% for product in products %}
    {% if product.is_active %}
        {{ product.name }}
    {% endif %}
{% endfor %}

Here we thus enumerate over the products in product, check if it is an active product, and only then we render the .name of the product.

Why is it a problem?

Templates should not be concerned with business logic, they should only implement rendering logic. Templates thus try to let data look pleasant on the screen, but they should not decide what that data is, that is the responsibility of the view.

It is less efficient to let the template do this. It means that you first load all Products into memory, pass these to the template, and then the template will have to decide what to render or not. The template engine is not that fast, and could thus easily go into timeout if the number of products is large.

One often filters on related models as well, for example:

{% for product in products %}
    {% if product.category.is_active %}
        {{ product.name }}
    {% endif %}
{% endfor %}

This will make extra queries in the template, and thus turn into a N+1 problem.

What can be done to resolve the problem?

One should filter in the view. Django’s ORM makes filtering easier and more efficient. the filtering is done at the database side, and a database is designed to do this efficient. It will not generate N+1 problems if you filter on related objects, and furthermore it will reduce the bandwidth between the database and the Django/Python layer.

Instead of filtering the products in the template, we thus filter in the view:

from django.shortcuts import render

def my_view(request):
    # …
    products = Product.objects.filter(is_active=True)
    # …
    context = {
        'products': products
    }
    return render(request, 'some_template.html', context)

then we can render the active products with:

{% for product in products %}
    {{ product.name }}
{% endfor %}