2009-01-19 16 views
57

Las plantillas Django ofrecen la etiqueta integrada cycle para alternar entre varios valores en diferentes puntos de una plantilla (o para el bucle en una plantilla) pero esta etiqueta no se restablece cuando se accede en un ámbito fuera de la definición de cycle s. Es decir, si tiene dos o más listas en su plantilla, las filas de todas las cuales desea usar algunas definiciones de css odd y even, la primera fila de una lista continuará donde la última dejó, no con una nueva iteración de las opciones (odd y even)Color de fila alternativa en Django Plantilla con más de un conjunto de filas

por ejemplo, en el código siguiente, si el primer blog tiene un número impar de entradas, a continuación, la primera entrada en un segundo blog se iniciará tan even, cuando lo quiero a comenzar en odd.

{% for blog in blogs %} 
    {% for entry in blog.entries %} 
    <div class="{% cycle 'odd' 'even' %}" id="{{entry.id}}"> 
     {{entry.text}} 
    </div> 
    {% endfor %} 
{% endfor %} 

He intentado obviar esta colocando un parche con la etiqueta resetcycle ofrecido aquí:

Django ticket: Cycle tag should reset after it steps out of scope

en vano. (El código no funcionó para mí.)

También traté de mover mi lazo interno a una etiqueta personalizada, pero tampoco funcionó, tal vez porque el ciclo de compilación/renderizado mueve el ciclo de regreso al exterior ¿lazo? (Independientemente de por qué, no funcionó para mí.)

¿Cómo puedo lograr esta simple tarea? Preferiría no crear una estructura de datos en mi opinión con esta información precompilada; eso parece innecesario Gracias por adelantado.

Respuesta

109

La solución más sencilla (hasta que el parche se fija resetcycle y aplicada) es utilizar el filtro "divisibleby" integrado con forloop.counter:

{% for entry in blog.entries %} 
    <div class="{% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}" id="{{ entry.id }}"> 
    {{ entry.text }} 
    </div> 
{% endfor %} 

Un poco más detallado, pero no es difícil de entender y funciona genial

+26

También se puede escribir un poco más corto (al menos en Django 1.3): '{{forloop.counter | divisibleby: 2 | yesno:" par, impar "} } ' – Michael

+1

Bonita mejora, Michael!Nunca he usado mucho el filtro yesno, pero creo que tengo un montón de if/elses en mis plantillas que podrían acortarse de esa manera. –

1

La respuesta más fácil podría ser: "renunciar y usar jQuery". Si eso es aceptable, probablemente sea más fácil que pelear con las plantillas de Django por algo tan simple.

+0

Esto es lo que hago, aunque desde que tenía usando jQuery de todos modos, fue bastante trivial. –

2

Dale y utilizar Jinja2 Template System

me di por vencido en el lenguaje de plantillas de Django, es muy limitado en lo que puede hacer con él. Jinja2 utiliza la misma sintaxis que utiliza la plantilla django, pero agrega muchas mejoras sobre ella.

EDITAR/NOTA (ya sé que suena como un gran cambio por sólo una cuestión menor, pero en realidad te apuesto siempre encuentras la lucha contra el sistema de plantillas por defecto en Django, por lo que realmente vale la pena y creo que te hará más productivo a largo plazo.)

Puedes leer this article written by its author, aunque es técnico, menciona el problema de la etiqueta {% cycle%} en django.

Jinja no tiene una etiqueta de ciclo, que tiene un método de ciclo en el bucle:

{% for user in users %} 
    <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li> 
{% endfor %} 

Una ventaja importante de Jinja2 es que permite el uso de la lógica de la presentación, por lo que si usted tiene una lista de las imágenes, se puede poner en una tabla, porque se puede iniciar una nueva fila dentro de una tabla cada N elementos, ver, se puede hacer por ejemplo:

{% if loop.index is divisibleby(5) %} 
    </tr> 
    {% if not loop.last %} 
    <tr> 
    {% endif %} 
{% endif %} 

también puede utilizar expresiones matemáticas:

{% if x > 10 %} 

y se puede acceder a las funciones de Python directamente (pero no se requiere algún tipo de configuración para especificar qué funciones deben ser expuestos para la plantilla)

{% for item in normal_python_function_that_returns_a_query_or_a_list() %} 

las variables incluso fijar ..

{% set variable_name = function_that_returns_an_object_or_something() %} 
+2

Ese es un gran cambio para hacer (con algunas complicaciones importantes, como las aplicaciones de terceros o contrib) para un problema menor. -1 –

+3

Buen punto para que aparezca. El caso es que apuesto a que la gente siempre se encuentra luchando contra el sistema de plantillas de django, no es solo este pequeño problema o ese, es todo un montón de molestias. – hasen

+0

Gracias por su sugerencia y artículo; Me he sentido limitado por el enfoque de Django a las plantillas y molesto por sus errores. Pero Django es dulce en general. –

-5

Hay una forma de hacerlo en el lado del servidor con un iterador que no conserva una copia simultánea de todas las entradas:

import itertools 
return render_to_response('template.html', 
    { 
    "flattened_entries": itertools.chain(*(blog.entries for blog in blogs)), 
    }) 
+0

¿Cómo soluciona esto el problema del OP? Parece que esta es solo otra forma de proporcionar el comportamiento incorrecto (alternando los colores de las filas que no se restablecen entre las publicaciones del blog). -1 –

+0

Tienes razón, entendí su problema en reversa – orip

2

Termino haciéndolo, con el forloop.counter0 - ¡Funciona muy bien!

{% for product in products %} 

    {% if forloop.counter0|divisibleby:4 %}<div class="clear"></div>{% endif %} 

    <div class="product {% if forloop.counter0|divisibleby:4 %}col{% else %}col20{% endif %}"> 
     Lorem Ipsum is simply dummy text 
    </div> 

{% endfor %} 
Cuestiones relacionadas