Подзапрос в запросе Django

Добрый день!
Уже задавал вопрос — надо было сделать кастомную сортировку на основе другой таблицы.
habrahabr.ru/qa/29605/ — собственно, схема тут.
Решил достаточно просто — делаю сначала фильтрацию HabrItem, делаю join с таблицей ItemOrdering, потом с теми же параметрами фильтрую ItemOrdering, беру запрос из HabrItem и заменяю в нем упоминание таблицы на запрос из ItemOrdering и делаю запрос в бд через raw()
Чем плох метод? Тем, что у меня напрочь отсутствуют необходимые методы из менеджера и queryset'a, а я использую пайджинатор и стандартные вьюхи типа list_view.
Не могу пока придумать, как это обойти или реализовать иначе…
Вот как выглядит в коде.

class ParamOne(models.Model):
    title = models.CharField(verbose_name=u'title', max_length=32)
    def __unicode__(self):
        return self.title

class ParamTwo(models.Model):
    title = models.CharField(verbose_name=u'title', max_length=32)
    def __unicode__(self):
        return self.title

class ParamThree(models.Model):
    title = models.CharField(verbose_name=u'title', max_length=32)
    def __unicode__(self):
        return self.title


class Item(models.Model):
    title = models.CharField(verbose_name=u'title', max_length=32)
    paramOne = models.ManyToManyField(ParamOne, blank=True, null=True)
    paramTwo = models.ManyToManyField(ParamTwo, blank=True, null=True)
    paramThree = models.ManyToManyField(ParamThree, blank=True, null=True)

    objects = ItemManager()

    def __unicode__(self):
        return self.title

class ItemOrdering(models.Model):
    item = models.ForeignKey(Item)
    paramOne = models.ForeignKey(ParamOne, blank=True, null=True)
    paramTwo = models.ForeignKey(ParamTwo, blank=True, null=True)
    paramThree = models.ForeignKey(ParamThree, blank=True, null=True)
    order = models.IntegerField(verbose_name=u"Order")


def getOrdered():
    paramOne = ParamOne.objects.get(title=1)
    paramTwo = ParamTwo.objects.get(title=1)
    itemOrdering = ItemOrdering.objects.filter(paramOne=paramOne, paramTwo=paramTwo).exclude(paramThree=None)

    items = Item.objects.filter(paramOne=paramOne, paramTwo=paramTwo)
    items.query.join(('items_item', 'items_itemordering', 'id', 'item_id'), promote=True, nullable=True)
    items = items.extra(select={'ordering':'COALESCE("items_itemordering".order, "items_item".order)'}, order_by=['ordering'])


    objcts = Item.objects.raw(items.query.__str__().replace('JOIN "items_itemordering"', 'JOIN (%s) AS "items_itemordering"'%itemOrdering.query.__str__()))
    return objcts


А вот результат sql
SELECT (COALESCE("items_itemordering".order, "items_item".order)) AS "ordering", "items_item"."id", "items_item"."title" FROM "items_item" INNER JOIN "items_item_paramOne" ON ("items_item"."id" = "items_item_paramOne"."item_id") INNER JOIN "items_item_paramTwo" ON ("items_item"."id" = "items_item_paramTwo"."item_id") LEFT OUTER JOIN (SELECT "items_itemordering"."id", "items_itemordering"."item_id", "items_itemordering"."paramOne_id", "items_itemordering"."paramTwo_id", "items_itemordering"."paramThree_id", "items_itemordering"."order" FROM "items_itemordering" WHERE ("items_itemordering"."paramOne_id" = 2  AND "items_itemordering"."paramTwo_id" = 1  AND NOT ("items_itemordering"."paramThree_id" IS NULL))) AS "items_itemordering" ON ("items_item"."id" = "items_itemordering"."item_id") WHERE ("items_item_paramOne"."paramone_id" = 2  AND "items_item_paramTwo"."paramtwo_id" = 1 ) ORDER BY "ordering" ASC


Как можно это решить через стандартный orm?
Уже сделал манкипатчинг и смог вставлять в .extra(tables=[]) подзапрос, но оно все равно ломает все, так как использует потом этот запрос в имени таблицы везде(
  • Вопрос задан
  • 4370 просмотров
Пригласить эксперта
Ответы на вопрос 1
@kozzztik
Может проще разбить на отдельные маленькие запросы, чем пытаться все вытянуть одной пачкой генерируя монструозные join`ы, которые исполнятся скорее всего все равно будут дольше.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы