跨多值关联
当基于 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,
),
)