Kry*_*ski 52 django django-models django-orm
我有两个这样的模型:
class User(models.Model):
email = models.EmailField()
class Report(models.Model):
user = models.ForeignKey(User)
Run Code Online (Sandbox Code Playgroud)
实际上,每个模型都有更多的字段,这些字段与此问题无关.
我想过滤所有拥有以"a"开头并且没有报告的电子邮件的用户.将有更多.filter()和.exclude()基于其他领域的标准.
我想这样做:
users = User.objects.filter(email__like = 'a%')
users = users.filter(<other filters>)
users = ???
Run Code Online (Sandbox Code Playgroud)
我想要 ???过滤掉没有与之关联的报告的用户.我该怎么做?如果这不可能像我提出的那样,那么另一种方法是什么?
Ala*_*air 84
使用isnull.
users_without_reports = User.objects.filter(report__isnull=True)
users_with_reports = User.objects.filter(report__isnull=False).distinct()
Run Code Online (Sandbox Code Playgroud)
使用时isnull=False,distinct()需要防止重复结果.
Sto*_*ica 24
Django 1.11中的新增功能,您可以添加EXISTS子查询:
User.objects.annotate(
no_reports=~Exists(Reports.objects.filter(user__eq=OuterRef('pk')))
).filter(
email__startswith='a',
no_reports=True
)
Run Code Online (Sandbox Code Playgroud)
这会生成如下所示的SQL:
SELECT
user.pk,
user.email,
NOT EXISTS (SELECT U0.pk FROM reports U0 WHERE U0.user = user.pk) AS no_reports
FROM user
WHERE email LIKE 'a%' AND NOT EXISTS (SELECT U0.pk FROM reports U0 WHERE U0.user = user.pk);
Run Code Online (Sandbox Code Playgroud)
一个NOT EXISTS条款几乎总是做一个"不存在"过滤器的最有效的方式.
一旦#25367发布,您将能够~Exists()直接在a中使用.filter(),避免重复条款.
Yur*_*rov 11
在没有额外查询或JOIN的情况下获取本机SQL EXISTS/NOT EXISTS的唯一方法是在.extra()子句中将其添加为原始SQL:
users = users.extra(where=[
"""NOT EXISTS(SELECT 1 FROM {reports}
WHERE user_id={users}.id)
""".format(reports=Report._meta.db_table, users=User._meta.db_table)
])
Run Code Online (Sandbox Code Playgroud)
事实上,这是一个非常明显和有效的解决方案,我有时想知道为什么它不是作为查找内置到Django.此外,它还允许细化子查询以查找例如仅在上周用[out]报告的用户,或者[out]未答复/未查看的报告.
除了@OrangeDog 的回答。从 Django 3.0 开始,您可以使用Exists子查询直接过滤查询集:
User.objects.filter(
~Exists(Reports.objects.filter(user__eq=OuterRef('pk'))
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31257 次 |
| 最近记录: |