2009-06-01 7 views
12

私はPeopleのモデルを持つDjangoアプリケーションを作成しています。私は多対多の関係を使用する人々に役割オブジェクトを割り当てます。役割には名前と重みがあります。最も重い役割を果たしている人のリストを注文したいと思っています。 People.objects.order_by( ' - roles__weight')を実行すると、複数のロールが割り当てられているときに重複が発生します。Django:多対多のフィールドでモデルを注文してください

私の最初のアイデアは、と呼ばれる非正規化フィールドを追加して、最も重い役割の重みとしました。これは、新しい役割がユーザーに追加または削除されるたびに更新されます。しかし、ManyToManyFieldがDjangoで更新されるたびにカスタムアクションを実行する方法がないことが判明しました(とにかくyet)。

だから私は完全に船に乗ってこれを扱うためのカスタムフィールド、記述子、マネージャーを書くことができると思っていましたが、ManyRelatedManagerがManyToManyFieldに対して動的に作成されると非常に困難です。

私はこれを行うことができる賢明なSQLを思いついたことがあります。サブクエリ(またはいくつか)で可能だと確信していますが、互換性がないことが心配ですデータベースバックエンドのDjangoがサポートしています。

誰もこれまでにこれをやったことがありますか、それを達成する方法はありますか?

select p.*, max (r.Weight) as HeaviestWeight 
from persons p 
inner join RolePersons rp on p.id = rp.PersonID 
innerjoin Roles r on rp.RoleID = r.id 
group by p.* 
order by HeaviestWeight desc 

注:Pによるグループ* SQLのあなたの方言で禁止することができる。SQLでこのよう

答えて

11

Django 1.1(現在ベータ版)にはaggregationが追加されています。あなたのクエリのようなものを行うことができます。

from django.db.models import Max 
People.objects.annotate(max_weight=Max('roles__weight')).order_by('-max_weight') 

これは、重複を返さずに、その最も重い役割によって人々をソートします。

生成されたクエリは次のとおりです。

SELECT people.id, people.name, MAX(role.weight) AS max_weight 
FROM people LEFT OUTER JOIN people_roles ON (people.id = people_roles.people_id) 
      LEFT OUTER JOIN role ON (people_roles.role_id = role.id) 
GROUP BY people.id, people.name 
ORDER BY max_weight DESC 
+0

class Role(models.Model): pass class PersonRole(models.Model): weight = models.IntegerField() person = models.ForeignKey('Person') role = models.ForeignKey(Role) class Meta: # if you have an inline configured in the admin, this will # make the roles order properly ordering = ['weight'] class Person(models.Model): roles = models.ManyToManyField('Role', through='PersonRole') def ordered_roles(self): "Return a properly ordered set of roles" return self.roles.all().order_by('personrole__weight') 

これはあなたのような何かを言うことができます探している。私はDjango 1.1を実行していませんが、私はカスタムマネージャーでそのSQLを使用できます。ありがとう:) –

1

何か。その場合は、select句で使用する予定の表pのすべての列をリストするだけです。

注:p.IDでグループ化するだけでは、select句でpの他の列を呼び出すことはできません。

これはDjangoとのやりとりがわかりません。

6

は、ここで注釈なしでそれを行う方法です:私がしただけで何

>>> person = Person.objects.get(id=1) 
>>> roles = person.ordered_roles() 
関連する問題