Wenn fruits
ist die Liste ['apples', 'oranges', 'pears']
,
Gibt es eine schnelle Möglichkeit, mit Django-Vorlagen-Tags "Äpfel, Orangen und Birnen" herzustellen?
Ich weiß, dass es nicht schwierig ist, dies mit einer Schleife und {% if counter.last %}
Anweisungen zu tun , aber da ich dies wiederholt verwenden werde, denke ich, dass ich lernen muss, wie man benutzerdefinierte Anweisungen schreibtStichworte Filter, und ich möchte das Rad nicht neu erfinden, wenn es bereits getan wurde.
Als Erweiterung sind meine Versuche, das Oxford-Komma fallen zu lassen (dh "Äpfel, Orangen und Birnen" zurückzugeben), noch chaotischer.
python
django
list
django-templates
Alasdair
quelle
quelle
{% url %}
Tag verwenden. Die{% for %}
Schleife sieht plötzlich viel ansprechender aus. "Wiederholt" bedeutet häufig, dass Ihre Vorlagen{% include %}
gemeinsame Funktionen benötigen .Antworten:
Erste Wahl: Verwenden Sie das vorhandene Tag für Verknüpfungsvorlagen.
http://docs.djangoproject.com/de/dev/ref/templates/builtins/#join
Hier ist ihr Beispiel
{{ value|join:" // " }}
Zweite Wahl: Mach es in der Ansicht.
fruits_text = ", ".join( fruits )
Stellen Sie
fruits_text
die Vorlage zum Rendern bereit.quelle
vegetables_text
) und verwende diese Listen möglicherweise in vielen Ansichten. Daher hätte ich lieber eine Lösung, bei der ich nur die Vorlagen ändern muss. Einer der Gründe, warum ich über das Schreiben eines benutzerdefinierten Tags nachgedacht habe, ist, dass ich Python verwenden kann - esjoin
ist definitiv eleganter als für Schleifen.Hier ist eine super einfache Lösung. Fügen Sie diesen Code in comma.html ein:
{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}
Und jetzt, wo immer Sie das Komma setzen würden, fügen Sie stattdessen "comma.html" hinzu:
{% for cat in cats %} Kitty {{cat.name}}{% include "comma.html" %} {% endfor %}
Update: @ user3748764 gibt uns eine etwas kompaktere Version ohne die veraltete ifequal-Syntax:
{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}
Beachten Sie, dass es vor dem Element und nicht nach dem Element verwendet werden sollte.
quelle
and
durch, and
.{% if not forloop.first %}{% if forloop.last %} and {% else %}, {% endif %}{% endif %}
Beachten Sie, dass es vor dem Element und nicht nach dem Element verwendet werden sollte.Ich würde eine benutzerdefinierte vorschlagen django Templating Filter anstelle eines benutzerdefinierten Tag - Filter ist handlicher und einfacher (gegebenenfalls wie hier).
{{ fruits | joinby:", " }}
sieht aus wie das, was ich für diesen Zweck haben möchte ... mit einem benutzerdefiniertenjoinby
Filter:def joinby(value, arg): return arg.join(value)
Was, wie Sie sehen, die Einfachheit selbst ist!
quelle
return arg.join(value[:-1]) + ' and ' + value[-1]
(für den AP-Stil, dh kein Komma zuvorand
; für den "Oxford-Komma" -Stil ein+ arg
Recht vor dem "+" und "" hinzufügen). Ich bevorzuge die Stärke des Asyndetons pro literarisches Gerät.net / asyndeton . Und keine dieser schönen Debatten über den englischen Stil gehört sowieso zu StackOverflow - bringen Sie es zu english.stackexchange.com! -)'and'
sind im obigen Kommentar zum bedingungslosen Einfügen codiert'and'
. Alles, was man braucht, um sich für kurze Zeit anders zu verhalten,value
ist Code[[as above] if len(value)>1 else value
. Übrigens ist Asyndeton sehr gut lesbar - Aristoteles, Shakespeare, Joyce (natürlich unter vielen anderen) haben es alle effektiv genutzt, und meine Vorliebe dafür beruht in erster Linie darauf, dass ich Dichter bin.Auf der Django-Vorlage ist dies alles, was Sie tun müssen, um nach jeder Frucht ein Komma zu setzen. Das Komma hört auf, sobald es die letzte Frucht erreicht hat.
{% if not forloop.last %}, {% endif %}
quelle
Hier ist der Filter, den ich geschrieben habe, um mein Problem zu lösen (er enthält kein Oxford-Komma).
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])
So verwenden Sie es in der Vorlage:
{{ fruits|join_with_commas }}
quelle
Wenn Sie ein '.' Verwenden Sie am Ende der Antwort von Michael Matthew Toomim:
{% if not forloop.last %}{% ifequal forloop.revcounter 2 %} and {% else %}, {% endifequal %}{% else %}{% endif %}{% if forloop.last %}.{% endif %}
quelle
Alle Antworten hier schlagen eine oder mehrere der folgenden fehl:
and
für den letzten Artikel verwendet.Hier ist mein Eintrag in diesen Kanon. Zunächst die Tests:
class TestTextFilters(TestCase): def test_oxford_zero_items(self): self.assertEqual(oxford_comma([]), '') def test_oxford_one_item(self): self.assertEqual(oxford_comma(['a']), 'a') def test_oxford_two_items(self): self.assertEqual(oxford_comma(['a', 'b']), 'a and b') def test_oxford_three_items(self): self.assertEqual(oxford_comma(['a', 'b', 'c']), 'a, b, and c')
Und jetzt der Code. Ja, es wird ein bisschen chaotisch, aber Sie werden sehen, dass keine negative Indizierung verwendet wird:
from django.utils.encoding import force_text from django.utils.html import conditional_escape from django.utils.safestring import mark_safe @register.filter(is_safe=True, needs_autoescape=True) def oxford_comma(l, autoescape=True): """Join together items in a list, separating them with commas or ', and'""" l = map(force_text, l) if autoescape: l = map(conditional_escape, l) num_items = len(l) if num_items == 0: s = '' elif num_items == 1: s = l[0] elif num_items == 2: s = l[0] + ' and ' + l[1] elif num_items > 2: for i, item in enumerate(l): if i == 0: # First item s = item elif i == (num_items - 1): # Last item. s += ', and ' + item else: # Items in the middle s += ', ' + item return mark_safe(s)
Sie können dies in einer Django-Vorlage verwenden mit:
quelle
Ich würde es einfach verwenden,
', '.join(['apples', 'oranges', 'pears'])
bevor ich es als Kontextdaten an die Vorlage sende.AKTUALISIEREN:
data = ['apples', 'oranges', 'pears'] print(', '.join(data[0:-1]) + ' and ' + data[-1])
Sie erhalten eine
apples, oranges and pears
Ausgabe.quelle
"apples, oranges, pears"
. Die erforderliche Ausgabe ist"apples, oranges, and pears"
.Django hat keine Unterstützung für diesen Out-of-the-Box. Sie können hierfür einen benutzerdefinierten Filter definieren:
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])
Wenn Sie sich jedoch mit etwas Komplexerem als nur Listen von Zeichenfolgen befassen möchten, müssen Sie
{% for x in y %}
in Ihrer Vorlage eine explizite Schleife verwenden.quelle
Wenn Sie Einzeiler mögen:
@register.filter def lineup(ls): return ', '.join(ls[:-1])+' and '+ls[-1] if len(ls)>1 else ls[0]
und dann in der Vorlage:
quelle
Ich denke, die einfachste Lösung könnte sein:
@register.filter def comma_list(p_values: Iterable[str]) -> List[str]: values = list(p_values) if len(values) > 1: values[-1] = u'and %s' % values[-1] if len(values) > 2: return u', '.join(values) return u' '.join(values)
quelle