How to filter requests in django templates

I need to execute a filtered request from a django template to get a set of objects equivalent to the python code in the view:

queryset = Modelclass.objects.filter(somekey=foo) 

In my template, I would like to do

 {% for object in data.somekey_set.FILTER %} 

but I just can't figure out how to write FILTER.

+60
python django django-templates
21 Oct '08 at 23:55
source share
5 answers

You cannot do it, it is by design. The authors of the Django project assumed a strict separation of presentation code from data logic. Filtering models is data logic, and HTML output is presentation logic.

So you have a few options. The easiest way is to do filtering and then pass the result to render_to_response . Or you can write a method in your model so that you can say {% for object in data.filtered_set %} . Finally, you can write your own template tag, although in this particular case I would recommend this.

+97
Oct 22 '08 at 0:00
source share

I just add an extra template tag, for example:

 @register.filter def in_category(things, category): return things.filter(category=category) 

Then I can do:

 {% for category in categories %} {% for thing in things|in_category:category %} {{ thing }} {% endfor %} {% endfor %} 
+22
May 7 '13 at
source share

I regularly run into this problem and often use the add method solution. However, there are certain cases when the "add method" or "calculate it in the view" does not work (or does not work well). For example. when you cache the template fragments and need some non-trivial calculation of the database to create it. You do not want to do work with the database if you do not need it, but you will not know if you need it until you are deep in the logic of the templates.

Some other possible solutions:

  • Use the {% expr <expression> tag as <var_name>%} found at http://www.djangosnippets.org/snippets/9/ The expression is any legitimate Python expression with your Context template as your local scope.

  • Change the template processor. Jinja2 ( http://jinja.pocoo.org/2/ ) has a syntax that is almost identical to the Django template language, but with full Python accessibility. It is also faster. You can do this in bulk or restrict its use to the templates you are working on, but use the "safe" Django templates for pages supported by developers.

+11
Oct 23 '08 at 17:22
source share

This can be solved using the assignment tag:

 from django import template register = template.Library() @register.assignment_tag def query(qs, **kwargs): """ template tag which allows queryset filtering. Usage: {% query books author=author as mybooks %} {% for book in mybooks %} ... {% endfor %} """ return qs.filter(**kwargs) 
+8
Dec 23 '12 at 12:27
source share

Another option is that if you have a filter that you always want to apply, add a user manager to the model in question, which always applies the filter to the results returned.

A good example of this is the Event model, where for 90% of the queries you make on the model, you need something like Event.objects.filter(date__gte=now) , that is, you usually are interested in Events that are upcoming. It will look like this:

 class EventManager(models.Manager): def get_query_set(self): now = datetime.now() return super(EventManager,self).get_query_set().filter(date__gte=now) 

And in the model:

 class Event(models.Model): ... objects = EventManager() 

But again, this applies to the same filter against all default queries executed in the Event model, and therefore some of the methods described above are not so flexible.

+6
Sep 10 '12 at 11:37
source share



All Articles