简体   繁体   English

在Django中使用prefetch_related连接ManyToMany字段

[英]Joining ManyToMany fields with prefetch_related in Django

I may be missing something obvious, but I'm having trouble getting a join on a ManyToMany field to work in a Django app. 我可能会遗漏一些明显的东西,但是我无法在ManyToMany字段上加入Django应用程序。 I have two models: 我有两个型号:

class Area(models.Model):
    name = CharField(...)

class Role(models.Model):
    name = CharField(...)
    areas = ManyToManyField('Area', ...)

My goal is to have the equivalent of this query: 我的目标是拥有相当于这个查询:

select a.name, r.name
from area a
join area_role ar on ar.area_id = a.id
join role r on ar.role_id = r.id
order by a.name, r.name

The resulting data set would look like: 结果数据集如下所示:

Area    Role
---------------------
A       My Role
A       Your Role
A       Yo Mamas Role
B       My Role
B       Some Other Role

As you can see in the example, the My Role item appears twice, once for each area. 正如您在示例中所看到的,“ 我的角色”项目出现两次,每个区域出现一次。 I know I could get the list of areas and then get a list of roles for each (resulting in N+1 queries), but I'd like to be efficient about it if possible. 我知道我可以得到区域列表,然后获得每个区域的角色列表(产生N + 1个查询),但是如果可能的话我想要有效率。 As such, I found that prefetch_related might be what I wanted to use. 因此,我发现prefetch_related可能是我想要使用的。 When I use this, however, I end up with all Area values as None . 但是,当我使用它时,我最终将所有Area值都设置为None Here's what I tried: 这是我试过的:

rqs = ( Role.objects.filter(areas__id__in=[1,2,3])
        .prefetch_related(areas).order_by('areas__name', 'name') )

for r in rqs:
    print("Area Name: " + str(r.areas.name))
    print("Role Name: " + str(r.name))

The role names come along for the ride correctly, but the area names do not. 角色名称正确用于骑行,但区域名称没有。 What am I doing wrong here? 我在这做错了什么?

It isn't possible to access r.areas__name for a Role r . 无法访问角色r r.areas__name You still have to access the roles via r.areas.all() . 您仍然必须通过r.areas.all()访问角色。 However, by using prefetch_related , you fetch all the related objects in one extra query, instead of O(n) queries. 但是,通过使用prefetch_related ,您可以在一个额外查询中获取所有相关对象,而不是O(n)查询。

Since you want to order by area name, you should probably use the Area model for your queryset, then loop through the related roles. 由于您希望按区域名称排序,因此您应该使用Area模型作为查询集,然后循环执行相关角色。

areas = Area.objects.filter(id__in=[1, 2, 3]).order_by('name').prefetch_related('role_set')

for area in areas:
    roles = area.role_set.all()
    for role in roles:
        print area.name, roles.name

That should give you the ordering you want, as long as the Role model is ordered by name by default. 这应该为您提供所需的顺序,只要默认情况下按name排序Role模型。 If not, you could use a Prefetch object to order the related queryset. 如果没有,您可以使用Prefetch对象来订购相关的查询集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM