Django ORM - 不同表中行的部分匹配

Posted

技术标签:

【中文标题】Django ORM - 不同表中行的部分匹配【英文标题】:Django ORM - partial match of rows in different tables 【发布时间】:2013-08-15 12:54:06 【问题描述】:

我有两个不同的 Django 模型,“modelA”和“modelB”,它们只有两个共同的列:“EMAIL”和“NAME”,每个模型中的其余列都不同。我想从“modelA”返回一个对象列表,但在“modelB”中不包含重复的“EMAIL”和“NAME”组合...

例如,如果“modelA”有以下对象:

EMAIL             NAME       SOMEFIELD
bob@email.com     Bob        ....
bob@email.com     Robert     ....

并且“modelB”有对象:

EMAIL             NAME       ADIFFERENTFIELD
bob@email.com     Bob        ....
sammy@email.com   Sam        ....
bob@email.com     Bobby      ....

我希望最终的“modelA”查询集只返回:

EMAIL             NAME       SOMEFIELD
bob@email.com     Robert     ....

执行此 Django 的最有效方法是什么?我现在能想到的最佳解决方案是获取“modelA”查询集并遍历每个对象以测试“modelB”中是否存在相同的“EMAIL”和“NAME”组合,如果不存在,添加该对象到一个新列表。这听起来非常低效。尽管我对 Django 的经验很少,但我知道一定有更好的方法 :) 如果相关,我的数据库正在使用 PostgreSQL。提前致谢。

【问题讨论】:

【参考方案1】:

您只需两个查询即可完成此操作:

from django.db.models import Q

b_models = modelB.objects.values('email', 'name')
exclude = Q()
for model in b_models:
    exclude |= (Q(email=model['email']) & Q(name=model['name']))

a_models = modelA.objects.exclude(exclude)

Q 对象允许将过滤器与简单的二元运算符组合(&|~ 用于 SQL 的 ANDORNOT)。这将排除 modelB 表中已存在的任何电子邮件和姓名对。

如果您要按单个属性(例如电子邮件)进行过滤,您可以这样做:

emails = modelB.objects.values_list('email', flat=True)
a_models = modelA.objects.exclude(email__in=emails)

这将只执行一个查询。

【讨论】:

【参考方案2】:

最有效的将是原始查询。你当然会尝试使用 Q 或聚合,但是 django 并不会生成纯粹快速的 sql。

请阅读自然连接。 SQL natural join POSTGRES

【讨论】:

以上是关于Django ORM - 不同表中行的部分匹配的主要内容,如果未能解决你的问题,请参考以下文章

Django基础之django ORM单表操作

Django基础之django ORM单表操作

Django vs SQLAlchemy:哪个 Python ORM 更好

Django开发:(3.1)ORM:单表操作

Django之orm查询

Django的orm操作数据库