首页 > 解决方案 > Django 使用 Q 和 Or 过滤 ManyToMany

问题描述

class State(models.Model):
    name = models.CharField(max_length=55, unique=True)

class City(models.Model):
    name = models.CharField(max_length=255)
    states = models.ManyToManyField(State, related_name='cities')
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='children', blank=True)

我有一个州,我想查找父州为空或其父州不包含州的城市。

我试过state.cities.filter(Q(parent=None) | ~Q(parent__states=state))但它不起作用,我的查询很奇怪:

`SELECT "city"."id", "city"."name", "city"."parent_id", FROM "city" INNER JOIN "city_states" ON ("city"."id" = "city_states"."city_id") WHERE ("city_states"."state_id" = 7 AND ("city"."parent_id" IS NULL OR NOT ("city"."parent_id" IN (SELECT U2."city_id" FROM "city_states" U2 WHERE (U2."state_id" = 7 AND U2."id" = "city_states"."id")) AND "city"."parent_id" IS NOT NULL))) ORDER BY "city"."name" ASC`

特别是代码AND U2."id" = "city_states"."id"执行什么?

标签: djangodjango-modelsdjango-queryset

解决方案


您可以在这里简单地使用.exclude(…)[Django-doc]

state.cities.exclude(
    parent__states=state
)

parent如果是None/ ,这仍然有效NULL,因为那时parent__states=state不成立。

这将构造一个如下所示的查询:

SELECT app_name_city.*
FROM app_name_city
WHERE NOT (
    app_name_city.parent_id IN (
        SELECT U2.city_id
        FROM `app_name_city_states U2
        WHERE U2.state_id = id_of_state
    )
    AND app_name_city.parent_id IS NOT NULL
)

因此,子查询为给定的州制作了一个城市列表,因此我们要求该城市有一个不在这些州中的任何一个城市。


推荐阅读