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

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

Existe-t-il un moyen rapide d'utiliser les balises de modèle django pour produire "pommes, oranges et poires"?

Je sais que ce n'est pas difficile de le faire en utilisant une boucle et des instructions {% if counter.last %}, mais parce que je vais l'utiliser à plusieurs reprises, je pense que je vais devoir apprendre à écrire des filtres tags personnalisés, et je ne veux pas réinventer la roue si c'est déjà fait.

En tant qu'extension, mes tentatives de supprimer la virgule Oxford (IE retour "pommes, oranges et poires") sont encore plus messier.

57
demandé sur Alasdair 2009-08-06 05:50:18

9 réponses

Je suggère un template django personnalisé filter plutôt qu'un tag personnalisé -- filter est plus pratique et plus simple (le cas échéant, comme ici). {{ fruits | joinby:", " }} ressemble à ce que je voudrais avoir pour le but... avec un filtre joinby PERSONNALISÉ:

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

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

33
répondu Alex Martelli 2009-08-06 02:41:01

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

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

Voici leur exemple

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

Deuxième choix: faites-le dans la vue.

fruits_text = ", ".join( fruits )

Fournissez fruits_text au modèle pour le rendu.

117
répondu S.Lott 2009-08-06 10:21:02

Voici une solution super simple. Mettez ce code en virgule.html:

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

Et maintenant, où que vous mettiez la virgule, incluez " virgule.html " à la place:

{% for cat in cats %}
Kitty {{cat.name}}{% include "comma.html" %}
{% endfor %}
61
répondu Michael Matthew Toomim 2010-09-07 00:47:35

Sur le modèle Django, tout ce que vous devez faire pour établir une virgule après chaque fruit. La virgule s'arrêtera une fois que son atteint le dernier fruit.

{% if not forloop.last %}, {% endif %}
17
répondu Tommygun 2016-06-02 17:19:19

Voici le filtre que j'ai écrit pour résoudre mon problème:

def join_with_commas(obj_list):
    """Takes a list of objects and returns their unicode representations,
    seperated 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(unicode(obj) for obj in obj_list[:l-1]) \
                + " and " + unicode(obj_list[l-1])

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

6
répondu Alasdair 2015-04-23 06:07:13

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 %}
4
répondu Todd Davies 2013-02-10 14:28:14

Django n'a pas de support pour cela prêt à l'emploi. Vous pouvez définir un filtre personnalisé pour ceci:

from django import template


register = template.Library()


@register.filter
def join_and(value):
    """Given a list of strings, format them with commas and spaces, but
    with 'and' at the end.

    >>> join_and(['apples', 'oranges', 'pears'])
    "apples, oranges, and pears"

    """
    # convert numbers to strings
    value = [str(item) for item in value]

    if len(value) == 1:
        return value[0]

    # join all but the last element
    all_but_last = ", ".join(value[:-1])
    return "%s, and %s" % (all_but_last, value[-1])

Cependant, si vous voulez traiter quelque chose de plus complexe que de simples listes de chaînes, vous devrez utiliser une boucle {% for x in y %} explicite dans votre modèle.

1
répondu Wilfred Hughes 2013-05-29 18:09:03

Si vous aimez les one-liners:

@register.filter
def lineup(ls): return ', '.join(ls[:-1])+' and '+ls[-1] if len(ls)>1 else ls[0]

, puis dans le modèle:

{{ fruits|lineup }}
0
répondu F. Malina 2016-02-20 17:06:48

, je voudrais simplement utiliser ', '.join(['apples', 'oranges', 'pears']) avant de l'envoyer au modèle en tant que données de contexte.

Mise à jour:

data = ['apples', 'oranges', 'pears']
print(', '.join(data[0:-1]) + ' and ' + data[-1])

Vous obtiendrez apples, oranges and pears sortie.

0
répondu Yiğit Genç 2018-07-21 00:27:35