Context
There is no denying the fact that we all love Django and most importantly Django Admin. It provides ready-to-use interactive interface for CRUD operations with models along with tons of customizations and features like filters, pagination, bulk-actions etc.
One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site.
— Django site
Problem
Wouldn’t it be great if there was a way to display the actual image instead of just the boring link. Well, we are lucky as there are plenty of methods to achieve this.
For ease of understanding and post’s length this will be a 3 part post -
- Part 1: Using readonly_fields ✅
- Part 2: Create custom widget for the field ✅
- Part 3: Create a Mixin to reuse the widget ❌
For this tutorial let’s suppose we have a model as below -
class User(AbstractUser):
# Fields
profile_pic = models.ImageField(upload_to="upload/images/")
By default, the django admin displays the link for ImageField along with a change button. Here I have an ImageField named “Profile Pic” and it is displayed like this -

Solution: Use readonly_fields
Django admin provides readonly_fields to allow fields to prevent them from editing. We can create a new method which
would return the image tag (<img></img>) with mark_safe
which then could be used to display the actual image. Create a method as mentioned below in the User model.
def get_profile_pic_tag(self):
return mark_safe('<img src="{url}" />'.format(
url=self.profile_pic.url
)
)
get_profile_pic_tag.short_description = "Profile Pic"
This method can be created in your ModelAdmin as well. The only difference would be to replace the self parameter with something else like obj or user and use obj.profile_pic.url instead of self.profile_pic.url
Now we can use the above method under the readonly_fields property as below -
@admin.register(models.User)
class UserAdmin(admin.ModelAdmin):
list_display = ('id', 'first_name', 'last_name', 'email', 'profile_pic',)
readonly_fields = ('get_profile_pic_tag', )
...
And Voila!!! The actual image will be visible as below -

In the next part of this tutorial we will understand the cons of using this approach and implement a fix for it.