Jak uzyskać dostęp do elementu słownika w szablonie Django?

181

Chciałbym wydrukować liczbę głosów uzyskanych przy każdym wyborze. Mam ten kod w szablonie:

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

votesjest tylko słownikiem, podczas gdy choicesjest obiektem modelowym.

Z tym komunikatem powstaje wyjątek:

"Could not parse the remainder"
Mohamed
źródło

Odpowiedzi:

63

Aby powtórzyć / rozszerzyć komentarz Jeffa, myślę, że powinieneś dążyć do po prostu własności w klasie Choice, która oblicza liczbę głosów związanych z tym obiektem:

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

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

    votes = property(calculateVotes)

Następnie w szablonie możesz wykonać:

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

Tag szablonu, to IMHO trochę przesada w przypadku tego rozwiązania, ale nie jest to również okropne rozwiązanie. Celem szablonów w Django jest izolowanie użytkownika od kodu w szablonach i odwrotnie.

Wypróbuję powyższą metodę i zobaczę, co SQL generuje ORM, ponieważ nie jestem pewien, czy z góry głowy buforuje właściwości i po prostu tworzy podselekcję dla właściwości lub czy będzie iteracyjnie / on- uruchom zapytanie, aby obliczyć liczbę głosów. Ale jeśli generuje okropne zapytania, zawsze możesz wypełnić właściwość w swoim widoku danymi, które sam zebrałeś.

John Ewart
źródło
dzięki @john ewart, twoje rozwiązanie zadziałało dla mnie. Jestem nowicjuszem w Django i Pythonie i nie mogę dowiedzieć się, jak uzyskać SQL wygenerowany przez ORM.
Mohamed
Odpowiedź na ten bit można znaleźć tutaj: docs.djangoproject.com/en/dev/faq/models/… To dość proste, faktycznie i może być wyświetlane w szablonie lub zalogowane za pomocą funkcji logowania, ale musisz pamiętaj, aby włączyć DEBUG, aby to zadziałało.
John Ewart,
to rozwiązanie jest idealne na problem, który miałem z modelami szablonów django + google app. Chciałbym móc dwukrotnie zagłosować.
Conrad.Dean
5
Chociaż działa, nie jest zbyt wydajny. Robi zapytania SQL w pętli (należy tego unikać). Tworzenie własnego tagu w celu wyszukiwania odnośników jest łatwe: @ register.filter def lookup (d, key): if d and isinstance (d, dict): return d.get (key)
dalore 30.10.12
Tworzenie klasy to zdecydowanie za dużo; słownik o lepszej strukturze w połączeniu z .itemswywołaniem (jak pokazano na jednej z pozostałych odpowiedzi) jest rozwiązaniem znacznie prostszym.
Zags,
285
choices = {'key1':'val1', 'key2':'val2'}

Oto szablon:

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

Zasadniczo .itemsjest słowem kluczowym Django, które dzieli słownik na listę (key, value)par, podobnie jak metoda Python .items(). Umożliwia to iterację słownika w szablonie Django.

rosyjski_szpieg
źródło
@anacarolinats (i inne) po prostu upewnij się, że wykonujesz iterację zarówno dla klucza, wartości do wyboru. przedmiotów. Powinno nadal działać.
OldTinfoil
Wreszcie! Dziękuję Ci!! : D
djGrill
więc w szablonie silnik nie może użyć (). BTW Dzięki, dziękuję za mnie.
BlaShadow
6
Ładne, zwięzłe rozwiązanie tego pytania. Dla wyjaśnienia, itemsjest to wywołanie słownika w języku Python, a nie słowo kluczowe Django. Jak zauważa Alex Martelli, jest to w zasadzie to samo co iteritems. Jak odpowiedział Wilhelm, wyszukiwanie słownikowe zajmuje 3 miejsce przed wyszukiwaniem kropek. Jeśli masz w słowniku element o nazwie 'items', otrzymasz tę wartość z powrotem zamiast listy krotek. Aby przetestować: dodaj {'items':'oops'}do słownika, a otrzymasz wypunktowaną listę liter od słowa „oops”
cod3monk3y
1
Użyj kolekcji.ZamówionoDykta, aby kontrolować kolejność iteracji
dnalow
186

możesz użyć notacji kropkowej:

Wyszukiwanie kropek można podsumować w następujący sposób: gdy system szablonów napotka kropkę w nazwie zmiennej, spróbuje wykonać następujące wyszukiwania w następującej kolejności:

  • Wyszukiwanie w słowniku (np. Foo [„bar”])
  • Wyszukiwanie atrybutów (np. Foo.bar)
  • Wywołanie metody (np. Foo.bar ())
  • Wyszukiwanie indeksu listy (np. Foo [2])

System używa pierwszego typu wyszukiwania, który działa. To logika zwarć.

Wilhelm
źródło
44
W jego przypadku wybór jest zmienny. Wykonanie .choice spowoduje wyszukanie wartości dla „wyboru” klucza, a nie wartości dla wyboru klucza.
ibz 30.01.11
+1 za informację, mimo że pytanie było rodzajem pytania „zgadnij, o czym myślę”. Dzięki Wilhelm.
eficker 25.10.11
1
Działa to nawet z zagnieżdżonymi słownikami. Kod Python: Kod my_dict[1][2]szablonu:my_dict.1.2
djsmith
2
@ JCLeitão Ponieważ poprawna wersja to d.key.1- zwróć uwagę na drugą.
Izkata
3
Sprawdź jednak dokumenty na ten temat ... z „1.6 docs.djangoproject.com/en/1.6/topics/templates/#variables ”: Zauważ, że „bar” w wyrażeniu szablonu takim jak {{foo.bar}} będzie interpretowane jako dosłowny ciąg znaków i nie wykorzystujący wartości zmiennej „bar”, jeśli istnieje ona w kontekście szablonu.
jamesc
25

Musisz znaleźć (lub zdefiniować) znacznik szablonu „pobierz”, na przykład tutaj .

Definicja znacznika:

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

I jest używany jak:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}
Ned Batchelder
źródło
3
rozważ h.get(key,'default_value')ze względu na KeyError
semiomant
9

Użyj elementów słownika:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}
Priyanshu Chauhan
źródło
6

django_template_filter nazwa filtra get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}
Nick Korolkov
źródło
6

Podobnie do odpowiedzi @russian_spy:

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

Może to być przydatne do rozkładania bardziej złożonych słowników.

Adam Starrh
źródło
3

Idealnie byłoby stworzyć metodę na obiekcie wyboru, który znalazł się w głosach, lub stworzyć relację między modelami. Działa również tag szablonu, który przeprowadził wyszukiwanie słownika.

Jeff Ober
źródło