2015-10-13 11 views
5

明らかに何かが不足している可能性がありますが、Djangoアプリケーションで動作するManyToManyフィールドの結合を取得できません。あなたが見ることができるようにDjangoでprefetch_relatedを使用してManyToManyフィールドに結合する

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

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 

結果のデータセットは、次のようになります。

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

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

私の目標は、このクエリと同等のものを持っていることです。私は2つのモデルを持っています例、私の役割アイテムは、各エリアにつき2回表示されます。私は領域のリストを取得し、それぞれの役割のリストを得ることができることを知っていますが(N + 1のクエリの結果)、可能であれば効率的にしたいと思います。そのように、私はprefetch_relatedが私が使用したかったかもしれないことを発見しました。しかし、これを使うと、すべてのAreaの値はなしとなります。私が試したことは次のとおりです。

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)) 

ロール名は正しく乗っていますが、エリア名は正しくありません。私はここで間違って何をしていますか?

+0

無関係:なぜ 'areas = ManyToManyField( 'Area'、...)'の中に 'Area'を引用符で囲んでいますか? – Pynchia

+1

'print("エリア名: "+ str(r.areas__name))'あなたは 'print("エリア名: "+ str(r.areas.name))'を意味しましたか? – danielcorreia

+1

@Pynchiaこの場合、領域はロールモデルの前に定義されているため、引用符なしでAreaを使用できます。 Roleの後にAreaが定義されている場合は、引用符が必要です。 [完全な説明はこちら](https://docs.djangoproject.com/en/1.8/ref/models/fields/#lazy-relationships) – danielcorreia

答えて

5

ロールrの場合、r.areas__nameにアクセスすることはできません。まだr.areas.all()でロールにアクセスする必要があります。ただし、prefetch_relatedを使用すると、O(n)クエリではなく、1つの追加クエリですべての関連オブジェクトを取得できます。

地域名で注文したいので、クエリーセットにAreaモデルを使用し、関連する役割をループする必要があります。

限り Roleモデルは、デフォルトでは nameが注文されたとして、あなたが望む順序を与える必要があり
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 

。そうでない場合は、Prefetchオブジェクトを使用して、関連するクエリーセットを注文することができます。

関連する問題