Skip to content

Instantly share code, notes, and snippets.

@Vigrond
Last active May 18, 2020 18:13
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Vigrond/ac3c468377ce6d3e53f9b7059fd42569 to your computer and use it in GitHub Desktop.
Save Vigrond/ac3c468377ce6d3e53f9b7059fd42569 to your computer and use it in GitHub Desktop.
A Django 2.2 Admin Mixin that supports foreign key relationship links with list_links attribute
from django.urls import reverse
from django.utils.html import format_html
class ListLinksMixin(object):
"""
Support for list_links attribute. Items in list_links must also be in list_display
Usage to make 'fieldTwo' a link:
list_display = ('fieldOne', 'fieldTwo',)
list_links = ('fieldTwo',)
"""
list_links = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.list_links:
for field in self.list_links:
if field in self.list_display:
func_name = field + '_link'
setattr(self, func_name, self._generate_link_func(field))
self.list_display = [func_name if item ==
field else item for item in self.list_display]
def _generate_link_func(self, field):
def _func(item):
instance = getattr(item, field)
if not instance:
return None
url = reverse(
f'admin:{instance._meta.app_label}_{instance._meta.model_name}_change', args=[instance.pk])
return format_html(f'<a href="{url}">{instance}</a>')
_func.short_description = field
_func.admin_order_field = field
return _func
@vsemionov
Copy link

vsemionov commented Jul 3, 2019

Thanks for sharing the gist, I found it on SO. I noticed that it causes an error when the value of the related field is None. Here's a simple patch to fix it:

     def _generate_link_func(self, field):
         def _func(item):
             instance = getattr(item, field)
+            if not instance:
+                return None
             url = reverse(
                 f'admin:{instance._meta.app_label}_{instance._meta.model_name}_change', args=[instance.pk])
             return format_html(f'<a href="{url}">{instance}</a>')

@Vigrond
Copy link
Author

Vigrond commented Jul 3, 2019

Thanks for sharing the gist, I found it on SO. I noticed that it causes an error when the value of the related field is None. Here's a simple patch to fix it:

Thanks I have updated the gist

@marisancans
Copy link

Thank you for this. It's unbelievable that django doesn't support this out of the box.

@spetoolio
Copy link

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    if self.list_links:
        for field in self.list_links:
            func_name = field + '_link'
            setattr(self, func_name, self._generate_link_func(field))
            if field in self.list_display:
                self.list_display = [
                    func_name if item == field
                    else item for item in self.list_display
                ]
            if field in self.readonly_fields:
                self.readonly_fields = [
                    func_name if item == field
                    else item for item in self.readonly_fields
                ]

This change allows the links to be in readonly_fields as well (either or both), which is nice if your list_display is already crowded and you only want it if the viewer is viewing the particular model. I also find it disorienting when something is in list_display and not in the model view.

It probably could be a bit cleaner than if-ing each fields list, but it works great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment