Django orm跨多值关联,链式调用filter/exclude数据与预期不符合问题

跨多值关联

当基于 ManyToManyField 或反向 ForeignKey 筛选某对象时,设 Blog/Entry 关联关系(Blog 对 Entry 是一种一对多关联关系)

Django 有一套统一的方式处理 filter() 调用。配置给某次 filter() 的所有条件会在调用时同时生效。

以下例子使用的models,如果需要验证的

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=32, null=False, blank=False)


class Entry(models.Model):
    headline = models.CharField(max_length=32, null=False, blank=False)
    pub_date = models.DateField(null=True, blank=True)

    blog = models.ForeignKey(Blog, related_name="entry", on_delete=models.CASCADE)

Filter

一. 对于多值关联来说,限制条件作用于链接至主模型的对象,而不一定是那些被前置 filter() 调用筛选的对象

例如:

Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)

两段链式调用,都是作用域Blog模型,

第一个过滤器限制结果集为那些关联了标题包含 "Lennon" 的条目的博客。

第二个过滤器进一步要求结果集中的博客要发布于 2008 年。

第二个过滤器筛选的条目与第一个过滤器筛选的可能不尽相同。我们是用过滤器语句筛选 Blog,而不是 Entry

所以这条orm将筛选出包含 标题为"Lennon" 的博客条目发布于 2008 年的博客(并不是同时包含标题为Lennon 的博客和发布于 2008 年

举个例子:

Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
<QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (2)>]>

1,Blog和Entry是一对多关系,需要查询blog下 entry的headline包含lennon和pub_data__year=2008

2, Entry<id=3> 这条数据包含lennon  ,Entry<id=2> 这条数据 pub_data__year=2008,它们都是关联 Blog<id=2>

3,所有 结果是`<QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (2)>]>`

4, 结论 这条orm将筛选出包含 标题为"Lennon" 的博客条目发布于 2008 年的博客(并不是同时包含标题为Lennon 的博客和发布于 2008 年

二.那么要实现标题含有 标题为"Lennon" 且发布于 2008 (同一个条目,同时满足两个条件)年的博客

例如:

Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
Blog.objects.filter(entry__headline__contains='Lennon',entry__pub_date__year=2008)
<QuerySet [<Blog: Blog object (1)>]>

Exclude

一. filter() 的查询行为会跨越多值关联,就像前文说的那样,但 exclude() 不是这样。

例如:

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

查询出排除那些关联条目标题包含 "Lennon" 和同时满足有发布于 2008 年的博客

(只要多条数据中一条满足一个过滤条件即可,但必须是要有两种满足)

但并不会限制博客同时满足这两种条件NOT(id in A ∩ id in B)

举个例子:

数据同上

Blog.objects.exclude(
    entry__headline__contains='Lennon',
    entry__pub_date__year=2008,
)
<QuerySet [<Blog: Blog object (3)>]>

1. 这个语句并不是排除同时满足这两种条件的

2. 从结果看来<QuerySet [<Blog: Blog object (3)>]>,只查到这一条

3,Blog<id=2> 是一条Entry<id=2>满足entry__pub_date__year=2008,一条满足entry__headline__contains='Lennon'

二. 那么要满足 多条数据中一条满足一个过滤条件即可,但不必须是要有两种满足,实现如下:NOT id in A and NOT id in B

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

3. 那么要满足同时两种条件(在同一条目满足两个条件)实现如下:NOT (id in (A and B))

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值