¿Cómo realizo el filtrado de consultas en las plantillas de django?

Necesito realizar una consulta filtrada desde una plantilla de django, para obtener un conjunto de objetos equivalente al código de Python dentro de una vista:

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

En mi plantilla me gustaría hacer

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

pero parece que no puedo encontrar la forma de escribir FILTRO.

No puedes hacer esto, que es por diseño. Los autores del marco de Django intentaron una separación estricta del código de presentación de la lógica de datos. Filtrar modelos es lógica de datos, y generar HTML es lógica de presentación.

Así que tienes varias opciones. Lo más fácil es hacer el filtrado, luego pasar el resultado a render_to_response . O puede escribir un método en su modelo para que pueda decir {% for object in data.filtered_set %} . Finalmente, podría escribir su propia etiqueta de plantilla, aunque en este caso específico no lo recomendaría.

Acabo de agregar una etiqueta de plantilla extra como esta:

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

Entonces puedo hacer:

 {% for category in categories %} {% for thing in things|in_category:category %} {{ thing }} {% endfor %} {% endfor %} 

Me encuentro con este problema regularmente y con frecuencia uso la solución “agregar un método”. Sin embargo, definitivamente hay casos en los que “agregar un método” o “calcularlo en la vista” no funciona (o no funciona bien). Por ejemplo, cuando almacena en caché fragmentos de plantillas y necesita algún cálculo de base de datos no trivial para producirlos. No desea hacer el trabajo de base de datos a menos que lo necesite, pero no sabrá si lo necesita hasta que esté en la lógica de la plantilla.

Algunas otras soluciones posibles:

  1. Use la {% expr como %} etiqueta de plantilla que se encuentra en http://www.djangosnippets.org/snippets/9/ La expresión es cualquier expresión legal de Python con el Contexto de su plantilla como su ámbito local.

  2. Cambia tu plantilla de procesador. Jinja2 ( http://jinja.pocoo.org/2/ ) tiene una syntax que es casi idéntica al lenguaje de la plantilla de Django, pero con la potencia de Python disponible. También es más rápido. Puede hacer esto al por mayor, o puede limitar su uso a las plantillas en las que está trabajando, pero use las plantillas “más seguras” de Django para las páginas mantenidas por el diseñador.

Esto se puede resolver con una etiqueta de asignación:

 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) 

La otra opción es que si tiene un filtro que siempre desea aplicar, agregar un administrador personalizado en el modelo en cuestión que siempre aplica el filtro a los resultados devueltos.

Un buen ejemplo de esto es un modelo de Event , donde para el 90% de las consultas que realiza en el modelo, deseará algo como Event.objects.filter(date__gte=now) , es decir, normalmente está interesado en Events que son proximo Esto se vería como:

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

Y en el modelo:

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

Pero, de nuevo, esto aplica el mismo filtro en todas las consultas predeterminadas realizadas en el modelo de Event y, por lo tanto, no es tan flexible como algunas de las técnicas descritas anteriormente.