Como acessar um elemento de dicionário em um modelo do Django?


181

Gostaria de imprimir o número de votos que cada escolha obteve. Eu tenho esse código em um modelo:

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

votesé apenas um dicionário enquanto choicesé um objeto de modelo.

Isso gera uma exceção com esta mensagem:

"Could not parse the remainder"

Respostas:


63

Para ecoar / estender o comentário de Jeff, o que acho que você deve procurar é simplesmente uma propriedade em sua classe Choice que calcule o número de votos associados a esse objeto:

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

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

    votes = property(calculateVotes)

E então no seu modelo, você pode fazer:

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

A marca de modelo, IMHO é um pouco exagerada para esta solução, mas também não é uma solução terrível. O objetivo dos modelos no Django é isolá-lo do código em seus modelos e vice-versa.

Eu tentaria o método acima e veria o SQL que o ORM gera, pois não tenho certeza se ele pré-armazenará em cache as propriedades e apenas criará uma subseleção para a propriedade ou se iterativamente / on- demanda execute a consulta para calcular a contagem de votos. Mas, se gerar consultas atrozes, você sempre poderá preencher a propriedade em sua exibição com os dados que você mesmo coletou.


obrigado @john ewart, sua solução funcionou para mim. Eu sou novato em django e python e não consigo descobrir como obter o sql que o ORM gerou.
Mohamed

Você pode encontrar a resposta para esse trecho aqui: docs.djangoproject.com/en/dev/faq/models/… É bastante simples, na verdade, e pode ser exibido em seu modelo ou registrado em um recurso de registro, mas é necessário lembre-se de ativar DEBUG para que isso funcione.
21710 John Ewart

esta solução é perfeita para um problema que eu tenho tido com modelos de Django Templating + Google App Engine. Eu gostaria de poder votar em você duas vezes.
Conrad.Dean

5
Embora funcione, não é muito eficiente. Ele está fazendo consultas sql em um loop (algo que você deve evitar). Criar o seu próprio tag para fazer pesquisas de dicionários é fácil: @ register.filter def lookup (d, key): se d e isinstance (d, dict): d.get retorno (key)
dalore

Criar uma classe é muito caro; um dicionário melhor estruturado, combinado com a .itemschamada (como ilustrado em uma das outras respostas), é uma solução muito mais simples.
Zags 07/02

285
choices = {'key1':'val1', 'key2':'val2'}

Aqui está o modelo:

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

Basicamente, .itemsé uma palavra-chave do Django que divide um dicionário em uma lista de (key, value)pares, bem como o método Python .items(). Isso permite a iteração sobre um dicionário em um modelo do Django.


@anacarolinats (e outros) apenas certifique-se de iterar sobre a chave, o valor para options.items. Ainda deve funcionar.
precisa saber é o seguinte

Finalmente! Obrigado!! : D
djGrill

portanto, no mecanismo de modelo não é possível usar (). BTW Obrigado wotks para mim.
BlaShadow

6
Solução concisa agradável para a pergunta. Para esclarecer, itemsé uma chamada de método Python no dicionário, não uma palavra-chave do Django. Como Alex Martelli aponta , é basicamente o mesmo que iteritems. Como Wilhelm respondeu, a pesquisa de dicionário é a 3ª em precedência para pesquisas de pontos. Se você tiver um item no dicionário 'items', receberá esse valor de volta em vez de uma lista de tuplas. Para testar: adicione {'items':'oops'}ao seu dicionário e você obterá uma lista com marcadores de letras da palavra 'oops'
cod3monk3y 8/11/13

1
Use collections.OrderedDict para controlar a ordem da iteração
dnalow

186

você pode usar a notação de ponto:

As pesquisas de pontos podem ser resumidas assim: quando o sistema de modelos encontra um ponto em um nome de variável, ele tenta as seguintes pesquisas, nesta ordem:

  • Pesquisa no dicionário (por exemplo, foo ["bar"])
  • Pesquisa de atributo (por exemplo, foo.bar)
  • Chamada de método (por exemplo, foo.bar ())
  • Pesquisa no índice de lista (por exemplo, foo [2])

O sistema usa o primeiro tipo de pesquisa que funciona. É lógica de curto-circuito.


44
No seu caso, a escolha é uma variável. Fazendo .choice irá procurar o valor para a chave "escolha" e não o valor para a chave.
ibz 30/01

+1 para as informações, mesmo que a pergunta fosse uma espécie de "adivinhe o que estou pensando". Obrigado Wilhelm.
Eficker # 2531

1
Isso funciona mesmo com dicionários aninhados. Código Python: Código do my_dict[1][2]modelo:my_dict.1.2
djsmith

2
@ JCLeitão Porque a versão correta é d.key.1- nota o segundo.
Izkata

3
Verifique os documentos sobre isso ... de "1.6 docs.djangoproject.com/en/1.6/topics/templates/#variables ": Observe que "bar" em uma expressão de modelo como {{foo.bar}} será interpretada como uma string literal e não usando o valor da variável “bar”, se houver alguma no contexto do modelo.
jamesc

25

Você precisa encontrar (ou definir) uma tag de modelo 'get', por exemplo, aqui .

A definição da tag:

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

E é usado como:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}

3
considerar h.get(key,'default_value')por causa do KeyError
semiomant

9

Use itens do dicionário:

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


6

Semelhante à resposta de @russian_spy:

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

Isso pode ser adequado para quebrar dicionários mais complexos.


3

Idealmente, você criaria um método no objeto de escolha que se encontrasse em votos ou criaria um relacionamento entre os modelos. Uma tag de modelo que executou a pesquisa no dicionário também funcionaria.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.