How is a {{ field }} rendered?

I am testing the template_name feature, and I am wondering how exactly the field is rendered. Where does the HTML come from and can it be overwritten on a per field base (like the widgets?)

I want to change some classes on the {{ field }}. I am aware of the widget_tweaks package. Is this the only - or best way?

Are you talking about a form field here or a model field? The two are different.

Hi Ken,

I am talking about the form field in the templates

Form fields are rendered by the widgets being used. The widgets are defined in django.forms.widgets. Each widget class (e.g. TextInput) has a template_name attribute (django/forms/widgets/text.html) with the template to use when rendering that form field.

See:

Yes - but in the template if I call {{ field.widget.render }} nothing happens but if I use {{ field }} it renders the template from template_name. And I asked myself: how is it done. The Field class doesnt have a str method or I looked up at the wrong place at the source code.

I want to find out how it all is connected.

Read the code in django.forms.widgets. The “how’s” are defined there.

Hi Ken,

I checked the windgets methods and it uses the render function to display the HTML; but where does it all come together? So if i call {{ field }} in the template, where is the code that says: call widget.render() and return the HMTL?

Oh is it the BoundField Class?

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

I think you’d need to be looking through the template rendering engine. For example, see the comments at the top of django.template.base. It looks like the engine parser builds an internal structure from the template where each element to be rendered is a node in a tree, and then walks the tree to create the output.

It would make sense to me that that logic would exist there because of the ability to create / use different rendering engines. You would want all the widgets to be rendered the same, but how you identify those fields within a template may be different depending upon the template language.

1 Like

Here is what I traced in Django 5.1:

As per The Django template language | Django documentation | Django, when the template system encounters a dot, it tries the following lookups, in this order:

  • Dictionary lookup
  • Attribute or method lookup
  • Numeric index lookup

A forms.Form declares fields that are some subclass of forms.Field (e.g, forms.CharField, forms.ChoiceField, etc.).

forms.Form is a subclass of forms.BaseForm which has the magic method __getitem__(name).

With {{ a_form.a_field }} in a Django template, the template system tries to access it with a dictionary lookup first. Even a_form['a_field'] in Python code is a dictionary lookup. This triggers the BaseForm.__getitem__(), which returns forms.BoundField of the field-name for which the dictionary lookup is being done on the form. Code snippet below from BaseForm.__getitem__(name):

    if name not in self._bound_fields_cache:
        self._bound_fields_cache[name] = field.get_bound_field(self, name)
    return self._bound_fields_cache[name]

forms.BoundField is a subclass of forms.utils.RenderableFieldMixin. RenderableFieldMixin.__str__() returns the form field as the html widget, which is what you see both in the template {{ a_form.a_field }}, and print(a_form.a_field).