Understanding Django Admin: get_list_display() in ModelAdmin


Purpose

  • The list view is the primary table-like view that shows all instances of your model, allowing you to browse, edit, or delete them.
  • This method is used within a custom ModelAdmin class to define the fields that will be displayed in the list view of the Django admin interface for your model.

How it Works

    • You create a subclass of django.contrib.admin.ModelAdmin to customize the admin behavior for your specific model.
  1. Overriding get_list_display()

    • Within your subclass, you override the get_list_display() method. This method should return a tuple or list containing the field names (as strings) that you want to be displayed in the list view.

Example

from django.contrib import admin

from .models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    list_display = ('name', 'created_at', 'get_status')  # Customize displayed fields

    def get_status(self, obj):
        if obj.is_active:
            return 'Active'
        else:
            return 'Inactive'

        # Optionally set a short description for the custom field
        get_status.short_description = 'Status'

admin.site.register(MyModel, MyModelAdmin)
  • Optionally, you can use the short_description attribute on the custom method to provide a more descriptive label for the displayed value in the admin interface.
  • The get_status method is a custom function that calculates and returns the status (Active/Inactive) based on the model's is_active field.
  • In this example, the list_display tuple specifies that the name, created_at, and get_status fields will be shown in the list view.

Additional Considerations

  • Read-Only Fields
    If you want to display fields that are read-only in the admin interface, you can include them in list_display even if they're also in readonly_fields.
  • List Ordering
    To define the default sorting order for the list view, use the list_display_links attribute. The first field in list_display_links will be used for sorting by default.
  • Foreign Key Fields
    To display data from related models through ForeignKey fields, you can use accessor methods like obj.related_model.field_name.
  • Custom Methods
    You can define custom methods like get_status to display derived or calculated values that aren't directly stored in model fields.


Displaying a Related Model Field

from django.contrib import admin

from .models import Book, Author

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'get_publication_year')  # Display author name

    def get_publication_year(self, obj):
        return obj.publication_date.year

    get_publication_year.short_description = 'Publication Year'

admin.site.register(Book, BookAdmin)
  • The get_publication_year method extracts the year from the publication_date field and adds it to the list view with a descriptive label.
  • Django automatically resolves related model fields (author here) in the list view.
  • This example displays the author field of the Book model.

Dynamically Filtering Fields Based on User Role

from django.contrib import admin
from django.contrib.auth.models import User

class MyModelAdmin(admin.ModelAdmin):
    def get_list_display(self, request):
        if request.user.is_superuser:
            return ('name', 'email', 'created_at')
        else:
            return ('name', 'created_at')

admin.site.register(MyModel, MyModelAdmin)
  • The get_list_display method returns a different tuple of field names depending on whether the user is a superuser or not.
  • This example dynamically changes the displayed fields based on the user's role.
from django.contrib import admin
from django.db import models

class ActiveManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    is_active = models.BooleanField(default=True)

    objects = ActiveManager()  # Use the custom manager by default

class MyModelAdmin(admin.ModelAdmin):
    list_display = ('name',)

    def get_queryset(self, request):
        # Optionally override queryset filtering for admins
        qs = super().get_queryset(request)
        if not request.user.is_staff:
            qs = qs.filter(is_active=True)  # Only show active objects for non-staff
        return qs

admin.site.register(MyModel, MyModelAdmin)
  • The get_queryset method in the ModelAdmin can be overridden to further refine the list view based on user roles or other criteria.
  • This example demonstrates using a custom model manager (ActiveManager) to filter objects by default.


Customizing the Admin Template

  • You can override the default admin list template (admin/list.html) to inject custom HTML and JavaScript to manipulate the list display dynamically. This approach offers greater flexibility but requires knowledge of template inheritance and JavaScript.

Creating a Custom View

  • For complex list view customization that goes beyond field selection, you can create a custom view that interacts with your model data and renders the list using your preferred templating system. This gives you complete control over the list presentation but requires more development effort compared to get_list_display().

Third-Party Admin Packages

  • Several third-party Django admin packages offer extended functionality for customizing the list view. These packages may provide features like:
    • Inline editing of related models
    • Grouping and filtering options
    • Advanced search capabilities
  • Explore third-party admin packages if you need advanced functionalities or a more polished look and feel for your admin interface.
  • Opt for a custom view for intricate list display requirements that involve complex data manipulation, filtering, or interactive features.
  • Consider a custom template if you need to add simple HTML elements or JavaScript behaviors to the list.
  • Use admin.ModelAdmin.get_list_display() for basic customization of field selection and display in the admin list view.
  • Third-party packages introduce additional dependencies and might require configuration or customization to fit your specific needs.
  • Custom templates and views require more development effort and can become difficult to maintain if you're not careful with template inheritance and code organization.