While there are some good, functional solutions already shared here, I feel that non-form markup, such as auxiliary image tags, belong in templates, not tacked on to Django form widgets or generated in model admin classes. A more semantic solution is:
Admin Template Overrides
Note: Apparently my reputation isn't high enough to post more than two simple links, so I have created annotations in the following text and included the respective URLs at the bottom of this answer.
From the Django Admin Site documentation:
It is relatively easy to override many of the templates which the admin module uses to generate the various pages of an admin site. You can even override a few of these templates for a specific app, or a specific model.
Django's django.contrib.admin.options.ModelAdmin
(commonly accessed under the namespace django.contrib.admin.ModelAdmin
) presents a series of possible template paths to Django's template loader in order from most specific to less so. This snippet was copied directly from django.contrib.admin.options.ModelAdmin.render_change_form
:
return TemplateResponse(request, form_template or [
"admin/%s/%s/change_form.html" % (app_label, opts.model_name),
"admin/%s/change_form.html" % app_label,
"admin/change_form.html"
], context)
Therefore, considering the aforementioned Django admin template override documentation and the template search paths, suppose one has created an app "articles" in which is defined a model class "Article". If one wants to override or extend only the default Django admin site change form for model articles.models.Article
, one would execute the following steps:
- Create a template directory structure for the override file.
- Although the documentation does not mention it, the template loader will look in app directories first if
APP_DIRS
1 is set to True
.
- Because one wants to override the Django admin site template by app label and by model, the resulting directory hierarchy would be:
<project_root>/articles/templates/admin/articles/article/
- Create the template file(s) in one's new directory structure.
- Only the admin change form needs to be overridden so create
change_form.html
.
- The final, absolute path will be
<project_root>/articles/templates/admin/articles/article/change_form.html
- Completely override or simply extend the default admin change form template.
- I wasn't able to locate any information in the Django documentation concerning the context data available to the default admin site templates so I was forced to look at the Django source code.
- Default change form template: github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_form.html
- A few of the relevant context dictionary definitions can be found in
django.contrib.admin.options.ModelAdmin._changeform_view
and django.contrib.admin.options.ModelAdmin.render_change_form
My Solution
Assuming that my ImageField attribute name on the model is "file", my template override to implement image previews would be similar to this:
{% extends "admin/change_form.html" %}
{% block field_sets %}
{% if original %}
<div class="aligned form-row">
<div>
<label>Preview:</label>
<img
alt="image preview"
src="/{{ original.file.url }}"
style="max-height: 300px;">
</div>
</div>
{% endif %}
{% for fieldset in adminform %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% endblock %}
original
appears to be the model instance from which the ModelForm was generated. As an aside, I usually don't use inline CSS but it wasn't worth a separate file for a single rule.
Sources:
- docs.djangoproject.com/en/dev/ref/settings/#app-dirs