#django #django-models #django-admin
Вопрос:
Я пытаюсь отфильтровать администратора Django по аннотированному полю, но получаю FieldDoesNotExist
ошибку.
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
В результате в Django Admin возникает ошибка:
FieldDoesNotExist at /admin/events/event/
Event has no field named 'event_start_date'
Мне нужно фильтровать event_start_date
, а не eventsession_set__start_date
потому, что порядок фильтрации (редактирования) в последнем случае приводит к появлению в представлении списка нескольких строк на событие (по одной для каждого сеанса).
Ошибка возникает из-за метода get_field 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))
Я на Django 3.2. Есть идеи?
Комментарии:
1. Как бы странно это ни звучало, к сожалению, это полностью не поддерживается Django
2. Хлоп. Не то, на что я надеялся, но спасибо. облом.
Ответ №1:
Это пример того, как добавить порядок и отфильтровать по аннотированным полям на странице списка администраторов django
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
Ответ №2:
Я считаю, что нашел решение для дублирования записей — переопределение, get_changelist
как описано здесь.
def get_changelist(self, request, **kwargs):
from django.contrib.admin.views.main import ChangeList
class SortedChangeList(ChangeList):
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.order_by("event_start_date")
if request.GET.get("o"):
return ChangeList
return SortedChangeList