2011-08-05 15 views
12

Estoy usando django-uniform y para usar algunas características uniformes, estoy buscando una forma de agregar clases css directamente desde la declaración de formulario (para widgets independientes).¿Cómo establecer la clase css de una etiqueta en una declaración de formulario django?

(como un bono, aquí mi reutilizable de sólo lectura hecha en casa fragmento mixin ...)

from django import forms 

def _get_cleaner(form, field): 
    def clean_field(): 
     return getattr(form.instance, field, None) 
    return clean_field 

class UniformROMixin(forms.BaseForm): 
    """ 
    UniformROMixin, inherits to turn some fields read only 

     - read_only = list of field names. 
    """ 

    def __init__(self, *args, **kwargs): 
     super(UniformROMixin, self).__init__(*args, **kwargs) 
     if hasattr(self, "read_only"): 
      if self.instance and self.instance.pk: 
       for field in self.read_only: 
        self.fields[field].widget.attrs['readonly'] = True 
        self.fields[field].widget.attrs['class'] += "readOnly" 
        # here I would like to set css class of the label 
        # created from the self.fields[field].label string 
        setattr(self, "clean_" + field, _get_cleaner(self, field)) 

Mi única manera de que ahora es añadir un poco de javascript en mi plantilla de formulario genérico y agregar clases manual.

¿Alguna idea brillante?

+2

no sé de una manera de agregar una clase CSS en la declaración de la forma, pero he utilizado: http://pypi.python.org/pypi/django-widget-tweaks para agregar convenientemente atributos a cosas como etiquetas de etiqueta y elementos de formulario en el nivel de plantilla cuando tiene sentido hacerlo. – Brandon

+0

Gracias por la sugerencia. En mi caso, no manejo la parte de la plantilla completamente hecha por django-uniform. Aún puedo ver cómo funciona el método "renderizado" del widget y anularlo ... – christophe31

Respuesta

3

me encontré con este fragmento que puede ser una buena respuesta:

How to add css class and "*" to required fields's labels

aquí una adaptación a mis necesidades (no determinado todavía, voy a editar el cargo una vez hecho):

from django.utils.html import escape 

def readonly_cssclass_adder(bound_field, label_content, label_attrs): 
    if 'readonly' in bound_field.field.widget.attrs: 
     if 'class' in attrs: 
      label_attrs['class'] += " readOnly" 
     else: 
      label_attrs['class'] = "readOnly" 
    return label_content, label_attrs 


def add_required_label_tag(original_function, tweak_foos=None): 
    if not tweak_foos: 
     return original_function 

    def required_label_tag(self, contents=None, attrs=None): 
     contents = contents or escape(self.label) 
     if attrs is None: 
      attrs = {} 
     for foo in tweak_foos: 
      contents, attrs = foo(self, contents, attrs) 
     return original_function(self, contents, attrs) 
    return required_label_tag 

def decorate_bound_field(): 
    from django.forms.forms import BoundField 
    BoundField.label_tag = add_required_label_tag(BoundField.label_tag, 
              tweak_foos=[readonly_cssclass_adder]) 

Si tiene una mejor solución que no modifique toda la clase BoundField, todavía estoy escuchando.

editar: pueden estar vinculados a la forma uniforme de django para manejar el campo requerido pero parece que no se llama al readonly_cssclass_adder. Pero me encontré con otro y más facil solución, mi aparato readOnly activa automáticamente readOnly ctrlHolder

Esta adición es mi respuesta favorita por ahora:

editar 2: La otra forma elijo al final fue a "anular" la uni_form/field.html plantilla que no llama a BoundField.label_tag. Así que revisé aquí el estado del campo.

<label for="{{ field.auto_id }}"{% if field.field.required %} 
     class="requiredField{% if field.widget.attrs.readonly %} readOnlyLabel{% endif %}" 
     {% else %}{% if field.widget.attrs.readonly %}class="readOnlyLabel"{% endif %}{% endif %}> 
    {{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %} 
</label> 
18

Reproductores tienen un argumento attrs palabra clave que tomar una dict que puede definir atributos para el elemento de entrada que hace. Los formularios también tienen algunos atributos que puede definir para cambiar la forma en que Django muestra su formulario. Tomemos el siguiente ejemplo:

class MyForm(forms.Form): 
    error_css_class = 'error' 
    required_css_class = 'required' 
    my_field = forms.CharField(max_length=10, 
           widget=forms.TextInput(attrs={'id': 'my_field', 
                  'class': 'my_class'})) 

Esto funciona en cualquier clase Widget. Desafortunadamente, no hay una manera fácil de cambiar la forma en que Django hace etiquetas si solo hace {{ field }}. Por suerte, se juega con la forma objetar un poco en la plantilla:

<form> 
    {% for field in form %} 
     <label class="my_class" for="{{ field.name }}">{{ field.label }}</label> 
     {{ field }} 
    {% endfor %} 
    <button type="submit">Submit</button> 
</form> 

Por otra parte, siempre se puede añadir atributos arbitrarios a los objetos con los que trabaja:

# In a view... 
form = MyForm() 
form.label_classes = ('class_a', 'class_b',) 
# Or by hijacking ```__init__``` 
class MyForm(forms.Form): 
    def __init__(self, *args, **kwargs): 
     self.my_field = forms.CharField(max_length=10, 
             widget=forms.TextInput(attrs={'id': 'my_field', 
                     'class': 'my_class'})) 
     self.my_field.label_classes = ('class_a', 'class_b',) 
     super(MyForm, self).__init__(*args, **kwargs) 

Render su plantilla con el formulario en contexto, y en la plantilla puede hacer:

<form> 
    {% for field in form %} 
     <label class="{% for class in field.label_classes %}{{ class }} {% endfor %}" 
       for="{{ field.name }}">{{ field.label }}</label> 
     {{ field }} 
    {% endfor %} 
    <button type="submit">Submit</button> 
</form> 

Lo que más le guste.

+0

¡Excelente solución! La primera línea para aquellos que intentan usarla debe ser '{% for field in form.myfield%}' – WayBehind

+0

Los objetos 'Field' no son iterables – xj9

+0

@ xj9: ¿Cómo funcionaría esto en ModeForm? Cuando accedo a él como self.field arroja un error, cuando agrego un atributo a self.fields [field] no aparece ... – Stefan

0

opción un poco personalizada en base a la solución @ XJ9 utilizado con el campo ManyToMany y Bootstrap .checkbox-inline. Funciona igual para el botón de opción con .radio-inline.

formulario.py

class MyForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(MyForm, self).__init__(*args, **kwargs) 

self.fields['m2mfield'] = forms.ModelMultipleChoiceField(
           queryset=Model.objects.all().order_by('name'), 
           required=True, 
           widget=forms.CheckboxSelectMultiple()) 

template.html

<div class="col-sm-9"> 
{% for field in form.m2mfield %} 
    <label class="checkbox-inline" for="{{ field.name }}">{{ field.label }}</label> 
    {{ field }} 
{% endfor %} 
</div> 
Cuestiones relacionadas