Используя django, как я могу объединить два запроса из отдельных моделей в один запрос?

В моем конкретном случае у меня есть два типа "сообщений", которые мне нужно извлечь и разбивать на страницы.

Опустите детали и просто скажите, что первый вид находится в модели под названием Msg1, а другой называется Msg2

Поля этих двух моделей совершенно разные, единственными полями, которые являются общими для двух моделей, являются "дата" и "название" (и, конечно же, id).

Я могу получить Msg1.objects.all() и Msg2.objects.all(), но могу ли я объединить эти два запроса в один запрос, отсортировать его по дате и разбивать на страницы?

Мне нужно сохранить ленивый характер запроса.

Тривиальное решение заключается в list(query) обоих запросах и объединяет их в список python. но по очевидным причинам это неэффективно.

Я просмотрел ссылки django на моделях и dp-api, но не кажется, что есть способ объединить запросы разных моделей/таблиц в один.

Ответ 1

Я бы предположил, что вы используете Наследование модели.

Создайте базовую модель, содержащую дату и название. Подкласс Msg1 и Msg2 отключите его, как описано. Выполняйте все свои запросы (чтобы заполнить страницу) с использованием базовой модели, а затем в последний момент переключитесь на производный тип.

Самое замечательное в наследовании - это то, что django позволяет вам использовать базовую модель в внешних ключах из других моделей, чтобы вы могли сделать все приложение более гибким. Под капотом это всего лишь таблица базовой модели с таблицей на подмодуль, содержащую клавиши "один к одному".

Ответ 2

"объединяет эти два запроса в один запрос, сортирует его по дате и разбивает на страницы?"

  • Это объединение SQL. Оставьте Django ORM и используйте союз SQL. Это не блестяще быстро, потому что SQL должен создать временный результат, который он сортирует.

  • Создайте временный результат, который можно отсортировать. Поскольку список имеет метод сортировки, вам нужно объединить два результата в один список.

  • Напишите алгоритм слияния, который принимает два набора запросов, разбивая на страницы результаты.


Изменить. Здесь алгоритм слияния.

def merge( qs1, qs2 ):
    iqs1= iter(qs1)
    iqs2= iter(qs2)
    k1= iqs1.next()
    k2= iqs2.next()
    k1_data, k2_data = True, True
    while k1_data or k2_data:
        if not k2_data:
            yield k1
            try:
                k1= iqs1.next()
            except StopIteration:
                k1_data= False
        elif not k1_data:
            yield k2
            try:
                k2= iqs2.next()
            except StopIteration:
                k2_data= False
        elif k1.key <= k2.key:
            yield k1
            try:
                k1= iqs1.next()
            except StopIteration:
                k1_data= False
        elif k2.key < k1.key: # or define __cmp__.
            yield k2
            try:
                k2= iqs2.next()
            except StopIteration:
                k2_data= False
        else:
            raise Exception( "Wow..." )

Вы можете складывать страницы:

def paginate( qs1, qs2, start=0, size=20 ):
    count= 0
    for row in merge( qs1, qs2 ):
        if start <= count < start+size:
            yield row
        count += 1
        if count == start+size:
            break