Gab*_*ant 5 python django django-models django-orm django-queryset
必须有办法通过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)
Run Code Online (Sandbox Code Playgroud)
给定租户,我希望用户拥有他们占据的房间.
相关的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;
Run Code Online (Sandbox Code Playgroud)
例如,可以使用相关用户对象获取任何单个值my_tenant.rooms.values_list('owner__email', flat=True),但获取用户的完整查询集会让我感到沮丧.
通常一个方式来解决这将是建立一个ManyToMany场在我Tenant的模型指向User同TenantRoom为"到"模型.这将不会在这种情况下工作,虽然,因为TenantRoom模型具有第二(无关)ForeignKey到User(见"restictions").此外,它似乎是租户模型上的不必要的混乱.
做得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'))
Run Code Online (Sandbox Code Playgroud)通过Python进行子选择(有关此背后的推理,请参阅性能注意事项)
user_ids = id__in=my_tenant.rooms.values_list('user')
users = User.objects.filter(id__in=list(user_ids))
Run Code Online (Sandbox Code Playgroud)原始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""")
Run Code Online (Sandbox Code Playgroud)其他...?
执行此操作的正确方法是related_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)
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
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)
Run Code Online (Sandbox Code Playgroud)