Используя 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