带有多个相关字段子句的 Django 查询集 exclude()

标签 django django-orm

我正在 Django 中创建一个稀疏的首选项表。我的模型很简单:

class Preference(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='preferences')
    preference = models.CharField(max_length=255, db_index=True)
    value = models.BooleanField()

某些首选项具有默认状态,因此我需要能够向数据库提出两个问题:“哪些用户将此首选项设置为某个值?”以及“哪些用户没有将此偏好设置为该值(因为他们没有设置偏好,或者因为他们主动将偏好设置为另一个值)?”

我的问题是前一个问题有效,但后一个问题(相同的查询子句,但使用 exclude() 而不是 filter() )不起作用。例如:

我的测试数据库有 14 个用户,单个用户设置了两个首选项:'PREF_A'设置为 True'PREF_B'设置为 False .
>>> User.objects.all().count()
14
>>> User.objects.filter(preferences__preference="PREF_A", preferences__value=True).count()
1
>>> User.objects.exclude(preferences__preference="PREF_A", preferences__value=True).count()
13
>>> User.objects.filter(preferences__preference="PREF_A", preferences__value=False).count()
0
>>> User.objects.exclude(preferences__preference="PREF_A", preferences__value=False).count()
13

所以,我的结果是:

共有 14 个用户
  • 1 个用户将 PREF_A 设置为 True
  • 13 个用户没有将 PREF_A 设置为 True
  • 0 个用户将 PREF_A 设置为 False
  • 13 个用户没有将 PREF_A 设置为 False <--- 这是不准确的

  • 此查询哪里出错了,我如何编写查询以正确排除将特定首选项设置为特定值的人?

    我试过使用 Q~Q看看行为是否会有所不同,但结果是一样的。

    最佳答案

    这是 Django 中仍然存在的问题,其中 exclude()不作为 filter() 的反面.这是the documentation explaining the difference :

    Note

    The behavior of filter() for queries that span multi-value relationships, as described above, is not implemented equivalently for exclude(). Instead, the conditions in a single exclude() call will not necessarily refer to the same item.

    For example, the following query would exclude blogs that contain both entries with “Lennon” in the headline and entries published in 2008:

    Blog.objects.exclude(
        entry__headline__contains='Lennon',
        entry__pub_date__year=2008,
    )
    

    However, unlike the behavior when using filter(), this will not limit blogs based on entries that satisfy both conditions. In order to do that, i.e. to select all blogs that do not contain entries published with “Lennon” that were published in 2008, you need to make two queries:

    Blog.objects.exclude(
        entry__in=Entry.objects.filter(
            headline__contains='Lennon',
            pub_date__year=2008,
        ),
    )
    

    你所做的可能是要走的路。

    关于带有多个相关字段子句的 Django 查询集 exclude(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16704560/

    相关文章:

    django - 如何在 axios POST 请求中附加 csrf header 和值

    django - 使用 Django RelatedField 进行自定义连接查询?

    python - 外键的复杂 Django 查询

    python - 如何在 django orm 中使用过滤器值作为变量

    python - Django - 有没有办法获取当前数据库别名?

    MySQL 不为外键创建索引

    python - django-mssql - 无效的连接字符串属性

    Django - 检查两个密码哈希是否具有相同的原始密码

    python - celery 不采摘 CELERY_ALWAYS_EAGER 设置

    javascript - Django 管理员 : Alter how data is displayed