2010-10-21 1 views
19

Я пытаюсь объединить AND и OR в фильтр с использованием объектов Q. Похоже, что | вести себя как И. Это связано с предыдущим аннотатом, который запускается в том же запросе, а не как подзапрос.Фильтр запросов Django, объединяющий AND и OR с объектами Q, не возвращает ожидаемые результаты

Каков правильный способ обращения с Django?

models.py

class Type(models.Model): 
    name = models.CharField(_('name'), max_length=100) 
    stock = models.BooleanField(_('in stock'), default=True) 
    hide = models.BooleanField(_('hide'), default=False) 
    deleted = models.BooleanField(_('deleted'), default=False) 

class Item(models.Model): 
    barcode = models.CharField(_('barcode'), max_length=100, blank=True) 
    quantity = models.IntegerField(_('quantity'), default=1) 
    type = models.ForeignKey('Type', related_name='items', verbose_name=_('type')) 

views.py

def hire(request): 
    categories_list = Category.objects.all().order_by('sorting') 
    types_list = Type.objects.annotate(quantity=Sum('items__quantity')).filter(
     Q(hide=False) & Q(deleted=False), 
     Q(stock=False) | Q(quantity__gte=1)) 
    return render_to_response('equipment/hire.html', { 
      'categories_list': categories_list, 
      'types_list': types_list, 
      }, context_instance=RequestContext(request)) 

в результате SQL-запрос

SELECT "equipment_type"."id" [...] FROM "equipment_type" LEFT OUTER JOIN 
    "equipment_subcategory" ON ("equipment_type"."subcategory_id" = 
    "equipment_subcategory"."id") LEFT OUTER JOIN "equipment_item" ON 
    ("equipment_type"."id" = "equipment_item"."type_id") WHERE 
    ("equipment_type"."hide" = False AND "equipment_type"."deleted" = False) 
    AND ("equipment_type"."stock" = False)) GROUP BY "equipment_type"."id" 
    [...] HAVING SUM("equipment_item"."quantity") >= 1 

ожидается SQL запрос

SELECT 
    * 
FROM 
    equipment_type 
LEFT JOIN (
    SELECT type_id, SUM(quantity) AS qty 
    FROM equipment_item 
    GROUP BY type_id 
) T1 
ON id = T1.type_id 
WHERE hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0) 

EDIT: Я добавил ожидаемый SQL запрос (без присоединиться на equipment_subcategory)

+0

выглядит ошибкой для меня. я бы написал отчет об ошибке или попросил на #django – tback

ответ

4

ОК, без успеха здесь или на #django. Поэтому я выбираю использовать необработанный запрос SQL, чтобы решить эту проблему ...

Вот рабочий код:

types_list = Type.objects.raw('SELECT * FROM equipment_type 
    LEFT JOIN (           
     SELECT type_id, SUM(quantity) AS qty    
     FROM equipment_item         
     GROUP BY type_id         
    ) T1             
    ON id = T1.type_id          
    WHERE hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0) 
    ') 
20

Попробуйте добавить скобки для явного указания вашей группировки? Как вы уже выяснили, несколько параметров до filter() просто соединены через AND в базовом SQL.

Первоначально вы имели это для фильтра:

[...].filter(
    Q(hide=False) & Q(deleted=False), 
    Q(stock=False) | Q(quantity__gte=1)) 

Если вы хотите (A & B) & (C | D), то это должно работать:

[...].filter(
    Q(hide=False) & Q(deleted=False) & 
    (Q(stock=False) | Q(quantity__gte=1))) 
+0

Я также пробовал это решение, но он по-прежнему не обрабатывает запрос правильно. Учитывая документацию по адресу http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects, фильтр (Q & Q) .filter (Q | Q) или фильтр (Q & Q , Q | Q) или фильтр (Q & Q & (Q | Q)) должны вести себя одинаково. И я в своем случае, это не так ... – cgaspoz

+0

Вы пробовали это с чем-то, что не добавлено через annotate()? Документация для логики AND и OR для filter() и exclude() не является доказательством пули, поэтому продолжайте проверять фактические запросы. Документация показывает предложения OR'd в SQL, но я не вижу этого с 1.2.3 и sqlite3. Я вижу это, когда делаю Qa & Qb & (Qc | Qd). – istruble

4

Этот ответ запаздывает, но может быть полезным для многих парней там.

[...].filter(hide=False & deleted=False) 
.filter(Q(stock=False) | Q(quantity__gte=1)) 

Это создаст что-то похожее на

WHERE (hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0)) 

 Смежные вопросы

  • Нет связанных вопросов^_^