wake-up-neo.net

Kommagetrennte Listen in Django-Vorlagen

Wenn fruits die Liste ['apples', 'oranges', 'pears'] ist,

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 Sitte schreibt stichworte Filter, und ich möchte das Rad nicht neu erfinden, wenn es bereits gemacht wurde.

Als Erweiterung sind meine Versuche, das Oxford Comma (dh "Äpfel, Orangen und Birnen") zurückzugeben, noch unübersichtlicher.

60
Alasdair

Hier ist der Filter, den ich geschrieben habe, um mein Problem zu lösen (er enthält nicht das 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 }}

7
Alasdair

Erste Wahl: Verwenden Sie das vorhandene Join-Vorlagen-Tag.

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

Hier ist ihr Beispiel

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

Zweite Wahl: Machen Sie es in der Ansicht.

fruits_text = ", ".join( fruits )

Geben Sie der Vorlage fruits_text zum Rendern an.

124
S.Lott

Hier ist eine super einfache Lösung. Geben 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 einsetzen würden, fügen Sie stattdessen "comma.html" ein:

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

Ich würde vorschlagen, dass ein benutzerdefiniertes Django-Template filter verwendet wird, anstatt dass ein benutzerdefiniertes tag - filter einfacher und einfacher ist (gegebenenfalls wie hier). {{ fruits | joinby:", " }} sieht aus wie das, was ich zu diesem Zweck haben möchte ... mit einem benutzerdefinierten joinby-Filter:

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

wie Sie sehen, ist die Einfachheit selbst!

33
Alex Martelli

Auf der Django-Vorlage müssen Sie nach jeder Frucht ein Komma festlegen. Das Komma hört auf, sobald es die letzte Frucht erreicht hat.

{% if not forloop.last %}, {% endif %}
18
Tommygun

Wenn Sie ein "." Am Ende der Antwort von Michael Matthew Toomim verwenden Sie dann:

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

Alle Antworten hier schlagen eine oder mehrere der folgenden Antworten fehl:

  • Sie schreiben etwas (schlecht!) Um, das in der Standardvorlagenbibliothek enthalten ist (ack, beste Antwort!)
  • Sie verwenden nicht and für den letzten Eintrag.
  • Ihnen fehlt ein serielles (Oxford) Komma.
  • Sie verwenden negative Indexierung, was für Django-Querysets nicht funktioniert.
  • Sie behandeln die Saitenhygiene normalerweise nicht richtig.

Hier ist mein Einstieg in diese Canon. Zuerst 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 es nicht negative Indexierung verwendet:

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:

{% load my_filters %}
{{ items|oxford_comma }}
2
mlissner

Django hat keine Unterstützung für dieses Out-of-the-Box. Sie können dafü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 jedoch etwas komplexeres als nur Listen von Strings behandeln möchten, müssen Sie eine explizite {% for x in y %}-Schleife in Ihrer Vorlage verwenden.

1
Wilfred Hughes

Ich würde einfach ', '.join(['apples', 'oranges', 'pears']) verwenden, bevor ich es als Kontextdaten an die Vorlage schicke.

AKTUALISIEREN:

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

Sie erhalten apples, oranges and pears Ausgabe.

0
Yiğit Genç

Wenn Sie Einliner 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:

{{ fruits|lineup }}
0
F. Malina