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.
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!
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.
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 %}
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 %}
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 }}
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 %}
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.
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 }}
, 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.