Дублирование записей при объединении `distinct` и `order_by`

Я использую filter_backend для упорядочивания полей, но у меня есть проблема, когда я получаю API с упорядочиванием по product__company__name, API отвечает 1 результатом, как я и ожидал, но с 2 дублированными записями. Я прочитал заметку в этой документации https://docs.djangoproject.com/en/3.2/ref/models/querysets/#distinct, что If you order by fields from a related model, those fields will be added to the selected columns and they may make otherwise duplicate rows appear to be distinct. Since the extra columns don’t appear in the returned results (they are only there to support ordering), it sometimes looks like non-distinct results are being returned. Так как я могу решить эту проблему? Большое спасибо.

    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ["product__company__name"]
    ordering_fields = [
        "created",
        "product__company__name",
    ]
    def get_queryset(self):
            result = (
                MyModel.objects.filter(
                   <logic_code>
            )
            return result.distinct()

В PostgreSQL можно указать, какие поля должны учитываться при проверке отличимости. Вот что говорится в документации:

Только в PostgreSQL вы можете передавать позиционные аргументы (*fields), чтобы указать имена полей, к которым должен применяться DISTINCT. Это переводится как SQL-запрос SELECT DISTINCT ON. Вот в чем разница. При обычном вызове distinct() база данных сравнивает каждое поле в каждой строке, определяя, какие строки являются отличительными. Для вызова distinct() с указанными именами полей база данных будет сравнивать только указанные имена полей.

(Источник.)

Если вы сделаете .distinct("id"), это означает, что он будет учитывать только первичный ключ MyModel, а не считать две строки разными, если любое поле в них отличается.

Если вы не используете PostgreSQL, вам придется ограничить выборку столбцов, как в этом ответе.

В процессе поиска решения с помощью ORM, я преобразовал его в список и решил эту проблему.

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