Django: Customizing how a model form renders fields

A quick look at providing a custom HTML template for ModelForm to use for fields you choose.

Published: Nov. 6, 2022
App Store

I recently wanted to improve my form that contains a couple of ImageField fields. I wanted to display a small preview of the image to remind users what they saved for this particular model.

Since I am using the Django Form API to render the form in a template without providing my own HTML, I couldn’t add more HTML to show the preview.

Instead, what you can do is to provide custom “widgets” for some of the fields in your model form. I will use my implementation as an example, but you could use this same approach for other form fields to customize how they get rendered.

Initial setup

To get the ability to customize the widgets, you need to do a bit of configuration in the settings.py. You need to add 'django.forms' to your INSTALLED_APPS and add this line:

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

TimonWeb has a bit more info about this.

Creating your custom template

The next step is to create your template in the templates directory. Creating a custom widget template is easier than it sounds since you can look at the base widget templates in Django to get the initial markup.

You can find these templates in your virtual environment under site-packages; once there, go to:

django/forms/templates/django/forms/widgets

Because I wanted to customize the optional image field, I used the template clearable_file_input.html as my starting point.

I started by copying this markup to my new template and modifying it to include checking if an image exists and, if so, adding a little HTML to show its preview.

Using the template in your form

To use the custom template, I created a class like this:

class ImageFieldWidgetWithPreview(ClearableFileInput):
    template_name = 'overrides/form_image_field_widget_with_preview.html' 

And finally, we can use this in the Meta class for our model form:

class DetailForm(forms.ModelForm):
    class Meta:
        model = PressKit
        widgets = {
            'product_icon': ImageFieldWidgetWithPreview
        }

And that is all. The form will now use the custom template to render the product_icon field.

Bluesky logo

Follow on Bluesky to not miss new posts

Filip Němeček profile photo

WRITTEN BY

Filip Němeček Mastodon

iOS blogger and developer with interest in Python/Django.

iOS blogger and developer with interest in Python/Django.