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() после аннотации ().

Вернуться на верх