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 Sponsored App StoreI 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.