I'm trying to display image thumbnails in django admin's list_display and I am doing it like this:
from django.utils.safestring import mark_safe class PhotoAdmin(admin.ModelAdmin): fields = ('title', 'image',) list_display = ('title', '_get_thumbnail',) def _get_thumbnail(self, obj): return mark_safe(u'<img src="%s" />' % obj.admin_thumbnail.url)
Admin keeps displaying the thumbnail as escaped html, although I marked the string as safe. What am I doing wrong?
For example, you can check if my_textfield contains a script tag. If so, mark the instance as malicious and return an escaped version of my_textfield (the normal Django behavior). Otherwise, use mark_safe to return your HTML code marked as safe. And all of this doesn't need any migrations to the database.
Django's Admin is amazing. A built-in and fully functional interface that quickly gets in and allows data entry is priceless. Developers can focus on building additional functionality instead of creating dummy interfaces to interact with the database.
The Django admin application can use your models to automatically build a site area that you can use to create, view, update, and delete records. This can save you a lot of time during development, making it very easy to test your models and get a feel for whether you have the right data.
As of Django 1.9, you can use format_html()
, format_html_join()
, or allow_tags
in your method. See the list_display
docs for more info.
The code in the question using mark_safe
will work. However a better option for methods like these might be format_html
, which will escape arguments.
def _get_thumbnail(self, obj): return format_html(u'<img src="{}" />', obj.admin_thumbnail.url)
In earlier versions of Django, using mark_safe()
would not work, and Django would escape the output. The solution was to give the method an allow_tags
attribute with the value set to True.
class PhotoAdmin(admin.ModelAdmin): fields = ('title', 'image',) list_display = ('title', '_get_thumbnail',) def _get_thumbnail(self, obj): return u'<img src="%s" />' % obj.admin_thumbnail.url _get_thumbnail.allow_tags = True
I know this is a rather late answer, but I thought a more complete implementation would be helpful to others...
If you don't have it already with django-filer, get easy_thumbnails pip install easy-thumbnails
.
# -*- coding: utf-8 -*- from django.contrib import admin from easy_thumbnails.files import get_thumbnailer from models import Photo class PhotoAdmin(admin.ModelAdmin): list_display = ('_thumbnail', 'title', ) list_display_links = ('_thumbnail', 'title', ) # This makes the icon clickable too readonly_fields = ('_thumbnail', ) fields = ('title', 'photo', ) def _thumbnail(self, obj): if obj.photo: thumbnailer = get_thumbnailer(obj.photo) thumb = thumbnailer.get_thumbnail({ 'crop': True, 'size': (50, 50), # Sharpen it up a little, since its so small... 'detail': True, # Put other options here... }) # Note: we get the actual width/height rather than # hard-coding 50, 50, just to be DRYer return u'<img src="%s" alt="thumbnail: %s" width="%d" height="%d"/>' % (thumb.url, obj.photo.name, thumb.width, thumb.height) else: return "[No Image]" # Optional, Provide a nicer label in the display _thumbnail.short_description = 'Thumbnail' # Required, leaves the markup un-escaped _thumbnail.allow_tags = True admin.site.register(Photo, PhotoAdmin)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With