2009-08-06 10 views
54

Wenn fruits die Liste ['apples', 'oranges', 'pears'],durch Kommata getrennte Listen in django Vorlagen

ist es eine schnelle Möglichkeit django Template-Tags verwenden, um „Äpfel, Orangen und Birnen“?

Ich weiß es nicht schwierig ist, dies zu tun, eine Schleife und {% if counter.last %}-Anweisungen, sondern weil ich werde dies verwenden, immer wieder denke ich, ich werde lernen müssen, wie Filter benutzerdefinierten -Tags zu schreiben, und ich Ich will das Rad nicht neu erfinden, wenn es schon fertig ist.

Als eine Erweiterung sind meine Versuche, die Oxford Comma (dh Rückkehr "Äpfel, Orangen und Birnen") fallen noch unordentlicher.

+2

Warum verwenden Sie nicht das vorhandene Join Template-Tag? –

+1

@ S.Lott: Ich habe das Join Template-Tag nicht gefunden, als ich die Liste auf der Dokumentseite durchgesehen habe. Hoppla. Nachdem das gesagt ist, besteht die nächste Stufe darin, jedes Element in der Liste in einen Hyperlink einzubinden, für den ich denke, dass ich einen Filter schreiben muss. – Alasdair

+0

Wenn Sie Links zu Ihren Django-URLs verwenden, müssen Sie das Tag '{% url%}' verwenden. Die '{% for%}' - Schleife sieht plötzlich viel ansprechender aus. "Wiederholt" bedeutet häufig, dass Ihre Vorlagen "gemeinsame Eigenschaften" enthalten müssen. –

Antwort

30

würde ich einen benutzerdefinierte django Templating Filter eher als ein benutzerdefinierter Tag vorschlagen - Filter sind handlicher und einfacher (geeignet, wenn, wie hier). {{ fruits | joinby:", " }} sieht aus wie, was ich für den Zweck haben wollen würde ... mit einem benutzerdefinierten joinby Filter:

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

die, wie Sie sehen, ist selbst Einfachheit!

+0

Mir war der Unterschied zwischen Tags und Filtern nicht bewusst. Während die benutzerdefinierten Tags beim Betrachten der Dokumentation etwas entmutigend wirken, scheinen Filter einfacher zu sein und genau das, was ich in diesem Fall brauche. Vielen Dank! – Alasdair

+5

Dies fügt nicht das abschließende "und" ein. – Meekohi

+1

@Meekohi, also 'return arg.join (Wert [: - 1]) + 'und' + Wert [-1]' (für AP Stil, dh kein Komma vor 'und'; für "Oxford Komma" Stil, füge ein '+ arg' vor dem' + 'und' 'hinzu. Ich bevorzuge die Stärke des Asyndetons per http://literarydevices.net/asyndeton/. Und nichts von dieser feinen Debatte über englischen Stil gehört sowieso zu StackOverflow - nehmen Sie es auf Englisch.stackexchange.com! -) –

111

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

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

Hier ist ihr Beispiel

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

Zweite Wahl: tun es in der Ansicht.

fruits_text = ", ".join(fruits) 

fruits_text der Vorlage Geben Sie für das Rendering.

+0

Ich könnte andere Listen (zB 'vegetables_text') verlangen, und ich kann diese Listen in vielen Ansichten verwenden, also würde ich lieber eine Lösung haben, die nur erfordert, dass ich die Vorlagen ändere. Einer der Gründe, warum ich darüber nachdachte, ein benutzerdefiniertes Tag zu schreiben, ist, dass ich Python verwenden kann - "Join" ist definitiv eleganter als For-Loops. – Alasdair

+4

Dies fügt auch nicht das abschließende "und" ein. – Meekohi

+0

Gibt es eine Best Practice, ob dies in der Vorlage oder in der Ansicht zu tun ist? – Rikki

6

Hier ist der Filter schrieb ich mein Problem zu lösen:

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]) 

Um es in der Vorlage zu verwenden: {{ fruits | join_with_commas }}

59

Hier ist eine super einfache Lösung. Setzen Sie diesen Code in comma.html:

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

Und jetzt, wo Sie das Komma setzen würde, umfassen "comma.html" statt: ''

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

Sehr nützlich. Vielen Dank! –

+3

die beste Lösung, wenn Sie mehr als die Zeichenfolgen in einem Array verbinden müssen – BiAiB

+0

Sehr clevere Lösung. – vmassuchetto

4

Wenn Sie ein möchten am Ende von Michael Matthew Toomim Antwort, dann verwenden:

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

Django keine Unterstützung für diese Out-of-the-box haben. Sie können einen benutzerdefinierten Filter für diese 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 mit etwas komplexer als nur Listen von Zeichenketten behandeln wollen, müssen Sie eine explizite {% for x in y %} Schleife in Ihrer Vorlage verwenden.

0

Wenn Sie Einzeiler:

@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 }} 
13

Auf der Django-Vorlage dies alles, was Sie für die Einrichtung ein Komma nach jeder Frucht tun müssen. Das Komma stoppt, sobald es die letzte Frucht erreicht hat.

{% if not forloop.last %}, {% endif %} 
+1

Sehr saubere und einfache Lösung. – SaeX

Verwandte Themen