Add class to Django label_tag() output

五迷三道 提交于 2019-11-27 06:59:00

A custom template tag seems to be the solution. A custom filter would also do, although it can be less elegant. But you would need to fall back to custom form rendering in both cases.

If this is a task of high importance; I'd create a Mixin that allows me to annotate the form fields with label classes and supplies form rendering methods using those classes. So that the following code works:

{{ form.as_table_with_label_classes }}

But I'd like to ask; Do you really need a class on the label tag? I mean HTML design-wise. It is absolutely necessary to add a class in there? Couldn't it be solved with some CSS like:

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

I sometimes use jQuery for such cases where; it will improve the page if it works, but it won't be a disaster if it doesn't. And keep the HTML source as lean as possible.

user240515

Technique 1

I take issue with another answer's assertion that a filter would be "less elegant." As you can see, it's very elegant indeed.

@register.filter(is_safe=True)
def label_with_classes(value, arg):

    return value.label_tag(attrs={'class': arg})

Using this in a template is just as elegant:

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

Technique 2

Alternatively, one of the more interesting technique I've found is: Adding * to required fields.

You create a decorator for BoundField.label_tag that will call it with attrs set appropriately. Then you monkey patch BoundField so that calling BoundField.label_tag calls the decorated function.

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)    

How about adding the CSS class to the form field in the forms.py, like:

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

then I just do the following in the template:

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

Of course this can easily be modified to work within a for loop tag in the template.

Tarun Behal

A bit too late but came across a similar problem. Hope this helps you.

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']
Jose Jorge Lorenzo Vila

I am agree with answer number one, with css this could be done, but. What is the reson for this to be in django source?

In django.forms.forms.py there's this definition that shows there's code to display attrs in labels:

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

but _html_output calls this function without attrs:

label = bf.label_tag(label) or ''

So it seems that django is partially prepared to this but actually it does not used it.

@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']}

You need change method label_tag in BoundField class, and use it in form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!