change list display link in django admin
Asked Answered
O

7

35

I am trying to change the link for an object in the django admin list display. Here is what I have so far:

class FooModelAdmin(admin.ModelAdmin):
    fields = ('foo','bar')
    list_display = ('foo_link','bar')

    def foo_link(self,obj):
        return u'<a href="/foos/%s/">%s</a>' % (obj.foo,obj)
    domain_link.allow_tags = True
    domain_link.short_description = "foo"

This produces another link within the original list display link e.g.

<a href="/admin/app/model/pk/"><a href="/foos/foo/">Foo</a></a>
Overthrow answered 22/10, 2010 at 16:14 Comment(0)
O
37

The solution was to override the init and set the list_display_links to None e.g.

class FooModelAdmin(admin.ModelAdmin):
    fields = ('foo','bar')
    list_display = ('foo_link','bar')

    def foo_link(self,obj):
        return u'<a href="/foos/%s/">%s</a>' % (obj.foo,obj)
    foo_link.allow_tags = True
    foo_link.short_description = "foo"
    def __init__(self,*args,**kwargs):
        super(FooModelAdmin, self).__init__(*args, **kwargs)
        self.list_display_links = (None, )
Overthrow answered 22/10, 2010 at 17:37 Comment(1)
Working with Django 3.0 and allow_tags didn't work for me, but applying mark_safe on the html before returning.Lyophobic
C
38

I believe the correct way of doing it, is subclassing ChangeList and override the url_for_result method to create the correct change url you want.

Override the get_changelist in the admin.ModelAdmin subclass to return the new class:

from django.contrib.admin.views.main import ChangeList
from django.contrib.admin.util import quote

class FooChangeList(ChangeList):
    def url_for_result(self, result):
        pk = getattr(result, self.pk_attname)
        return '/foos/foo/%d/' % (quote(pk))

class FooAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return FooChangeList
Claiborn answered 29/5, 2013 at 19:10 Comment(0)
O
37

The solution was to override the init and set the list_display_links to None e.g.

class FooModelAdmin(admin.ModelAdmin):
    fields = ('foo','bar')
    list_display = ('foo_link','bar')

    def foo_link(self,obj):
        return u'<a href="/foos/%s/">%s</a>' % (obj.foo,obj)
    foo_link.allow_tags = True
    foo_link.short_description = "foo"
    def __init__(self,*args,**kwargs):
        super(FooModelAdmin, self).__init__(*args, **kwargs)
        self.list_display_links = (None, )
Overthrow answered 22/10, 2010 at 17:37 Comment(1)
Working with Django 3.0 and allow_tags didn't work for me, but applying mark_safe on the html before returning.Lyophobic
M
19

By default the first column of list display will be link to the admin edit page. If you want another column or columns to be that link, a very easy way is as follows:

class FooModelAdmin(admin.ModelAdmin):
    list_display = ('foo_link', 'bar', 'another_bar', )
    list_display_links = ('foo_link', 'another_bar', )

If foo_link is not a property of the model, it should be a callable like the following:

class FooModelAdmin(admin.ModelAdmin):
    list_display = ('foo_link', 'bar', 'another_bar', )
    list_display_links = ('foo_link', 'another_bar', )

    def foo_link(self, obj):
        return "%s blah blah" % obj.some_property # or anything you prefer e.g. an edit button

A full example from my project:

class SchoolTeacherAdmin(admin.ModelAdmin):
    list_display = ('name', 'designation', 'school_name', 'school_code', 'date_of_birth', 'mobile', 'nid', 'edit', )
    list_display_links = ('edit', )

    def school_code(self, obj):
        return obj.school.code

    def school_name(self, obj):
        return obj.school.name.upper()

    def edit(self, obj):
        return "Edit"
Mail answered 23/10, 2017 at 11:46 Comment(0)
C
8

Here is the link to Django 3.1 documentation of the ModelAdmin option called ModelAdmin.list_display_links.

Calgary answered 26/10, 2020 at 8:31 Comment(2)
it was available before 3.1 too, I'm on 2.2 and its there docs.djangoproject.com/en/2.2/ref/contrib/admin/…Justifiable
This answer is specific only to if you want the link to be the "edit" function; for generic links this is not applicable and the question doesn't really specify.Accumbent
B
2

Needed something like this for a project. That was my solution to generate clickable references

from django.utils.safestring import mark_safe

@admin.register(models.Transaction)
class TransactionAdmin(admin.ModelAdmin):
    model = models.Transaction
    list_display = ('id', 'transaction_code', 'status', 'downloaded', 'realm',
                    'product_id', 'ticket', 'deleted', 'updated', 'created')
    search_fields = ("transaction_code", 'product_id', 'ticket_id')
    list_filter = ('status', 'downloaded', 'realm')
    readonly_fields = ('updated', 'created')
    change_form_template = 'admin/change_form_transaction.html'
    add_form_template = 'admin/change_form.html'
    list_display_links = ('id', )
    ordering = ('-created', )
    
    def ticket(self, obj):
        if obj.ticket_id:
            return mark_safe(f'<a href="https://ticketing.oursite.com/staff/index.php?/Tickets/Ticket/View/{obj.ticket_id}">{obj.ticket_id}</a>')
        return None
    
    ticket.allow_tags = True
    ticket.short_description = "ticket id"
Backblocks answered 27/2, 2023 at 15:6 Comment(1)
And mark_safe really being what resolves the original question.Accumbent
B
1

After following this idea myself (to link from the list display to the actual page) I had second thoughts. There are two pages that you have to consider: the admin page of the model and the actual public page (probably detail view) of the model. If you link from the admin to the public page (even if it is a CMS page) you loose the connection to its admin page.

The admin page of the model actually links to the public page via the "Preview" link (regularly placed at the top right). This link derives from model_object.get_absolute_url().

So, if you want to change where the preview link points you simply have to override get_absolute_url(). And in this case, it's probably a good thing you do that, anyway, because you will likely want to make use of that url in all other places, as well.

Brigade answered 10/9, 2014 at 17:54 Comment(0)
C
0

You need to override the template since the link is wrapped there. Have a look at Edit Django User admin template.

Centrepiece answered 22/10, 2010 at 17:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.