it-swarm.com.de

Wie führe ich eine Abfragefilterung in Django Vorlagen durch?

Ich muss eine gefilterte Abfrage in einer Django Vorlage ausführen, um eine Gruppe von Objekten zu erhalten, die python Code in einer Ansicht entspricht:

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

In meiner Vorlage würde ich gerne machen

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

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

73
Ber

Sie können dies nicht tun, was beabsichtigt ist. Die Autoren des Django Frameworks beabsichtigten eine strikte Trennung von Präsentationscode und Datenlogik. Das Filtern von Modellen ist Datenlogik und das Ausgeben von HTML ist Präsentationslogik.

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

112
Eli Courtwright

Ich füge nur ein zusätzliches Template-Tag hinzu:

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

Dann kann ich machen:

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

Ich stoße regelmäßig auf dieses Problem und verwende häufig die "Methode hinzufügen" -Lösung. Es gibt jedoch definitiv Fälle, in denen "eine Methode hinzufügen" oder "in der Ansicht berechnen" nicht funktioniert (oder nicht gut funktioniert). Z.B. wenn Sie Vorlagenfragmente zwischenspeichern und eine nicht triviale DB-Berechnung benötigen, um sie zu erstellen. Sie möchten die DB-Arbeit nicht ausführen, es sei denn, Sie müssen es tun, aber Sie werden nicht wissen, ob Sie dies tun müssen, bis Sie mit der Vorlagenlogik vertraut sind.

Einige andere mögliche Lösungen:

  1. Verwenden Sie das Template-Tag {% expr <expression> als <var_name>%} unter http://www.djangosnippets.org/snippets/9/ Der Ausdruck ist ein beliebiger legaler Python Ausdruck mit dem Kontext Ihrer Vorlage als lokalem Bereich.

  2. Ändern Sie Ihren Vorlagenprozessor. Jinja2 ( http://jinja.pocoo.org/2/ ) hat eine fast identische Syntax wie die Django Template-Sprache, jedoch mit vollem Python verfügbarer Strom. Es ist auch schneller. Sie können diesen Vorgang im Großhandel durchführen oder die Verwendung auf Vorlagen beschränken, an denen Sie arbeiten , aber verwenden Sie Djangos "sicherere" Vorlagen für vom Designer gepflegte Seiten.

11
Peter Rowell

Dies kann mit einem Zuweisungs-Tag gelöst werden:

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)
9
chrisv

Die andere Möglichkeit besteht darin, dass Sie, wenn Sie einen Filter haben, den Sie immer anwenden möchten, dem betreffenden Modell ein benutzerdefinierter Manager hinzufügen, das den Filter immer auf die zurückgegebenen Ergebnisse anwendet.

Ein gutes Beispiel hierfür ist ein Event -Modell, bei dem Sie für 90% der Abfragen, die Sie an dem Modell durchführen, etwas wie Event.objects.filter(date__gte=now) wünschen, dh, Sie interessieren sich normalerweise für Events, die anstehen. Das würde so 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()

Auch hier gilt derselbe Filter für alle Standardabfragen, die für das Modell Event ausgeführt werden, und daher sind einige der oben beschriebenen Techniken nicht so flexibel.

8
mrmagooey