69

I have a django admin interface and in the model listing I want a custom column that will be a hyperlink using one of the fields values. Basically one of the models' fields is a url and i'd like the column to have that URL in a clickable hyperlink. This link will need to have additional URL prepended to it as its a relative path in the model field.

dusan
  • 9,104
  • 3
  • 35
  • 55
mikec
  • 3,543
  • 7
  • 30
  • 34
  • 1
    Possible duplicate of [How to add clickable links to a field in Django admin?](http://stackoverflow.com/questions/1949248/how-to-add-clickable-links-to-a-field-in-django-admin) – Louis May 23 '16 at 22:57

3 Answers3

87

Define a method in your ModelAdmin-class and set its allow_tags attribute to True. This will allow the method to return unescaped HTML for display in the column.

Then list it as an entry in the ModelAdmin.list_display attribute.

Example:

class YourModelAdmin(admin.ModelAdmin):
    list_display = ('my_url_field',)

    def my_url_field(self, obj):
        return '<a href="%s%s">%s</a>' % ('http://url-to-prepend.com/', obj.url_field, obj.url_field)
    my_url_field.allow_tags = True
    my_url_field.short_description = 'Column description'

See the documentation for ModelAdmin.list_display for more details.

JRodDynamite
  • 12,325
  • 5
  • 43
  • 63
  • I found out the other day that you actually don't need the `a` tag, since Django admin will automatically turn the URL into a hyperlink. I'm not at my work PC though, so I could be wrong. In my case, I didn't need to set `allow_tags`. I also created a `get_url()` function on my model, as opposed to my admin model - but that's fairly trivial. However, your way is best if we want to open the link in a new window with `target=_blank` -- Hope this is helpful. – Nick Bolton Jan 29 '10 at 21:56
  • @JRodDynamite This is no longer valid for the latest django versions. Could you please add the version of django this works on too ? Thanks – Kiran Ruth R May 22 '20 at 07:46
  • Here is a post for the up-to-date solution: https://stackoverflow.com/a/50989257/1331671 – Ron Sep 11 '20 at 09:09
  • The solution below using `format_html` works, this is an old answer – Lenka Pitonakova Feb 15 '23 at 20:09
40

Use the format_html utility. This will escape any html from parameters and mark the string as safe to use in templates. The allow_tags method attribute has been deprecated in Django 1.9.

from django.utils.html import format_html
from django.contrib import admin
from django.utils.translation import gettext_lazy as _

class MyModelAdmin(admin.ModelAdmin):
    list_display = ['show_url', ...]
    # ...

    @admin.display(description=_("Column title"))
    def show_url(self, obj):
        return format_html("<a href='http://pre.com{0}'>{0}</a>", obj.url)

Now your admin users are safe even in the case of:

url == '<script>eval(...);</script>'

See the documentation for more info.

Flimm
  • 136,138
  • 45
  • 251
  • 267
Seppo Erviälä
  • 7,160
  • 7
  • 35
  • 40
  • this worked perfectly for me. The only difference I had (seems like it may be a new update is to use 'instance' instead of 'obj'. Let me answer below just as an example. Thanks for the post Seppo! – Alex Winkler Apr 29 '20 at 08:30
1

I am using 'instance' instead of 'obj'. Seppo Erviälä's answer helped me the most as I'm using Django 3.0.1.

def get_facebook(self, instance):
    return format_html("<a target='_blank' href='{0}'>{0}</a>", instance.profile.facebook)
get_facebook.short_description = 'Facebook'
Alex Winkler
  • 469
  • 4
  • 25