Question

I have such models:

class Category(Model):
    ...
    type = models.CharField(max_length=255, choices=settings.CATEGORIES)

class Product(models.Model):
    ...
    categories = models.ManyToManyField(Category)

I have the list of categories, entered by user (format is arbitrary):

c = [<Category: G, type: producer>, <Category: L, type: producer>, <Category: Teen, type: age>, <Category: Man, type: sex>]

Now I want to have all products that in categories have 'G' or 'L' with type 'producer', 'Teen' with type 'age' and 'Man' with type 'sex'. I'm doing for example next queryset:

Product.objects.filter(Q(categories=c[0])|Q(categories=c[1]), Q(categories=c[2]), Q(categories=c[3])

that have such query:

SELECT "shop_product"."id", "shop_product"."title", "shop_product"."description",
"shop_product"."price", "shop_product"."code", "shop_product"."stored_count",
"shop_product"."sold_count", "shop_product"."added_date" FROM "shop_product"
INNER JOIN     "shop_product_categories" ON ("shop_product"."id" =   
"shop_product_categories"."product_id")    WHERE 
(("shop_product_categories"."category_id" = 1 OR 
"shop_product_categories"."category_id" = 2) AND    
"shop_product_categories"."category_id" = 4 AND 
"shop_product_categories"."category_id" = 6)

I have at least one objects, that suits such requirements, but queryset returns nothing. Any suggests?

Was it helpful?

Solution

You need to do cascading filtering, otherwise the current select will return all products that have "shop_product_categories"."category_id" with value of 1/2 and 4 and 6 at the same time... Here is an example queryset that will return what you want:

Product.objects.filter(categories__in=c[0:2])
               .filter(categories=c[2])
               .filter(categories=c[3])
               .distinct()

Which generates SQL like this:

SELECT DISTINCT "test1_product"."id" FROM "test1_product" INNER JOIN "test1_product_categories" ON ("test1_product"."id" = "test1_product_categories"."product_id") 
    INNER JOIN "test1_product_categories" T4 
        ON ("test1_product"."id" = T4."product_id")
    INNER JOIN "test1_product_categories" T6 
        ON ("test1_product"."id" = T6."product_id") 
WHERE ("test1_product_categories"."category_id" IN (1, 2) 
    AND T4."category_id" = 3 
    AND T6."category_id" = 4 )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top