Добрый день!
Уже задавал вопрос — надо было сделать кастомную сортировку на основе другой таблицы.
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=[]) подзапрос, но оно все равно ломает все, так как использует потом этот запрос в имени таблицы везде(