简体   繁体   中英

Django Filter on between two different ManytoMany fields

I want to model a Cake with multiple Icings .
Each Icings has a flavor.
An Icing can belong to multiple Cakes so this needs to be a many-to-many relationship.

I achieved the requirement thourgh this model:

class Cake(models.Model):
     layers = models.ManyToManyField(Icing, through='CakeLayer')

class Icing(models.Model):
     flavour = models.CharField(max_length=200)

class CakeLayer(models.Model):
     cake = models.ForeignKey(Cake, on_delete=models.CASCADE)
     icing = models.ForeignKey(Icing, on_delete=models.CASCADE)
     order = models.IntegerField()

However, I want to query a cake which has a chocolate icing ontop of a vanila icing (ie chocolate_icing.order > vanila_icing.order )

I cannot achieve it through Django's ORM but its rather simple by SQL.

SELECT * FROM "cake" 
    INNER JOIN "cakelayer" i1 
        ON ("cake"."id" = "cakelayer"."cake_id") 
    INNER JOIN "cakelayer" i2 
        ON ("cake"."id" = "cakelayer"."cake_id") 
    WHERE (i1.order > i2.order 
        AND i1.icing.flavor="chocolate"
        AND i2.icing.flavor="vanila"
        )

I would rather write python code than inject SQL. Any idea how to convert this SQL to Django ORM syntax?

You can query for this with:

Cake.objects.filter(
    layers__flavour='vanilla'
).annotate(
    
).filter(
    layers__flavour='chocolate',
    cakelayer__order__gt=F('order')
)

Here we use .annotate(..) to obtain a reference to the layer that matches with vanilla, and then we can use that in the second join.

This will construct a query that looks like:

SELECT cake.id, cakelayer.order AS vorder
FROM cake
INNER JOIN cakelayer ON cake.id = cakelayer.cake_id
INNER JOIN icing ON cakelayer.icing_id = icing.id
INNER JOIN cakelayer T4 ON cake.id = T4.cake_id
INNER JOIN icing T5 ON T4.icing_id = T5.id
WHERE icing.flavour = vanilla
  AND 
  AND T5.flavour = chocolate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM