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

时间:2013-08-13 18:59:28

标签: python django postgresql orm model

我有两个不同的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。提前谢谢。

2 个答案:

答案 0 :(得分:2)

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

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)

这只会执行一个查询。

答案 1 :(得分:0)

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

请阅读有关自然联接的信息。 SQL natural join POSTGRES