Optimising Django Admin List Views

April 30, 2021

If you have very large tables or are storing large blobs or data in specific fields, the only method on your queryset can greatly improve query performance.

The Mighty Only Method

Django supports storing JSON directly in a relational database using the JSONField.

I recently made use of this feature to save the JSON response of an http request directly into a database. As the number of records saved grew I realised my admin page slowed down immensely even though I did not include the json response field in the list_display attribute of the admin instance.

With the django-debug-toolbar I was able to identify that the slow query was indeed the paginated query for the Listview page. I expanded the sql query in the django-debug-toolbar view and noticed that all of the fields on the table were being queried even though I had only specified a subset of fields in the list_display attribute of the admin instance and had explicitly excluded my large blob of JSON field.

I decided to override the get_queryset method of the admin instance and made sure to align the fields returned from the database with the fields specified in the list_display attribute.

And just like that, my admin view was speedy again 😍

Here is a pseudo example of the solution.

class MyModel(models.Model):
    """Hypothetical django model which holds big blobs of JSON."""

    url = models.URLField()
    response = models.JSONField(help_text="This blob can be huge.")
    created_date = models.DateTimeField(auto_now_add=True)


@admin.register(MyModel)
class MyModelAdmin(ReadOnlyModelAdmin):
    """Optimising django admin list views with `only`."""

    list_display = ("url", "created_date")

    def get_queryset(self, *args: Any, **kwargs: Any) -> Any:
        """Only fetch the fields used in list_display."""

        return (
            super()
            .get_queryset(*args, **kwargs)
            .only("url", "created_date")
        )