2008-10-21 26 views
62

necesito para realizar una consulta filtrada desde dentro de una plantilla de Django, para obtener un conjunto de objetos equivalentes al código Python en una vista:¿Cómo se realiza el filtrado de consulta en las plantillas de Django

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

En mi plantilla I quisiera hacer

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

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

Respuesta

98

No puede hacer esto, que 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.

Así que tiene varias opciones. Lo más fácil es hacer el filtrado, luego pasar el resultado al 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.

+2

Gracias por la aclaración del concepto de diseño django. Estoy usando el método de método modelo. – Ber

+2

¡Hola gente es 2014 ahora! Aproximadamente 6 años más tarde, las bibliotecas de JS han progresado mucho, y el filtrado de una cantidad no demasiado grande de datos debería hacerse más bien en el lado del cliente con el soporte de una buena biblioteca de scripts Java, o al menos AJAX-ed. – andi

+1

@andi: ciertamente estoy de acuerdo, incluso para conjuntos de datos moderadamente grandes, p. incluso miles de filas en una mesa. Después de haber trabajado en bases de datos con millones de filas, definitivamente hay un lugar para el filtro del lado del servidor :) –

11

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). P.ej. 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:

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

  2. Cambie su procesador de plantillas. 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.

6

La otra opción es que si usted tiene un filtro que siempre se desea aplicar, añadir un custom manager en el modelo en cuestión que siempre se aplica el filtro a los resultados devueltos.

Un buen ejemplo de esto es un modelo Event, donde el 90% de las consultas que se hace en el modelo que se va a querer algo así como Event.objects.filter(date__gte=now), es decir, que está normalmente interesado en que se Events próxima. Este sería el resultado:

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 se aplica el mismo filtro contra todas las consultas predeterminadas realizadas en el modelo Event y por lo tanto no es tan flexible algunos de las técnicas descritas arriba.

8

Esto se puede solucionar 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) 
22

acabo de agregar una etiqueta de plantilla adicional del modo siguiente:

@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 %} 
+0

Estoy intentando esta solución pero sigue desencadenando un error: las instrucciones '' for 'deben usar el formato' para x en y ': para p en r | people_in_roll_department: d'. ¿Algunas ideas? – diosney

+1

Golpeado por un error desagradable :(https://code.djangoproject.com/ticket/19882 – diosney

Cuestiones relacionadas