How do I use allow_tags in django 2.0 admin?

Just found the answer, use mark_safe function.

In old code, you may use:

def image_(self, obj):
    return '<image src="%s" />' % obj.image
image_.allow_tags = True

In new code, you should use:

from django.utils.safestring import mark_safe
def image(self, obj):
    return mark_safe('<image src="%s" />' % obj.image)

Additionaly to the other answers you can use the mark_safe function as decorator:

from django.utils.safestring import mark_safe

@mark_safe
def icon_pw(self, obj):
    return f'<img src="{obj.icon.url}" />' if obj.icon else ''
icon_pw.short_description = 'Icon'
icon_pw.allow_tags = True

This is the easy way to upgrade your old Django admin code to 2.0.


TL;DR: You should probably use format_html() rather than mark_safe, as recommended by other answers.

The way other answers recommend to use mark_safe will just mark the entire resulting string as safe HTML. IOW, you're telling Django "This is valid and safe HTML, I have ensured any needed escaping has happened". Except that the other answers do not actually do the required escaping.

Consider the following (imperfect) approach from another answer:

from django.utils.safestring import mark_safe
def image(self, obj):
    return mark_safe('<image src="%s" />' % obj.image)

If obj.image now contains a ", or worse, is user input and contains an XSS attack, this will break the resulting HTML.

To prevent this, all data that is interpolated into such HTML snippets should be individually escaped beforehand. Fortunately there is the html_format() function which does both interpolation and the needed escaping. With that, the above example would become:

from django.utils.html import format_html
def image(self, obj):
    return format_html('<image src="{}" />', obj.image)

Note that his uses {} format strings rather than %s, since format_html() is based on str.format(), which uses that style.


If you have your code in admin.py you can overwrite adding only mark_safe function, like the example below:

from django.utils.safestring import mark_safe

def get_image_tag(self):
        if self.picture:
            return mark_safe('<img src="%s" width="60" height="75" />' % self.picture.url)
        else:
            return ' '
get_image_tag.short_description = 'Photo'
#get_image_tag.allow_tags = True #redundant
get_image_tag.admin_order_field = 'name'

This code was tested in Django 2.0.2 and Python 3.6.4.

Tags:

Python

Django