Python 如何按照双连接关系在Django中执行查询(或者:如何绕过Django对许多“通过”模型的限制?)
一定有办法通过ORM进行查询,但我没有看到 设置 以下是我正在建模的内容:一个租户可以占用多个房间,一个用户可以拥有多个房间。因此,房间有一个FK到租户和一个FK到用户。房间也由(可能不同的)用户维护 也就是说,我有这些(简化的)模型: 问题 给定一个租户,我希望用户拥有他们所居住的房间 相关的SQL查询将是:Python 如何按照双连接关系在Django中执行查询(或者:如何绕过Django对许多“通过”模型的限制?),python,django,django-models,django-queryset,django-orm,Python,Django,Django Models,Django Queryset,Django Orm,一定有办法通过ORM进行查询,但我没有看到 设置 以下是我正在建模的内容:一个租户可以占用多个房间,一个用户可以拥有多个房间。因此,房间有一个FK到租户和一个FK到用户。房间也由(可能不同的)用户维护 也就是说,我有这些(简化的)模型: 问题 给定一个租户,我希望用户拥有他们所居住的房间 相关的SQL查询将是: SELECT auth_user.id, ... FROM tenants_tenant, tenants_room, auth_user WHERE tenants_tenant.id
SELECT auth_user.id, ...
FROM tenants_tenant, tenants_room, auth_user
WHERE tenants_tenant.id = tenants_room.tenant_id
AND tenants_room.owner_id = auth_user.id;
从相关用户对象中获取任何单个值都可以使用,例如,my\u tenant.rooms.values\u list('owner\u email',flat=True)
,但是获取完整的用户查询集让我很困惑
通常一种解决方法是在myTenant
模型上设置一个ManyToMany
字段,指向User
,将TenantRoom
作为“直通”模型。但是,在这种情况下,这不起作用,因为TenantRoom
模型有第二个(不相关的)ForeignKey
到User
()。此外,租户模型上似乎存在不必要的混乱
执行my_tenant.rooms.values\u list('user',flat=True)
可以让我接近,但会返回用户ID的ValuesListQuerySet,而不是实际用户对象的queryset
问题
那么:有没有一种方法可以通过ORM只使用一个查询来获取实际模型实例的查询集
编辑 如果事实上,没有办法通过ORM在一个查询中直接实现这一点,那么实现我所寻找的目标的最佳方式是什么(最高效、最惯用、最可读等的组合)?以下是我看到的选项:
users = User.objects.filter(id__in=my_tenant.rooms.values_list('user'))
User.objects.all("""SELECT auth_user.*
FROM tenants_tenant, tenants_room, auth_user
WHERE tenants_tenant.id = tenants_room.tenant_id
AND tenants_room.owner_id = auth_user.id""")
正确的方法是使用
related\u name
:
class Tenant(models.Model):
name = models.CharField(max_length=100)
class Room(models.Model):
owner = models.ForeignKey(User, related_name='owns')
maintainer = models.ForeignKey(User, related_name='maintains')
tenant = models.ForeignKey(Tenant)
然后你可以这样做:
jrb = User.objects.create(username='jrb')
bill = User.objects.create(username='bill')
bob = models.Tenant.objects.create(name="Bob")
models.Room.objects.create(owner=jrb, maintainer=bill, tenant=bob)
User.objects.filter(owns__tenant=bob)
哇!放屁。我的模型上已经有相关的_名称,但为了尽量减少示例,我将它们作为(我认为是)无关的细节删除。我一心想弄清楚如何跟踪关系向前发展,不知何故,我错过了从用户后退的所有显而易见的解决方案。谢谢你帮我澄清@kRON我认为需要
相关的\u名称
,因为房间模型上有两个FK供用户使用。默认情况下,Django将向用户模型添加一个room\u set
属性,当存在一个FK时,该属性可以正常工作,但当添加第二个FK时,该属性会变得不明确(我怀疑发生的情况是,第二个FK只是破坏了第一个分配的room\u set
,但我尚未检查以确认)经过数小时对文档的仔细阅读,您的回答终于向我展示了相关的名称。非常感谢你,杰夫!
class Tenant(models.Model):
name = models.CharField(max_length=100)
class Room(models.Model):
owner = models.ForeignKey(User, related_name='owns')
maintainer = models.ForeignKey(User, related_name='maintains')
tenant = models.ForeignKey(Tenant)
jrb = User.objects.create(username='jrb')
bill = User.objects.create(username='bill')
bob = models.Tenant.objects.create(name="Bob")
models.Room.objects.create(owner=jrb, maintainer=bill, tenant=bob)
User.objects.filter(owns__tenant=bob)