Django Admin allows adding links to columns to open the change view of the model. Link on more than just the ID/Primary Key field makes it easier to click on the link, because, for example customer name or order date will be simply longer than their ID.

What we can also do is to make a link on a related object that leads to the edit view of that related object.

Here is the OrderAdmin where we have a column for a related object: customer

class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'created_dt', 'completed_dt', 'status', 'customer', )
    list_filter = ('status', OnlyActiveOrdersFilter,)


admin.site.register(Order, OrderAdmin)

And here is how it looks like:

image

Let's make it easier to click first by using list_display_links attribute where we'll list which fields should become links to the edit form of the model. This is a very convenient feature, because numbers are very hard to click at, especially small numbers.

# admin.py


class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'created_dt', 'completed_dt', 'status', 'customer', )
    list_filter = ('status', OnlyActiveOrdersFilter,)
    list_display_links = ('id', 'created_dt',)


admin.site.register(Order, OrderAdmin)

Here we go, both columns ID and created_dt fields are both clickable.

image

Now let's make the customer column value clickable, but it will lead to the customer edit page.

If you just include customer in the list_display_links it will not make it linked to the customer page, but will be yet another field that has a link to the ORDER model.

In order to link to the customer edit page we need to add a method and include that method in the list_display.

This method will return a piece of HTML and must be marked safe so that Django injects HTML and not an escaped text.

# admin.py

class OrderAdmin(admin.ModelAdmin):
    list_display = (
        'id',
        'created_dt',
        'completed_dt',
        'status',
        'link_to_customer', # new
    )
    list_filter = ('status', OnlyActiveOrdersFilter,)
    list_display_links = ('id', 'created_dt',)

    def link_to_customer(self, obj):  # new
        link = reverse("admin:myapp_customer_change", args=[obj.customer.id])
        return format_html(
            '<a href="{}">{}</a>',
            link,
            obj.customer,
        )

    link_to_customer.short_description = 'Customer' # new


admin.site.register(Order, OrderAdmin)

image

Now the link to customer looks like this: /notadmin123/myapp/customer/1/change/ and leads to the customer edit form:

image

By the way, it is important to make a performance optimisation here. Let's add list_select_related here. We can either set it to True(the default is False) or be more specific and provide a specific list of foreign keys to select.

If set to True or the list/tuple it would use the select_related in the queryset which would load OneToOneField and ForeignKeyField values in a single SELECT statement avoiding the need to send a separate query for every object.

class OrderAdmin(admin.ModelAdmin):
    list_display = (
        'id',
        'created_dt',
        'completed_dt',
        'status',
        'link_to_customer',
    )
    list_filter = ('status', OnlyActiveOrdersFilter,)
    list_display_links = ('id', 'created_dt',)
    list_select_related = ('customer',)  # new

    def link_to_customer(self, obj):
        link = reverse("admin:myapp_customer_change", args=[obj.customer.id])
        return format_html(
            '<a href="{}">{}</a>',
            link,
            obj.customer,
        )

    link_to_customer.short_description = 'Customer'


admin.site.register(Order, OrderAdmin)