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

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

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

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

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

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

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

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

Ответы [ 2 ]

11 голосов
/ 24 ноября 2008

Я бы посоветовал вам использовать Модель наследования .

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

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

2 голосов
/ 24 ноября 2008

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

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

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

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


Редактировать. Вот алгоритм слияния.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...