widgets formularios form fields example avanzados python django forms newforms

python - formularios - Agregar clase a Django label_tag() salida



formularios django (7)

Necesito alguna manera de agregar un atributo de clase al resultado del método label_tag () para un campo de formularios.

Veo que existe la capacidad de pasar en un diccionario attrs y lo he probado en el shell y puedo hacer algo como:

for field in form: print field.label_tag(attrs{''class'':''Foo''})

Veré la clase = ''Foo'' en mi salida, pero no veo una manera de agregar un argumento attrs desde la plantilla; de hecho, las plantillas están diseñadas específicamente contra eso, ¿no?

¿Hay alguna forma en la definición de mi formulario para definir la clase que se mostrará en la etiqueta?

En la forma, puedo hacer lo siguiente para dar una clase a las entradas

self.fields[''some_field''].widget.attrs[''class''] = ''Foo''

Solo necesito que produzca la clase para el también.


¿Qué le parece agregar la clase CSS al campo de formulario en forms.py, como:

class MyForm(forms.Form): title = forms.CharField(widget=forms.TextInput(attrs={''class'': ''foo''}))

entonces solo hago lo siguiente en la plantilla:

<label for="id_{{form.title.name}}" class="bar"> {{ form.title }} </label>

Por supuesto, esto puede modificarse fácilmente para que funcione dentro de una etiqueta for loop en la plantilla.


Estoy de acuerdo con la respuesta número uno, con css esto podría hacerse, pero. ¿Cuál es la resonancia de esto en la fuente django?

En django.forms.forms.py existe esta definición que muestra que hay código para mostrar attrs en las etiquetas:

class BoundField(StrAndUnicode): # .... def label_tag(self, contents=None, attrs=None): contents = u''<label for="%s"%s>%s</label>'' % (widget.id_for_label(id_), attrs, unicode(contents))

pero _html_output llama a esta función sin atributos:

label = bf.label_tag(label) or ''''

Parece que django está parcialmente preparado para esto, pero en realidad no lo usa.


Un poco tarde pero encontré un problema similar. Espero que esto te ayude.

class MyForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(MyForm, self).__init__(*args, **kwargs) self.fields[''myfield1''].widget.attrs.update( {''class'': ''form-control''}) self.fields[''myfield2''].widget.attrs.update( {''class'': ''form-control''}) def as_two_col_layout(self): return self._html_output( normal_row=''<div class="form-group"><span class="col-xs-2">%(label)s</span> <div class="col-xs-10">%(field)s%(help_text)s</div></div>'', error_row=''%s'', row_ender=''</div>'', help_text_html='' <span class="helptext">%s</span>'', errors_on_separate_row=True) class Meta: model = mymodel fields = [''myfield1'', ''myfield2'']


Una etiqueta de plantilla personalizada parece ser la solución. Un filtro personalizado también lo haría, aunque puede ser menos elegante. Pero tendría que recurrir a la representación de formularios personalizados en ambos casos.

Si esta es una tarea de gran importancia; Crearía un Mixin que me permite anotar los campos de formulario con clases de etiqueta y los suministros de los métodos de representación utilizando esas clases. Para que funcione el siguiente código:

{{ form.as_table_with_label_classes }}

Pero me gustaría preguntar; ¿Realmente necesitas una clase en la etiqueta? Me refiero a HTML en cuanto al diseño. Es absolutamente necesario agregar una clase allí? No podría ser resuelto con algunos CSS como:

encapsulating_selector label { some-attr: some-value; }

A veces uso jQuery para casos como este; mejorará la página si funciona, pero no será un desastre si no funciona . Y mantenga la fuente HTML lo más ajustada posible.


Técnica 1

No estoy de acuerdo con la afirmación de otra respuesta de que un filtro sería "menos elegante". Como puedes ver, es muy elegante.

@register.filter(is_safe=True) def label_with_classes(value, arg): return value.label_tag(attrs={''class'': arg})

Usar esto en una plantilla es igual de elegante:

{{ form.my_field|label_with_classes:"class1 class2"}}

Técnica 2

Alternativamente, una de las técnicas más interesantes que he encontrado es: Agregar * a los campos obligatorios .

Usted crea un decorador para BoundField.label_tag que lo llamará con attrs establecidos apropiadamente. A continuación, conectó el parche BoundField para que llamar a BoundField.label_tag llame a la función decorada.

from django.forms.forms import BoundField def add_control_label(f): def control_label_tag(self, contents=None, attrs=None): if attrs is None: attrs = {} attrs[''class''] = ''control-label'' return f(self, contents, attrs) return control_label_tag BoundField.label_tag = add_control_label(BoundField.label_tag)


@register.simple_tag def advanced_label_tag(field): """ Return form field label html marked to fill by `*` """ classes = [] attrs = {} contents = force_unicode(escape(field.label)) if field.field.required: classes.append(u''required'') contents = force_unicode(''%s <span>*</span>''%escape(field.label)) if classes: attrs[''class''] = u'' ''.join(classes) return field.label_tag(contents=contents, attrs=attrs)


class CustomBoundField(BoundField): def label_tag(self, contents=None, attrs=None): if self.field.required: attrs = {''class'': ''required''} return super(CustomBoundField, self).label_tag(contents, attrs) class ImportViewerForm(forms.Form): url = fields.URLField(widget=forms.TextInput(attrs={''class'': ''vTextField''})) type = fields.ChoiceField(choices=[(''o'', ''Organisation''), (''p'', ''Program'')], widget=forms.RadioSelect, help_text=''Url contain infornation about this type'') source = fields.ChoiceField(choices=[(''h'', ''hodex''), (''s'', ''studyfinder'')], initial=''h'', widget=forms.RadioSelect) def __getitem__(self, name): "Returns a BoundField with the given name." try: field = self.fields[name] except KeyError: raise KeyError(''Key %r not found in Form'' % name) return CustomBoundField(self, field, name) class Media: css = {''all'': [settings.STATIC_URL + ''admin/css/forms.css'']}

Necesitas cambiar el método label_tag en la clase BoundField, y usarlo en forma