Django использует aggregate() и distinct() вместе
У меня есть набор фильтров, который имеет следующие атрибуты:
dosFromGte = filters.DateFilter(method="search_by_dos_from_gte", lookup_expr="gte")
dosToLte = filters.DateFilter(method="search_by_dos_from_lte", lookup_expr="lte")
# One of these methods:
def search_by_dos_from_lte(self, queryset: Chart, name: str, value: str) -> Chart:
return queryset.annotate(max_dos=Min("diagnosis__dos_from")).filter(max_dos__lte=value)
# using annotate and aggregate Min().
Мне нужно выполнить несколько аннотаций, а затем получить только отдельные идентификаторы.
queryset = self.filter_queryset(self.get_queryset().exclude(state__in=repo_exclude))
queryset = queryset.annotate(
ChartId=F("chart_id")
).values(
"ChartId"
).distinct("id")
Когда я применяю эти фильтры ?clientId=11&project=56&dosFromGte=2023-08-17&dosToLte=2023-08-19
, он пытается запустить Min()
, а затем отличить на ids
.
Это дает NotImplementedError("aggregate() + distinct(fields) not implemented.")
Поэтому я попытался немного поработать и
queryset.values(
"id", "ChartId"
)
# remove duplicate charts based on pk, i.e. id
df = df.drop_duplicates('id')
df = df.drop('id', axis=1)
что было похоже на халтуру и грязную работу вокруг.
Есть ли более чистый ORM-способ сделать это?
Основная проблема здесь заключается в том, что Django не поддерживает использование distinct() с полями после вызова annotate() напрямую, поэтому вы и сталкиваетесь с NotImplementedError.
Вы можете использовать подзапрос для отдельной обработки аннотации, а затем отфильтровать основной набор запросов на основе результатов аннотированного подзапроса. Такой подход позволяет избежать прямого использования distinct() после аннотации ().