Wie greife ich auf ein Wörterbuchelement in einer Django-Vorlage zu?

181

Ich möchte die Anzahl der Stimmen ausdrucken, die jede Wahl erhalten hat. Ich habe diesen Code in einer Vorlage:

{% for choice in choices %}
    {{choice.choice}} - {{votes[choice.id]}} <br />
{% endfor %}

votesist nur ein Wörterbuch, während choiceses sich um ein Modellobjekt handelt.

Mit dieser Meldung wird eine Ausnahme ausgelöst:

"Could not parse the remainder"
Mohamed
quelle

Antworten:

63

Um Jeffs Kommentar zu wiederholen, sollten Sie meiner Meinung nach einfach eine Eigenschaft in Ihrer Choice-Klasse anstreben, die die Anzahl der mit diesem Objekt verbundenen Stimmen berechnet:

    class Choice(models.Model):
        text = models.CharField(max_length=200) 

        def calculateVotes(self):
            return Vote.objects.filter(choice = self).count()

        votes = property(calculateVotes)

Und dann können Sie in Ihrer Vorlage Folgendes tun:

    {% for choice in choices %}
            {{choice.choice}} - {{choice.votes}} <br />
    {% endfor %}

Das Template-Tag ist meiner Meinung nach ein bisschen übertrieben für diese Lösung, aber es ist auch keine schreckliche Lösung. Das Ziel von Vorlagen in Django ist es, Sie vom Code in Ihren Vorlagen zu isolieren und umgekehrt.

Ich würde die obige Methode ausprobieren und sehen, welche SQL der ORM generiert, da ich nicht sicher bin, ob die Eigenschaften vorab zwischengespeichert und nur eine Unterauswahl für die Eigenschaft erstellt werden oder ob sie iterativ / on- Führen Sie die Abfrage aus, um die Stimmenzahl zu berechnen. Wenn jedoch grausame Abfragen generiert werden, können Sie die Eigenschaft in Ihrer Ansicht jederzeit mit Daten füllen, die Sie selbst gesammelt haben.

John Ewart
quelle
danke @john ewart, deine lösung hat bei mir funktioniert. Ich bin ein Neuling in Django und Python und kann nicht herausfinden, wie ich die von ORM generierte SQL bekomme.
Mohamed
Die Antwort auf dieses Bit finden Sie hier: docs.djangoproject.com/de/dev/faq/models/… Es ist eigentlich recht einfach und kann in Ihrer Vorlage angezeigt oder mit einer Protokollierungsfunktion protokolliert werden, aber Sie müssen Denken Sie daran, DEBUG einzuschalten, damit dies funktioniert.
John Ewart
Diese Lösung ist perfekt für ein Problem, das ich mit Django Templating + Google App Engine-Modellen hatte. Ich wünschte, ich könnte dich zweimal abstimmen.
Conrad.Dean
5
Während es funktioniert, ist es nicht sehr effizient. Es führt SQL-Abfragen in einer Schleife aus (etwas, das Sie vermeiden sollten). Das Erstellen eines eigenen Tags für Diktat-Lookups ist einfach: @ register.filter def Lookup (d, Schlüssel): Wenn d und isinstance (d, Dikt): Geben Sie d.get (Schlüssel) zurück
dalore
Das Erstellen einer Klasse ist viel zu viel Aufwand. Ein besser strukturiertes Wörterbuch in Kombination mit dem .itemsAufruf (wie in einer der anderen Antworten dargestellt) ist eine weitaus einfachere Lösung.
Zags
285
choices = {'key1':'val1', 'key2':'val2'}

Hier ist die Vorlage:

<ul>
{% for key, value in choices.items %} 
  <li>{{key}} - {{value}}</li>
{% endfor %}
</ul>

Grundsätzlich .itemshandelt es sich um ein Django-Schlüsselwort, das ein Wörterbuch in eine Liste von (key, value)Paaren aufteilt, ähnlich wie die Python-Methode .items(). Dies ermöglicht die Iteration über ein Wörterbuch in einer Django-Vorlage.

