2010-01-08 9 views
7

Je veux imprimer un dictionnaire, trié par la clé. Le tri des clés est facile dans la vue, en plaçant simplement les clés dans une liste puis en triant la liste. Comment puis-je faire défiler les clés dans le modèle, puis obtenir la valeur du dictionnaire.Django | trier dict dans le modèle

{% for company in companies %} 
    {% for employee, dependents in company_dict.company.items %} 
    {% endfor %} 
{% endfor %} 

(juste composé l'exemple ...) La partie qui ne fonctionne pas est la partie « company_dict.company.items ». J'ai besoin de la "compagnie" pour être la valeur de l'entreprise. À l'heure actuelle, la société est à la recherche d'une clé nommée «entreprise», pas la valeur de «société» de la boucle ci-dessus.

Je fais un peu de traitement pour mettre le dictionnaire de dictionnaires ensemble. Changer la disposition des données n'est pas vraiment une option. Je pense que la bonne approche consiste à écrire une balise de modèle, je voulais juste savoir s'il y avait un moyen intégré que j'ai manqué.

+4

Une raison pour laquelle vous ne le faites pas dans la vue? –

+0

C'est un tas de traitement. Et pour le configurer afin de ne pas avoir à faire quoi que ce soit dans le modèle, prendrait un second passage aux données. Je suppose que je pourrais juste faire ça ... Figuré s'il était possible de partir tel quel, ce serait mieux. – johannix

Répondre

2

essayez ceci: http://www.bhphp.com/blog4.php/2009/08/17/django-templates-and-dictionaries

un filtre de modèle personnalisé fera l'affaire.

from django import template 
register = template.Library() 

def dict_get(value, arg): 
    #custom template tag used like so: 
    #{{dictionary|dict_get:var}} 
    #where dictionary is duh a dictionary and var is a variable representing 
    #one of it's keys 

    return value[arg] 

register.filter('dict_get',dict_get) 

plus sur les filtres de modèles personnalisés: http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#howto-custom-template-tags

dans votre exemple, vous feriez:

{% for employee, dependents in company_dict|company %} 
+2

Merci beaucoup! J'ai dû modifier ce que tu as fait un peu. Mon filtre renvoie "valeur [arg] .iteritems()" et le modèle ressemble à: {% pour employé, dépendants dans company_dict | get_dict_and_iter: company%} – johannix

+0

hey tout ce qui fonctionne. la plupart des personnes utilisant ce site pourraient modifier ce que j'ai fait à leur situation aussi bien. –

19

créer un filtre personnalisé, qui est comme ceci:

from django import template 
from django.utils.datastructures import SortedDict 

register = template.Library() 

@register.filter(name='sort') 
def listsort(value): 
    if isinstance(value, dict): 
     new_dict = SortedDict() 
     key_list = sorted(value.keys()) 
     for key in key_list: 
      new_dict[key] = value[key] 
     return new_dict 
    elif isinstance(value, list): 
     return sorted(value) 
    else: 
     return value 
    listsort.is_safe = True 

Ensuite, dans votre modèle, vous l'appellerez en utilisant:

{% for key, value in companies.items|sort %} 
     {{ key }} {{ value }} 
{% endfor %} 

Vous serez en mesure d'obtenir la dictée triée par clé.

+1

Peut-être presque exacte en double, mais tandis que l'autre n'a pas, cette réponse m'a aidé et est papa-gomme brillant, merci beaucoup! – mVChr

+0

Il m'a également aidé plus que la réponse précédente! – Mibou

+0

* "Marquer un filtre is_safe forcera la valeur de retour du filtre à une chaîne.Si votre filtre doit renvoyer une valeur booléenne ou autre, le marquage is_safe aura probablement des conséquences inattendues (comme la conversion d'un False booléen en string ' False '). "* ([Documentation django] (https://docs.djangoproject.com/fr/1.6/howto/custom-template-tags/#filters-and-auto-escaping)) Donc, c'est probablement mieux pour supprimer cette ligne is_safe. –

1

Cette dernière solution m'a aussi été très utile. J'utilise Django 1.6.2, et il semble convertir un dict en une liste avec la clé comme premier élément de cette liste et le contenu comme le second. Donc, même quand je passe dans un dict, il le traite comme une liste. Donc, je peaufiné ci-dessus pour ressembler à ceci, et il fonctionne pour moi:

@register.filter(name='sort') 
def listsort(value): 
    if isinstance(value, list): 
     return sorted(value, key=lambda k:k[0]) 
    else: 
     return value 
0

pour certains reasone filtre de Turikumwe pas fonctionné pour moi (python3.4, Django 1.7), donc je réécris à retourner la liste des tuples au lieu de SertedDict ou OrderedDict:

@register.filter(name='sort') 
def listsort(value): 
    if isinstance(value, dict): 
     a = [] 
     key_list = sorted(value.keys()) 
     for key in key_list: 
      a.append((key, value[key])) 
     return a 
    elif isinstance(value, list): 
     return sorted(value) 
    else: 
     return value 

listsort.is_safe = True 

donc, dans le modèle on n'a pas besoin d'obtenir .items

{% for key, value in companies|sort %} 
     {{ key }} {{ value }} 
{% endfor %} 
0

réponse de Turikumwe m'a près, bu Je n'ai pas travaillé pour mon environnement: python3 et Django 1.10.

Je trouve que l'invocation du filtre avec:

{% for key, value in companies.items|sort %} 
     {{ key }} {{ value }} 
{% endfor %} 

fait des résultats dans un objet ItemsView, pas un dict. (Je suspecte que c'est un problème de python 2 contre 3). Compte tenu de la ItemsView, la réponse est encore plus facile

from django import template 
from django.utils.datastructures import ItemsView 

register = template.Library() 

@register.filter(name='sort') 
def listsort(value): 
    if isinstance(value, ItemsView) or isinstance(value, list): 
     return sorted(value) 
    else: 
     return value 
Questions connexes