Explain Codes LogoExplain Codes Logo

Can "list_display" in a Django ModelAdmin display attributes of ForeignKey fields?

python
django-admin
select_related
prefetch_related
Nikita BarsukovbyNikita Barsukov·Nov 17, 2024
TLDR

For displaying a ForeignKey attribute in list_display of a Django Admin, you need to define a callable method that returns the attribute and include it in list_display.

Say, you have a Book model possessing a foreign key to an Author model. To show the author's name in list_display, here's how to do it:

class BookAdmin(admin.ModelAdmin): list_display = ('title', 'author_name') def author_name(self, obj): # Heck of a name for a method, ain't it? 😃 return obj.author.name author_name.short_description = 'Author Name'

This author_name method grabs the name of every book's associated author, and labels the unleashed magic as "Author Name" in the admin dashboard.

Streamlining performance with select_related

A performance-oriented tip: enhance your admin interface using select_related. Here's how select_related can reduce number of SQL queries and walkthrough the forest of data in an optimized fashion:

class BookAdmin(admin.ModelAdmin): list_display = ('title', 'author_name') def get_queryset(self, request): qs = super().get_queryset(request) # SQL sparing some pain in joins, thank you - "select_related"! return qs.select_related('author') def author_name(self, obj): return obj.author.name author_name.short_description = 'Author Name' author_name.admin_order_field = 'author__name' # Make this column sortable

Advanced customization

Diving deep in ForeignKey relations

Chaining attributes in a callable method allow us to access attributes of more complex relationships or deeper foreign keys:

def publisher(self, obj): # Careful here! That's one deep dive! return obj.author.publisher.name publisher.short_description = 'Publisher' publisher.admin_order_field = 'author__publisher__name' # Sortable, because why not?

Tackling ManyToMany with prefetch_related

For scenarios involving ManyToMany relationships or reverse foreign keys, reach for prefetch_related. prefetch_related fetches related objects in a separate query, helping to avoid N+1 query problems.

Mitigating potential pitfalls

Be mindful and wary of these potential bumps you may encounter:

  • Over-reliance on select_related may lead to heavier and slower SQL queries. Use with discretion.
  • Incorrect chaining of attributes can trigger AttributeErrors – programmers’ greatest fear. Double-check the chains.
  • Overburdening your list_display without optimizing queries can result in painfully slow admin load times – your test users will thank you for paying attention to this.

Tuning admin interface for pleasant user experience

Custom column headers

Your users will be happier with well-sorted and neatly labeled data columns. It's as simple as adjusting the short_description property:

author_name.short_description = 'Author Full Name' # "Full name", it's a formal affair…!

Multipurpose callable methods

Feeling frisky? Throw in some concatenated values or apply custom formatting straight in a callable:

def author_and_book(self, obj): # 'concatenate' is a long word, but gives concise results! 🤓 return '{} - {}'.format(obj.author.name, obj.title) author_and_book.short_description = 'Author & Book'