89 votes

Listes séparées par des virgules dans les modèles django

Si fruits est la liste ['apples', 'oranges', 'pears'] ,

Y a-t-il un moyen rapide d'utiliser les balises de template de django pour produire "pommes, oranges et poires" ?

Je sais qu'il n'est pas difficile de faire cela en utilisant une boucle et des {% if counter.last %} mais comme je vais l'utiliser à plusieurs reprises, je pense que je vais devoir apprendre à écrire des instructions personnalisées. étiquettes et je ne veux pas réinventer la roue si cela a déjà été fait.

Par ailleurs, mes tentatives de supprimer le Virgule d'Oxford (c'est-à-dire le retour des "pommes, oranges et poires") sont encore plus désordonnées.

4 votes

Pourquoi n'utilisez-vous pas la balise join template existante ?

1 votes

@S.Lott : Je n'ai pas repéré la balise join template lorsque j'ai regardé la liste sur la page docs. Oups. Cela dit, la prochaine étape est d'envelopper chaque élément de la liste dans un hyperlien, pour lequel je pense que je vais devoir écrire un filtre.

0 votes

Si vous utilisez des liens vers vos URL Django, vous devrez utiliser l'option {% url %} tag. L'étiquette {% for %} La boucle semble soudain beaucoup plus attrayante. L'expression "de manière répétée" signifie souvent que vos modèles doivent {% include %} caractéristiques communes.

158voto

S.Lott Points 207588

Premier choix : utiliser la balise existante du modèle de jointure.

http://docs.djangoproject.com/en/dev/ref/templates/builtins/#join

Voici leur exemple

{{ value|join:" // " }}

Deuxième choix : le faire dans la vue.

fruits_text = ", ".join( fruits )

Fournir fruits_text au modèle pour le rendu.

0 votes

Je pourrais avoir besoin d'autres listes (par exemple vegetables_text ), et il se peut que j'utilise ces listes dans de nombreuses vues, je préférerais donc avoir une solution qui ne me demande que de modifier les modèles. L'une des raisons pour lesquelles je pensais écrire une balise personnalisée est que je peux utiliser Python - join est nettement plus élégant que les boucles for.

10 votes

Il n'insère pas non plus le "et" final.

0 votes

Existe-t-il une meilleure pratique pour déterminer s'il faut le faire dans le modèle ou dans la vue ?

76voto

Voici une solution très simple. Mettez ce code dans comma.html :

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}

Et maintenant, partout où vous auriez mis la virgule, incluez "comma.html" à la place :

{% for cat in cats %}
Kitty {{cat.name}}{% include "comma.html" %}
{% endfor %}

Mise à jour : @user3748764 nous donne une version un peu plus compacte, sans la syntaxe ifequal, qui n'est plus d'actualité :

{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}

Notez qu'il doit être utilisé avant l'élément, et non après.

3 votes

La meilleure solution si vous avez besoin de joindre plus que les chaînes d'un tableau

0 votes

Tout ce que vous avez à faire pour ajouter le Virgule d'Oxford est de remplacer and avec , and .

1 votes

Une version légèrement plus compacte sans la syntaxe ifequal, qui est dépréciée. {% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %} Notez qu'il doit être utilisé avant l'élément, et non après.

35voto

Alex Martelli Points 330805

Je suggérerais un modèle personnalisé de django filtre plutôt qu'un étiquette -- Le filtre est plus pratique et plus simple (le cas échéant, comme ici). {{ fruits | joinby:", " }} ressemble à ce que j'aimerais avoir pour cet usage... avec une joinby filtre :

def joinby(value, arg):
    return arg.join(value)

ce qui, comme vous le voyez, est la simplicité même !

0 votes

Je ne savais pas qu'il existait une distinction entre les balises et les filtres. Alors que les balises personnalisées semblent un peu intimidantes lorsque je consulte la documentation, les filtres semblent plus simples et correspondent exactement à ce dont j'ai besoin dans ce cas. Je vous remercie de votre attention.

7 votes

Ce texte n'insère pas le "et" final.

2 votes

@Meekohi, donc return arg.join(value[:-1]) + ' and ' + value[-1] (pour le style AP, c'est-à-dire sans virgule avant le mot and ; pour le style "virgule d'Oxford", ajouter un + arg juste avant le ` + 'et'). Moi, je préfère la force de l'asyndète, per literarydevices.net/asyndeton . Et ce débat sur le style anglais n'a pas sa place sur StackOverflow de toute façon - emmenez-le sur english.stackexchange.com!-)

9voto

Alasdair Points 36535

Voici le filtre que j'ai écrit pour résoudre mon problème (il n'inclut pas la virgule d'Oxford)

def join_with_commas(obj_list):
    """Takes a list of objects and returns their string representations,
    separated by commas and with 'and' between the penultimate and final items
    For example, for a list of fruit objects:
    [<Fruit: apples>, <Fruit: oranges>, <Fruit: pears>] -> 'apples, oranges and pears'
    """
    if not obj_list:
        return ""
    l=len(obj_list)
    if l==1:
        return u"%s" % obj_list[0]
    else:    
        return ", ".join(str(obj) for obj in obj_list[:l-1]) \
                + " and " + str(obj_list[l-1])

Pour l'utiliser dans le modèle : {{ fruits|join_with_commas }}

4voto

Todd Davies Points 1916

Si vous voulez un '.' à la fin de la réponse de Michael Matthew Toomim, utilisez :

{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X