How to show only one object in django admin list view?

Question:

Problem

I wish to show only the last row of a QuerySet based on the ModelAdmin‘s ordering criteria. I have tried a couple of methods, but none has worked for me.

Model:

class DefaultConfig(models.Model):
    created_at = models.DateTimeField()
    ...

Attempt 1:

I tried overriding the ModelAdmin‘s get_queryset method and slicing super‘s result, but I came up with some issues.

I.E:

class DefaultConfigAdmin(models.ModelAdmin):
    model = Config
    ordering = ('-created_at',)

    def get_queryset(self, request):
         qs = super().get_queryset(request)
         return qs[<slice>]

I tried the following values for [<slice>]s:

  • [-1:]: raised an Exception because negative slicing is not supported
  • [:1]: raised AssertionError: Cannot reorder a query once a slice has been taken.

Attempt 2:

I tried obtaining the max value for created_at and then filtering for records with that value. I.E:

class DefaultConfigAdmin(models.ModelAdmin):
    model = Config

    def get_queryset(self, request):
         qs = super().get_queryset(request)
         return qs.annotate(max_created_at=Max('created_at')).filter(created_at=F('max_created_at'))

But silly me, that works at row level, so it will only return aggregates over the row itself.

Further attempts (TBD):

Perhaps the answer lies in SubQuerys or Windowing and ranking.

Is there a more straight forward way to achieve this though?

Asked By: EDG956

||

Answers:

Did you try to set list_per_page = 1?

class DefaultConfigAdmin(models.ModelAdmin):
    model = Config
    ordering = ('-created_at',)
    list_per_page = 1

Technically this will still return all Config objects, but only one per page and the latest one will be on the first page.


Another solution (similar to your "Attempt 2"), which involves an extra query, is to manually get hold of the latest created_at timestamp and then use it for filtering.

class DefaultConfigAdmin(models.ModelAdmin):
    model = Config

    def get_queryset(self, request):
         qs = super().get_queryset(request)
         latest_config = qs.order_by('created_at').last()
         return qs.filter(created_at=latest_config.created_at)
Answered By: Dušan Maďar
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.