2010-10-21 9 views
19

Próbuję połączyć AND i OR w filtrze za pomocą obiektów Q. Wygląda na to, że | zachowywać się jak ORAZ. Jest to związane z poprzednim adnotatem, które jest uruchamiane w tym samym zapytaniu, a nie jako podzapytanie.Filtr zapytań Django łączący AND i OR z obiektami Q nie zwraca oczekiwanych wyników.

Jaki jest właściwy sposób postępowania z 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)) 

Otrzymany zapytań 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 

spodziewać zapytań 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: dodałem zapytanie SQL oczekiwano (bez przyłączenia na equipment_subcategory)

+0

wygląda błędu do mnie. Złożę raport o błędzie lub zapytam na #django – tback

Odpowiedz

4

ok, ale bez powodzenia tutaj lub na #django. Więc wybrać użyć kwerendy SQL surowego, aby rozwiązać ten problem ...

Oto kod roboczych:

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

spróbuj dodać nawiasy, aby wyraźnie określić swoje zgrupowanie? Jak już wiesz, wiele paramerów do filter() jest po prostu łączonych za pośrednictwem AND w bazowym SQL.

Początkowo miał to na filtrze:

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

Jeśli chciał (A & B) & (C | D), to powinno działać:

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

Próbowałem również tego rozwiązania, ale nadal nie obsługuje ono poprawnie żądania. Biorąc pod uwagę dokumentację na http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects, filter (Q & Q) .filter (Q | Q) lub filter (Q & Q , Q | Q) lub filtr (Q & Q & (Q | Q)) powinny zachowywać się w taki sam sposób. A ja w moim przypadku, jest to niewłaściwy sposób ... – cgaspoz

+0

Czy próbowałeś tego z czymś, co nie zostało dodane za pomocą adnotacji()? Dokumentacja logiki AND i OR dla filter() i exclude() nie jest zgodna z kulą, więc sprawdzaj aktualne zapytania. Dokumentacja pokazuje klauzule OR'd w SQL, ale nie widzę tego w wersjach 1.2.3 i sqlite3. Widzę to, kiedy robię Qa & Qb & (Qc | Qd). – istruble

4

Ta odpowiedź jest późno, ale może być pomocne dla wielu facetów tam.

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

To wygeneruje coś podobnego do

WHERE (hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0)) 
Powiązane problemy