plantillas - templates django python
¿Cómo realizo el filtrado de consultas en las plantillas de django? (5)
Necesito realizar una consulta filtrada desde dentro de una plantilla django, para obtener un conjunto de objetos equivalentes al código 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 manera de escribir FILTRO.
Acabo de agregar una etiqueta de plantilla adicional 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 %}
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 quiere aplicar, agregue 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 hace en el modelo va a querer algo como Event.objects.filter(date__gte=now)
, es decir, normalmente está interesado en Events
que son próximo. Esto se vería así:
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 nuevamente, esto aplica el mismo filtro contra todas las consultas predeterminadas hechas en el modelo de Event
y por lo tanto no es tan flexible algunas de las técnicas descritas anteriormente.
Me encuentro con este problema de forma regular y a menudo uso la solución "agregar un método". Sin embargo, definitivamente hay casos donde "agregar un método" o "calcularlo en la vista" no funcionan (o no funcionan bien). Por ejemplo, cuando está almacenando en caché fragmentos de plantilla y necesita algún cálculo de base de datos no trivial para producirlo. No desea hacer el trabajo de DB a menos que lo necesite, pero no sabrá si es necesario hasta que se encuentre dentro de la lógica de la plantilla.
Algunas otras soluciones posibles:
Use la etiqueta de plantilla {% expr <expresión> como <var_name>%} 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.
Cambia tu procesador de plantilla. Jinja2 ( http://jinja.pocoo.org/2/ ) tiene una sintaxis que es casi idéntica al lenguaje de plantilla de Django, pero con el poder completo de Python disponible. También es más rápido. Puede hacerlo 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 los diseñadores.
No puedes hacer esto, lo cual es por diseño. Los autores del framework Django intentaron una separación estricta del código de presentación de la lógica de datos. El filtrado de modelos es una lógica de datos y la salida de HTML es lógica de presentación.
Entonces 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 recomendaría que no lo haga.