2009-08-06 16 views
54

Si fruits es la lista ['apples', 'oranges', 'pears'],separados por comas listas de plantillas de Django

hay una manera rápida usando etiquetas de plantilla de Django para producir "manzanas, naranjas y peras"?

Yo sé que no es difícil de hacer esto usando un bucle y {% if counter.last %} declaraciones, sino porque voy a usar esto en varias ocasiones creo que voy a tener que aprender a escribir de encargo etiquetas filtros, y yo no quiero reinventar la rueda si ya está hecho.

Como una extensión, mis intentos de dejar caer el Oxford Comma (es decir, devolver "manzanas, naranjas y peras") son aún más desordenados.

+2

¿Por qué no utiliza la etiqueta de plantilla de unión existente? –

+1

@ S.Lott: No identifiqué la etiqueta de plantilla de unión cuando revisé la lista en la página de documentos. Oops. Habiendo dicho eso, la próxima etapa es envolver cada elemento de la lista en un hipervínculo, para lo cual creo que tendré que escribir un filtro. – Alasdair

+0

Si usa enlaces a las URL de Django, deberá usar la etiqueta '{% url%}'. El bucle '{% for%}' de repente parece mucho más atractivo. "Repetidamente" a menudo significa que sus plantillas necesitan '{% include%}' características comunes. –

Respuesta

30

que sugeriría un encargo de plantillas Django filtro en lugar de una costumbre etiqueta - filtro es más práctico y más simple (en su caso, al igual que aquí). {{ fruits | joinby:", " }} se parece a lo que yo quiero tener el propósito ... con un filtro personalizado joinby:

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

que como se ve es la simplicidad misma!

+0

No conocía la distinción entre etiquetas y filtros. Mientras que las etiquetas personalizadas parecen algo desalentadoras cuando miro la documentación, los filtros parecen ser más simples, y exactamente lo que necesito en este caso. ¡Gracias! – Alasdair

+5

Esto no inserta el "y" final. – Meekohi

+1

@Meekohi, entonces 'return arg.join (value [: - 1]) + 'y' + value [-1]' (para el estilo AP, es decir, sin coma antes de 'y'; para el estilo" Oxford coma ", agrega un '+ arg' justo antes del' + 'y''). Yo, prefiero la fuerza del asyndeton, por http://literarydevices.net/asyndeton/. Y ninguno de estos finos debates sobre el estilo inglés pertenece a StackOverflow de todos modos, llévalo a english.stackexchange.com! -) –

111

Primera opción: utilice la etiqueta de plantilla de unión existente.

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

Aquí es su ejemplo

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

segunda opción: hacerlo en la vista.

fruits_text = ", ".join(fruits) 

Proporcionar fruits_text a la plantilla para la representación.

+0

Podría necesitar otras listas (por ejemplo, 'vegetables_text'), y puedo usar estas listas en muchas vistas, así que preferiría tener una solución que solo requiera que modifique las plantillas. Una de las razones por las que estaba pensando en escribir una etiqueta personalizada es que puedo usar Python: 'join' es definitivamente más elegante que para bucles. – Alasdair

+4

Esto tampoco inserta el "y" final. – Meekohi

+0

¿Existe alguna mejor práctica para hacer esto en la plantilla o en la vista? – Rikki

6

Aquí es el filtro que escribí para resolver mi problema:

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

para usarlo en la plantilla: {{ fruits | join_with_commas }}

59

Aquí es una solución muy sencilla. Pon este código en comma.html:

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

Y ahora donde quiera que había puesto la coma, incluye "comma.html" en vez: ''

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

Muy útil. ¡Gracias! –

+3

la mejor solución si necesita unir más que las cadenas en una matriz – BiAiB

+0

Solución muy inteligente. – vmassuchetto

4

Si desea una en el extremo de la respuesta de Michael Mateo Toomim, a continuación, utilizar:

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

Django no tiene soporte para este fuera de la caja. Se puede definir un filtro personalizado para esto:

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

Sin embargo, si usted quiere tratar con algo más complejo que sólo listas de cadenas, que tendrá que utilizar un bucle explícito {% for x in y %} en su plantilla.

0

Si te gusta de una sola línea:

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

y luego en la plantilla:

{{ fruits|lineup }} 
13

en la plantilla de Django esto todo lo que necesita hacer para el establecimiento de una coma después de cada fruta. La coma se detendrá una vez que haya alcanzado la última fruta.

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

Solución muy limpia y fácil. – SaeX

Cuestiones relacionadas