2010-11-08 8 views
32

Estoy sacando campos de un formulario en una plantilla como esta {{ form.first_name }} y me gustaría agregar una clase (por ejemplo, blueprint span-x -class) lo. Entonces, me gustaría saber si hay una buena solución preparada (filtro de plantilla) para eso, que podría usar de la manera {{ form.first_name|add_class:"span-4" }}? (Solo quiero saber si los desarrolladores de Django o alguien lo ha pensado sin antes haberlo hecho solo)Django: Agregar clases CSS al representar campos de formulario en una plantilla

Respuesta

22

Para resolver esto hice mi propio filtro de plantilla, puede aplicarlo en cualquier etiqueta, ¡no solo en los elementos de entrada!

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') 
@register.filter 
def add_class(value, css_class): 
    string = unicode(value) 
    match = class_re.search(string) 
    if match: 
     m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                css_class, css_class), 
                match.group(1)) 
     print match.group(1) 
     if not m: 
      return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
              string)) 
    else: 
     return mark_safe(string.replace('>', ' class="%s">' % css_class)) 
    return value 
+2

Muy bien hecho. Para hacer que funcione para los campos que terminan con '/>', he usado 'return mark_safe (string.replace ('', 'class ="% s "'% css_class))' - usé un espacio en lugar de '>' para que encuentre el primer espacio e inyecte el atributo antes que el resto. – abstractpaper

+0

La expresión regular coincide con la codicia, pero debe coincidir con la pereza. He alterado el código anterior a '' class_re = re.compile (r '(? <= Class = ["\']) (. *?) (? = [" \ '])') ''. De lo contrario, coincide con el último '' "' char en lugar del final de la clase. –

0

Debe especificar el widget explícitamente y agregar la clase usando el attrs keyword argument. No hay otra manera que yo sepa.

Sin embargo, si esto es demasiado engorroso, igual podría envolver el campo en otro elemento, como div o span, y agregar una clase a eso. Luego modifique su CSS en consecuencia.

+1

Como ya he mencionado:

@register.filter def add_class(field, class_name): return field.as_widget(attrs={ "class": " ".join((field.css_classes(), class_name)) }) 

Y en su plantilla me gustaría hacerlo en la plantilla, porque la forma se puede representar en varias apariencias. –

+1

Para obtener resultados optimizados, debería considerar leer sobre diseños receptivos. Tus plantillas y clases no se modificarán y toda la magia permanecerá en CSS. –

5

Todavía estoy aprendiendo Django, pero ¿no podría hacer esto algo como esto -

from django import forms 

class SomeForm(forms.Form): 
    f = forms.CharField(label='x',widget=forms.TextInput(attrs={'class':'name'})) 

supongo que no hay necesidad de hacer esto en el nivel de plantilla (o usar filtros) a menos que tenga alguna requisito que no entendí

+2

Es mucho más limpio separar el estilo (css) de la funcionalidad (el formulario). Por ejemplo, ¿cómo se agrega condicionalmente una clase a un campo de formulario en la plantilla que usa este método? Además, ¿cómo muestra este formulario de formas diferentes sin duplicar el formulario, como un formulario amigable para dispositivos móviles y un formulario no tan amigable para dispositivos móviles? La validación proporcionada por el formulario no cambia, pero la vista sí lo hace. – varikin

+1

La clase de CSS aplicada al nivel de formulario no afecta a las diferentes pantallas. La clase de formulario debe permanecer igual en cualquier dispositivo y debe tener una configuración de archivo CSS específica especializada por dispositivo, cuando sea necesario. –

+0

Esta es la respuesta correcta, para la mayoría de los casos de todos modos. ¡No hay necesidad de perder el tiempo con expresiones regulares! Tal vez también mencione el caso de ModelForm: 'clase Meta: widgets = {'f': forms.TextInput (attrs = {'clase': 'nombre'})}' – frnhr

12

Algunas notas extra sobre cómo ponerse en marcha con la muy práctica solución de Lazerscience. Así es como se ve el archivo con las importaciones de dependencia:

import re 
from django.utils.safestring import mark_safe 
from django import template 
register = template.Library() 

class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])') 
@register.filter 
def add_class(value, css_class): 
    string = unicode(value) 
    match = class_re.search(string) 
    if match: 
     m = re.search(r'^%s$|^%s\s|\s%s\s|\s%s$' % (css_class, css_class, 
                css_class, css_class), 
                match.group(1)) 
     print match.group(1) 
     if not m: 
      return mark_safe(class_re.sub(match.group(1) + " " + css_class, 
              string)) 
    else: 
     return mark_safe(string.replace('>', ' class="%s">' % css_class)) 
    return value 

Pegué esto en un archivo llamado add_class.py. La estructura del directorio es: mydjangoproject> general_tools_app> templatetags> add_class.py

general_tools_app es una aplicación que recopila funcionalidades útiles como esta que agrego a nuevos proyectos django.

(Los general_tools_app y templatetags directorios tanto tener un archivo vacío __init__.py para que se registren correctamente)

En settings.py, mi INSTALLED_APPS tupla incluye la entrada 'mydjangoproject.general_tools_app'.

Para usar el filtro en una plantilla, agrego la línea {% load add_class %} en la parte superior del archivo. Si quiero agregar la clase de 'eliminar' a un campo, lo haría esta

{{ myfield|add_class:'delete' }} 
+1

Encontré la definición 'class_re' demasiado codiciosa, y terminé en algunos campos que la clase se ingresaba en el atributo' type' en lugar de 'class'. Mi versión revisada:' class_re = re.compile (r '(? <= class = ["\']) ([^" \ '] *) (["\']) ') – DanH

3

Una nota más en la solución de lazerscience: si se aplica esto a un <selecciono> elemento sin atributo de clase, la cadena reemplazan en el caso más podría producir algo como esto:

<select name="state" id="id_state" class="class1 class2"> 
    <option value="AL" class="class1 class2">Alabama</option class="class1 class2"> 
    <option value="AK" class="class1 class2">Alaska</option class="class1 class2"> 
    <option value="AZ" class="class1 class2">Arizona</option class="class1 class2"> 
</select class="class1 class2"> 

estoy bastante seguro de los navegadores chatarra esas definiciones de clase de extraños, pero eso es un montón de cadena reemplaza cuando sólo se necesita uno. Un remedio fácil para esto:

return mark_safe(string.replace('>', ' class="%s">' % css_class, 1)) 

Ese último argumento (1) se asegurará de que sólo la primera instancia de ">" será reemplazado por "class =" ... ">, que es lógicamente correcto para cualquier elemento de forma.

+0

Hola , gracias por la inspiración, ¡supongo que nunca lo he usado con un 'select'! –

46

Sólo es necesario instalar Django widget_tweaks

pip install django-widget-tweaks 

Después se puede hacer algo así en su plantilla:

{{ form.search_query|attr:"type:search" }} 

-

Leer todo sobre ella here.

+1

Estaba buscando cómo agregar clases a 'labels', recuerdo que es sencillo agregarlas manualmente:' ' –

9

Otra forma es utilizar el método as_widget en un campo para modificarlo, más simple y más seguro que el enfoque de expresión regular, y no requiere ninguna dependencia adicional.

Definir un custom template filter: Me

{{ form.first_name|add_class:"span-4" }} 

También puede utilizar as_widget añadir otros atributos, como placeholder, etc.

+0

bastante simple y funciona – Bwire

+0

Me encanta esta solución elegante, además de que ahora aprendí a usar etiquetas de plantilla. ¡Gracias! – Matt

Cuestiones relacionadas