russian_spy
quelle
@anacarolinats (und andere) stellen nur sicher, dass Sie beide Schlüssel, den Wert für selection.items, durchlaufen. Es sollte immer noch funktionieren.
OldTinfoil
Schließlich! Danke dir!! : D
djGrill
daher kann in der Template Engine () nicht verwendet werden. Übrigens, danke wotks für mich.
BlaShadow
6
Schöne prägnante Lösung für die Frage. Zur Verdeutlichung itemshandelt es sich um einen Python-Methodenaufruf im Wörterbuch, nicht um ein Django-Schlüsselwort. Wie Alex Martelli betont, ist es im Grunde das gleiche wie iteritems. Wie Wilhelm antwortete, hat die Wörterbuchsuche bei Punktsuchen den 3. Platz. Wenn Sie einen Eintrag in Ihrem Wörterbuch haben 'items', erhalten Sie diesen Wert anstelle einer Liste von Tupeln zurück. Zum Testen: {'items':'oops'}Fügen Sie Ihrem Wörterbuch hinzu, und Sie erhalten eine Liste mit Buchstaben mit Aufzählungszeichen aus dem Wort 'oops'
cod3monk3y
1
Verwenden Sie Sammlungen.OrderedDict, um die Reihenfolge der Iteration zu steuern
dnalow
185

Sie können die Punktnotation verwenden:

Punktsuchen können folgendermaßen zusammengefasst werden: Wenn das Vorlagensystem auf einen Punkt in einem Variablennamen stößt, werden die folgenden Suchvorgänge in dieser Reihenfolge ausgeführt:

  • Wörterbuchsuche (z. B. foo ["bar"])
  • Attributsuche (z. B. foo.bar)
  • Methodenaufruf (zB foo.bar ())
  • Listenindex-Suche (z. B. foo [2])

Das System verwendet den ersten funktionierenden Nachschlagetyp. Es ist Kurzschlusslogik.

Wilhelm
quelle
44
In seinem Fall ist die Wahl eine Variable. Wenn Sie .choice ausführen, wird der Wert für die Schlüsselauswahl "und nicht der Wert für die Schlüsselauswahl" nachgeschlagen.
ibz
+1 für die Info, obwohl die Frage eine Art "Rate was ich denke" -Frage war. Danke Wilhelm.
Eficker
1
Dies funktioniert sogar mit verschachtelten Wörterbüchern. Python-Code: my_dict[1][2]Vorlagencode:my_dict.1.2
DJsmith
2
@ JCLeitão Weil die richtige Version ist d.key.1- beachten Sie die zweite.
Izkata
3
Überprüfen Sie die Dokumente dazu ... aus "1.6 docs.djangoproject.com/de/1.6/topics/templates/#variables ": Beachten Sie, dass "bar" in einem Vorlagenausdruck wie {{foo.bar}} interpretiert wird als Literalzeichenfolge und ohne Verwendung des Werts der Variablen "bar", falls eine im Vorlagenkontext vorhanden ist.
Jamesc
25

Sie müssen beispielsweise hier ein 'get'-Vorlagen-Tag finden (oder definieren) .

Die Tag-Definition:

@register.filter
def hash(h, key):
    return h[key]

Und es wird verwendet wie:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}
Ned Batchelder
quelle
3
Betrachten Sie h.get(key,'default_value')wegen KeyError
Semiomant
9

Verwenden Sie Wörterbuchelemente:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}
Priyanshu Chauhan
quelle
6

django_template_filter Filtername get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}
Nick Korolkov
quelle
6

Ähnlich der Antwort von @russian_spy:

<ul>
{% for choice in choices.items %} 
  <li>{{choice.0}} - {{choice.1}}</li>
{% endfor %}
</ul>

Dies könnte geeignet sein, komplexere Wörterbücher aufzuschlüsseln.

Adam Starrh
quelle
3

Im Idealfall erstellen Sie eine Methode für das Auswahlobjekt, das sich in Abstimmungen befindet, oder erstellen eine Beziehung zwischen den Modellen. Ein Vorlagen-Tag, das die Wörterbuchsuche durchführte, würde ebenfalls funktionieren.

Jeff Ober
quelle