2011-02-02 17 views
18

施行のManyToManyFieldユニークなアイテム:ジャンゴ - 私はこのような単純なものをやろうとしている

members = models.ManyToManyField(User,blank=True,null=True,unique=True) 

が、ユニークは許可されていません。作成されたテーブルを見ると、それは外来キーを作るので一意性が暗示されます。

グループを表すこのモデルにメンバーを関連付けることができます。グループにはメンバーはいない可能性がありますが、同じメンバーがグループに2回参加することはできません。

私はこれを試してやると例外がスローされると考えられますが、例外がスローされないようです。

def join(request,id): 
    user = request.user 
    mygroup = Group.objects.get(id=id) 
    mygroup.members.add(user) 
    mygroup.num_members+=1 
    mygroup.save() 

例外がスローされないため、num_membersが増分されます。重複したユーザーは、adminユーティリティーには表示されません。 add()は静かに失敗しますか?追加する前にユーザーが既に含まれているかどうかを確認するだけでいいですか?

ありがとうございます!

+0

は、なぜあなたは、ユーザーにグループからの外部キーをしませんか?この方法では、ユーザーは複数のグループに所属できますが、グループごとに1回だけ必要になります。 – Liorsion

+3

グループからユーザーへの 'ForeignKey'は、グループ内に1人のユーザーしか存在しないことを意味します。 'ForeignKey'はmany-to-oneです。 –

答えて

26

1つは、num_membersを使用しません。代わりに、会員数はmygroup.members.count()で確認できます。第二に、メンバーを複数回追加しても実際に複数回追加されるわけではないので、あなたは大丈夫です。 Userを指すmemberためGroup

ManyToManyFieldは、GroupUserに外部キーを持つ別のテーブル(group_group_usersようなもの)を用いて実施されます。ユーザーは複数のグループを持つことができ、グループには複数のユーザーを含めることができますが、同じ関係(つまり、外部キーを使用して一意になる)の場合は2行あることはできません。

使用法:

>>> group = Group.objects.get(pk=1) 
>>> user = User.objects.get(pk=1) 
>>> group.members.add(user) 
>>> # Worked fine as expected. Let's check the results. 
>>> group.members.all() 
[<User: foousername>] 
>>> group.members.add(user) 
>>> # Worked fine again. Let's check for duplicates. 
>>> group.members.all() 
[<User: foousername>] 
>>> # Worked fine. 
+0

これは私が探していたものです。なぜ私はIDを使用すべきではないのですか? – JPC

+0

@JPC - できますが、 'pk'を使うのは良い方法です。プライマリキーの名前が 'id'か' identity'かどうかにかかわらず、プライマリキーにマッピングされます。 – orokusaki

+0

@JPC - あ、それは 'id'です。メソッドパラメータとして 'id'を使用すべきでないのは、' id'がビルドインのPython関数であるからです。 – orokusaki

13

重複したユーザーは管理ユーティリティには表示されません。

これらは作成されていません。

add()は自動的に失敗しますか?

はい。

追加する前にユーザーが既に含まれているかどうかを確認するだけですか?

はい。またはその代わりに、手動でユーザーを数え、あなたはあなたのためだけに、データベースの数を持つことができます:

mygroup = Group.objects.filter(...).annotate(num_members=models.Count("members")) 

は、これは実際のモデルでnum_membersフィールドが不要になります。

また、関数のパラメータ名としてidを使用しないでください。

+0

P.S. 'mygroup.members.count()'は1つのSQLクエリを実行してカウントを取得します( 'SELECT COUNT(*)FROM ...')。一方、 'annotate'メソッドは' Group.objects.filter(...) 'を呼び出し、各グループのメンバ数を取得します。 'id'という名前のパラメータを持つと、同じ名前の組み込み関数が隠されます。 –

+0

ユーザが既に含まれているかどうかの確認は、concurency –

+0

で一般的に真であり、事前にチェックしてもエラーを捕捉する必要はなくなりません。ここでは、管理者を同時に使用することが重要です。そのような場合は、「あるユーザーがすでにグループに誰かを追加しても、他のユーザーがそのグループからそのユーザーを削除した場合、そのグループに他のユーザーがいなければグループかどうか? IMHO、答えは「問題ではない;これはユーザーレベルでの調整の失敗であり、それぞれの可能な結果は1人のユーザーにのみ正しい」 –

関連する問題