I'm trying to filter in Django Admin on an annotated field, but getting a FieldDoesNotExist
error.
class Event(models.Model):
name = models.CharField(max_length=50, blank=True)
class EventSession(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
ordering = ["event_start_date"]
list_filter = ["event_start_date", "event_end_date"]
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.annotate(
event_start_date=Min("eventsession_set__start_date"), # start of first day
event_end_date=Max("eventsession_set__start_date"), # start of last day
)
return qs
The resulting error in Django Admin is:
FieldDoesNotExist at /admin/events/event/
Event has no field named 'event_start_date'
I need to filter on event_start_date
rather than eventsession_set__start_date
because filtering ordering (edit) on the latter causes multiples rows per event (one for each session) to show up in the list view.
The error comes from the get_field method of django/db/models/options.py
:
try:
# Retrieve field instance by name from cached or just-computed
# field map.
return self.fields_map[field_name]
except KeyError:
raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
I'm on Django 3.2. Any ideas?
You can filter by annotated fields with a custom List Filter.
And you can order by an annotated field by defining display methods and setting the "order field" accordingly.
This is an example how to add ordering and filter by annotated fields at django admin list page
class EventStartDateListFilter(admin.SimpleListFilter):
title = "start_date"
parameter_name = "start_date"
def lookups(self, request, model_admin):
return (
("week", "week"),
# add other filters
)
def queryset(self, request, queryset):
value = self.value()
if value == "week":
return queryset.filter(_event_start_date__gt=now() - timedelta(weeks=1))
return queryset
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
list_display = ["__str__", "event_start_date", "event_end_date"]
ordering = ["event_start_date", "event_end_date"]
list_filter = [EventStartDateListFilter]
def event_start_date(self, obj):
return obj._event_start_date
event_start_date.admin_order_field = '_event_start_date'
def event_end_date(self, obj):
return obj._event_end_date
event_end_date.admin_order_field = '_event_end_date'
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.annotate(
_event_start_date=Min("eventsession_set__start_date"), # start of first day
_event_end_date=Max("eventsession_set__start_date"), # start of last day
)
return qs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With