Я пытаюсь фильтровать и упорядочивать объекты по наличию связанной модели с принудительным введением нулей в качестве последнего.
Примеры моделей:
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.