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"

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ś.


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.


@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ć.


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 %}

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 %}


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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.