Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django override the form HTML label template?

In my settings.py I have set

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

now in can add my own templates in:

<project>/templates/django/forms/widgets/

or

<app>/templates/django/forms/widgets/

this works great! However, what I can't find is where do I override the default html (form) label?

class TestForm(forms.Form):
    first_name = forms.CharField(label="First name", max_length=50)
    last_name = forms.CharField(label="Last name")
    nick_name = forms.CharField(required=False)

The above form would render the labels like this:

<label for="id_first_name">First name:</label>

I want to render the label differently. So, I thought it would easy as adding a html label template: templates/django/forms/widgets/label.html

This doesn't work. Was going through the Django docs, but I can't find how to do this for labels. Apparently a label is not a widget.

https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#built-in-widgets

My question, where/how do I change the default label?

like image 762
Roger Avatar asked Jul 26 '17 09:07

Roger


2 Answers

Here is a working solution (tested on Django 3.1) :

Create a child class of Django's Form, and set LABEL_TEMPLATE to the template your want.

myapp/base_form.py

from django import forms
from django.forms.utils import flatatt
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

LABEL_TEMPLATE = '<p{}>{}</p>'


class CustomLabelBoundField(forms.boundfield.BoundField):


    def label_tag(self, contents=None, attrs=None, label_suffix=None):
        """
        Wrap the given contents in a <label>, if the field has an ID attribute.
        contents should be mark_safe'd to avoid HTML escaping. If contents
        aren't given, use the field's HTML-escaped label.

        If attrs are given, use them as HTML attributes on the <label> tag.

        label_suffix overrides the form's label_suffix.
        """
        contents = contents or self.label
        if label_suffix is None:
            label_suffix = (self.field.label_suffix if self.field.label_suffix is not None
                            else self.form.label_suffix)
        # Only add the suffix if the label does not end in punctuation.
        # Translators: If found as last label character, these punctuation
        # characters will prevent the default label_suffix to be appended to the label
        if label_suffix and contents and contents[-1] not in _(':?.!'):
            contents = format_html('{}{}', contents, label_suffix)
        widget = self.field.widget
        id_ = widget.attrs.get('id') or self.auto_id
        if id_:
            id_for_label = widget.id_for_label(id_)
            if id_for_label:
                attrs = {**(attrs or {}), 'for': id_for_label}
            if self.field.required and hasattr(self.form, 'required_css_class'):
                attrs = attrs or {}
                if 'class' in attrs:
                    attrs['class'] += ' ' + self.form.required_css_class
                else:
                    attrs['class'] = self.form.required_css_class
            attrs = flatatt(attrs) if attrs else ''
            contents = format_html(LABEL_TEMPLATE, attrs, contents)
        else:
            contents = conditional_escape(contents)
        return mark_safe(contents)




def get_bound_field(field, form, field_name):
    """
    Return a BoundField instance that will be used when accessing the form
    field in a template.
    """
    return CustomLabelBoundField(form, field, field_name)


class CustomLabelForm(forms.Form):

    def __getitem__(self, name):
        """Return a BoundField with the given name."""
        try:
            field = self.fields[name]
        except KeyError:
            raise KeyError(
                "Key '%s' not found in '%s'. Choices are: %s." % (
                    name,
                    self.__class__.__name__,
                    ', '.join(sorted(self.fields)),
                )
            )
        if name not in self._bound_fields_cache:
            self._bound_fields_cache[name] = get_bound_field(field, self, name)
        return self._bound_fields_cache[name]

And inherit your form from CustomLabelForm :

myapp/forms.py

from django import forms
from myapp.base_form import CustomLabelForm

class TestForm(CustomLabelForm):
    first_name = forms.CharField(label="First name", max_length=50)
    last_name = forms.CharField(label="Last name")
    nick_name = forms.CharField(required=False)


This produces <p for="id_first_name">First name:</p>

like image 102
Charlesthk Avatar answered Nov 09 '22 05:11

Charlesthk


You could override __init__() method of the form:

def __init__(self, *args, **kwargs):
    self.fields['field_name'].label = 'Your new label here'
like image 2
Jenish Shrestha Avatar answered Nov 09 '22 04:11

Jenish Shrestha