Как правильно использовать order_by с nulls_last в соответствующем поле one_to_many? - PullRequest
0 голосов
/ 28 апреля 2020

Я пытаюсь фильтровать и упорядочивать объекты по наличию связанной модели с принудительным введением нулей в качестве последнего.

Примеры моделей:

class ModelA(models.Model):
    name = models.CharField(max_length=255)
    ...


class ModelB(models.Model):
    model_a = models.ForeignKey(ModelA, related_name=model_b)
    date = models.DateField()
    time = models.TimeField()
    ...

Теперь мне нужно отфильтровать ModelA по некоторые kwargs (обычные операции), но мне также нужно заказать ModelA на ближайшую дату и время ModelB (в будущем, а не в прошлом) по возрастанию или по убыванию с ОДНОЙ ПАРАМЕТРОЙ ЗАПРОСА , а также NULLS должны быть помещены последними независимо от возрастания или убывания.

Я уже пришел к выводу, что мне нужно перезаписать QuerySet по умолчанию order_by:

class ModelAQuerySet(models.QuerySet):
    def order_by(self, *field_names):
        if 'model_a_date' in field_names or '-model_a_date' in field_names:
            field_names = list(field_names)
            if 'model_a_date' in field_names:
                field_names.remove('model_a_date')
                return super().order_by(
                    'model_b__date',
                    'model_b_time',
                    *field_names
                )
            else:
                field_names.remove('-model_a_date')
                return super().order_by(
                    '-model_b__date',
                    '-model_b__time',
                    *field_names
                )
        else:
            return super().order_by(*field_names)

Он отлично работает, когда я упорядочиваю по убыванию ('-model_a_date'), так как NULLS являются последними, но я с трудом помещаю последние нули в порядке возрастания. Я уже пробовал:

return super().order_by(
    F('model_b').asc(nulls_last=True),
    'model_b__date',
    'model_b__time',
    *field_names
)

####

return super().order_by(
    F('model_b').asc(nulls_last=True)
).order_by(
    'model_b__date',
    'model_b_time',
    *field_names
)

####

return super().order_by(
    'model_b__date',
    'model_b_time',
    *field_names
).order_by(
    F('model_b').asc(nulls_last=True),
)

, но это не работает вообще. Либо когда я помещаю внутрь order_by вместе с другими аргументами, либо как отдельный order_by впереди или после вышеупомянутого order_by.

Есть какие-нибудь идеи по этому поводу? Кто-нибудь сталкивался с такой проблемой? Я здесь в рассоле и, честно говоря, у меня кончились идеи. Заранее спасибо.

РЕДАКТИРОВАТЬ

Я тоже пробовал .union вот так:

ModelA.objects.annotate(
    modelbs=Count('modelb')
).filter(
    modelbs__gt=0
).union(
    ModelA.objects.annotate(
        modelbs=Count('model_b')
    ).filter(
        modelbs=0
    )
)

Но это выходит с ошибкой:

ORDER BY term does not match any column in the result set.

1 Ответ

0 голосов
/ 28 апреля 2020

Если вы используете цепочку, вы можете:

  • сначала отфильтровать элементы, которые не равны нулю, упорядочить их по возрастанию или убыванию
  • секунд выбрать нули
  • наконец, вы сможете связать имеющиеся у вас qs (с нулями в конце) и вернуть их

Имеет ли это смысл?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...