Как объединить два набора запросов из одной модели, не упорядочивая их - PullRequest
1 голос
/ 25 мая 2019

Я создал два набора запросов из одной модели и объединил их в один набор запросов. Но не хочу делать какие-либо упорядочения для нового созданного набора запросов. Я хочу, чтобы мои элементы набора запросов отображались так, как я их слил.

queryset1  = modelA.objects.filter(id=modelB.rel_id)
queryset2  = modelA.objects.exclude(id=modelB.rel_id)
queryset = queryset1 | queryset2

Я ожидаю, что результат должен быть

queryset = <QuerySet [<modelA: YY>, <modelA: XX>, <modelA: ZZ>]>

Потому что modelA: YY - это набор запросов1, и я объединяю его как первый элемент Но результат был:

queryset = <QuerySet [<modelA: XX>, <modelA: YY>, <modelA: ZZ>]>

Это заказ по идентификатору модели. Даже я не устанавливаю порядок в modelA и новом наборе запросов.

1 Ответ

2 голосов
/ 25 мая 2019

Здесь вы должны использовать функцию union(..) [Django-doc] , например:

queryset = modelA.objects.filter(id=modelB.rel_id)<b>.union(</b>
    modelA.objects.exclude(id=modelB.rel_id),
    <b>all=True</b>
<b>)</b>

или | [Django-doc] , с другой стороны, будет, как указано в документации:

Объединяет два QuerySet с помощью оператора SQL OR .

Следующие значения эквивалентны:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))

При этом, если вы хотите указать modelB.rel_id в качестве последнего, вы можете сделать это следующим образом:

from django.db.models import BooleanField, ExpressionWrapper, Q

modelA.objects.annotate(
    <b>rel_to_b=</b>ExpressionWrapper(
        Q(id=modelB.rel_id),
        output_field=BooleanField()
    )
).order_by(<b>'rel_to_b'</b>)

Здесь мы таким образом аннотируем ModelA s с дополнительным атрибутом rel_to_b, в случае, если объекты связаны с B, этот атрибут будет True, и поскольку True упорядочен позже, чем False, это будет последняя строка.

Это выдаст запрос, который выглядит следующим образом:

SELECT model_a.*,
       <b>model_a.id = <i>modelB.rel_id</i> AS rel_to_b</b>
FROM model_a
<b>ORDER BY rel_to_b ASC</b>
...