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:
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.
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)
Now the link to customer looks like this: /notadmin123/myapp/customer/1/change/
and leads to the customer edit form:
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)