2008-10-21 4 views
62

Ich brauche einen gefilterten Abfrage innerhalb einer django Vorlage auszuführen, eine Reihe von Objekten entspricht Python-Code in einer Ansicht zu erhalten:Wie führe ich Abfrage-Filterung in django Vorlagen

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

In meiner Vorlage I möchte

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

tun, aber ich kann einfach nicht herausfinden, wie man FILTER schreibt.

Antwort

98

Sie können dies nicht tun, die von Entwurf ist. Die Django-Framework-Autoren beabsichtigten eine strikte Trennung von Darstellungscode und Datenlogik. Das Filtern von Modellen ist eine Datenlogik, und das Ausgeben von HTML ist eine Präsentationslogik.

So haben Sie mehrere Möglichkeiten. Am einfachsten ist es, die Filterung durchzuführen und das Ergebnis an render_to_response weiterzuleiten. Oder Sie könnten eine Methode in Ihr Modell schreiben, so dass Sie {% for object in data.filtered_set %} sagen können. Schließlich könnten Sie Ihr eigenes Schablonen-Tag schreiben, obwohl ich in diesem speziellen Fall davon abraten würde.

+2

Vielen Dank für die Klärung des Django-Designkonzeptes. Ich verwende den Modellmethodenansatz. – Ber

+2

Hallo Leute ist 2014 jetzt! Ungefähr 6 Jahre später haben JS-Bibliotheken große Fortschritte gemacht, und das Filtern nicht extrem großer Datenmengen sollte eher auf Client-Seite erfolgen, mit Unterstützung einer netten Java-Skript-Bibliothek oder zumindest AJAX-ed. – andi

+1

@andi: Ich stimme sicherlich sogar mit mäßig großen Datensätzen überein, z.B. sogar Tausende von Zeilen in einer Tabelle. Nachdem ich an Datenbanken mit Millionen von Zeilen gearbeitet habe, gibt es immer noch einen Platz für die serverseitige Filterung :) –

11

Ich laufe regelmäßig auf dieses Problem und verwende oft die "add a method" -Lösung. Es gibt jedoch Fälle, in denen "eine Methode hinzufügen" oder "in der Ansicht berechnen" nicht funktioniert (oder nicht gut funktioniert). Z.B. wenn Sie Template-Fragmente zwischenspeichern und einige nicht-triviale DB-Berechnungen benötigen, um sie zu erzeugen. Sie möchten die DB-Arbeit nicht ausführen, es sei denn Sie müssen, aber Sie werden nicht wissen, ob Sie müssen, bis Sie tief in der Vorlagenlogik sind.

Einige andere mögliche Lösungen: mit Ihrer Vorlage Kontext als lokalen Bereich

  1. Verwenden Sie die {% ausdr < Ausdruck> als < var_name>%} Template-Tag bei http://www.djangosnippets.org/snippets/9/ Der Ausdruck fand seinen Ausdruck jede juristische Python ist .

  2. Ändern Sie Ihren Vorlagenprozessor. Jinja2 (http://jinja.pocoo.org/2/) hat eine Syntax, die fast identisch mit der Django-Template-Sprache ist, aber mit voller Python-Power verfügbar ist. Es ist auch schneller. Sie können dies im Großhandel tun, oder Sie können die Verwendung auf Vorlagen beschränken, die Sie arbeiten arbeiten, aber verwenden Sie Djangos "sicherere" Vorlagen für Designer-Seiten verwaltet.

6

Die andere Option ist, dass, wenn Sie einen Filter haben, die Sie immer angewendet werden sollen, ein custom manager auf dem Modell in Frage hinzuzufügen, die immer den Filter gilt für die Ergebnisse zurückgegeben.

Ein gutes Beispiel hierfür ist ein Event Modell, bei dem 90% der Abfragen, die Sie auf dem Modell tun Sie so etwas wie Event.objects.filter(date__gte=now), das heißt Sie sind normalerweise interessiert in Events gehen zu wollen, die kommenden werden. Dies würde wie folgt aussehen:

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

Und im Modell:

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

Aber auch hier gilt den gleichen Filter gegen alle Standardabfragen auf das Event Modell gemacht und so ist nicht so flexibel einig die oben beschriebenen Techniken.

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

Dies kann mit einer Zuweisung Tag gelöst werden

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

Dann kann ich tun:

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

ich fügen Sie einfach einen zusätzlichen Template-Tag wie folgt:

+0

Ich versuche diese Lösung, aber es löst weiterhin einen Fehler aus: ''für' Anweisungen sollten das Format 'für x in y' verwenden: für p in r | Personen_in_Rollen_Department: d'. Irgendwelche Ideen? – diosney

+1

Von einem fiesen Bug getroffen :(https://code.djangoproject.com/ticket/19882 – diosney