一定有一种方法可以通过 ORM 执行此查询,但我没有看到它。
设置
这就是我正在建模的内容:一名租户可以占用多个房间,一名用户可以拥有多个房间。因此,房间有一个针对租户的 FK 和针对用户的 FK。房间也由(可能不同的)用户维护。
也就是说,我有这些(简化的)模型:
class Tenant(models.Model):
name = models.CharField(max_length=100)
class Room(models.Model):
owner = models.ForeignKey(User)
maintainer = models.ForeignKey(User)
tenant = models.ForeignKey(Tenant)
给定租户的问题
,我希望用户拥有他们占用的房间。
相关的 SQL 查询将是:
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;
从相关的 User 对象中获取任何单独的值可以使用 my_tenant.rooms.values_list('owner__email', flat=True) 来完成,但是获取完整的值用户的查询集让我很困惑。
通常解决此问题的一种方法是在我的 Tenant
模型上设置一个 ManyToMany
字段,指向 User
和 TenantRoom
> 作为“通过”模型。但在这种情况下,这不起作用,因为 TenantRoom
模型有第二个(不相关的)ForeignKey
到 User
(请参阅“限制” )。另外,租户模型上似乎出现了不必要的混乱。
执行 my_tenant.rooms.values_list('user', flat=True)
让我很接近,但返回的是用户 ID 的 ValuesListQuerySet,而不是实际 User 对象的查询集。
问题
那么:有没有一种方法可以通过 ORM 仅使用一个查询来获取实际模型实例的查询集?
编辑
如果事实上没有办法通过 ORM 在一个查询中直接执行此操作,那么最好的方法是什么(性能最佳、最惯用、最具可读性等的某种组合)实现我正在寻找的东西?以下是我看到的选项:
-
子选择
users = User.objects.filter(id__in=my_tenant.rooms.values_list('user'))
通过 Python 子选择(参见 性能考虑背后的推理)
user_ids = id__in=my_tenant.rooms.values_list('用户')
用户 = User.objects.filter(id__in=list(user_ids))
-
原始 SQL:
User.objects.all("""SELECT auth_user.*
来自租户_租户、租户_房间、auth_用户
其中租户_租户.id = 租户_房间.租户_id
AND租户_room.owner_id = auth_user.id""")
-
其他...?
There must be a way to do this query through the ORM, but I'm not seeing it.
The Setup
Here's what I'm modelling: one Tenant can occupy multiple rooms and one User can own multiple rooms. So Rooms have an FK to Tenant and an FK to User. Rooms are also maintained by a (possibly distinct) User.
That is, I have these (simplified) models:
class Tenant(models.Model):
name = models.CharField(max_length=100)
class Room(models.Model):
owner = models.ForeignKey(User)
maintainer = models.ForeignKey(User)
tenant = models.ForeignKey(Tenant)
The Problem
Given a Tenant, I want the Users owning a room which they occupy.
The relevant SQL query would be:
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;
Getting any individual value off the related User objects can be done with, for example, my_tenant.rooms.values_list('owner__email', flat=True)
, but getting a full queryset of Users is tripping me up.
Normally one way to solve it would be to set up a ManyToMany
field on my Tenant
model pointing at User
with TenantRoom
as the 'through' model. That won't work in this case, though, because the TenantRoom
model has a second (unrelated) ForeignKey
to User
(see "restictions"). Plus it seems like needless clutter on the Tenant model.
Doing my_tenant.rooms.values_list('user', flat=True)
gets me close, but returns a ValuesListQuerySet of user IDs rather than a queryset of the actual User objects.
The Question
So: is there a way to get a queryset of the actual model instances, through the ORM, using just one query?
Edit
If there is, in fact, no way to do this directly in one query through the ORM, what is the best (some combination of most performant, most idiomatic, most readable, etc.) way to accomplish what I'm looking for? Here are the options I see:
-
Subselect
users = User.objects.filter(id__in=my_tenant.rooms.values_list('user'))
-
Subselect through Python (see Performance considerations for reasoning behind this)
user_ids = id__in=my_tenant.rooms.values_list('user')
users = User.objects.filter(id__in=list(user_ids))
-
Raw SQL:
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""")
-
Others...?
发布评论
评论(1)
正确的方法是使用
lated_name
:然后你可以这样做:
The proper way to do this is with
related_name
:Then you can do this: