2011-02-02 3 views
18

시행 ManyToManyField 고유 항목 :장고 -이 같은 간단한 일을 할 노력하고있어

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

만의 고유은 허용되지 않습니다. 생성 된 테이블을 보았을 때 외래 키가 고유하므로 고유 키가 상상됩니다.

그룹을 나타내는이 모델에 회원을 연결할 수 있기를 원합니다. 그룹에는 회원이 없어도 동일한 회원이 그룹에 두 번 가입 할 수 있기를 원하지 않습니다.

제 생각에는 시도하고 시도하면 예외가 발생하지만 예외가 발생하지 않는 것 같습니다.

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가 증가합니다. 중복 된 사용자는 관리 유틸리티에 나타나지 않습니다. add()가 자동으로 실패합니까? 추가하기 전에 이미 사용자가 포함되어 있는지 단순히 확인해야합니까?

감사합니다.

+0

? 이 방법으로 사용자는 여러 그룹에있을 수 있지만 각 그룹에서 한 번만 - 원하는 것입니다. – Liorsion

+3

그룹에서 사용자로의 'ForeignKey'는 그룹에 사용자가 하나만 있음을 의미합니다. 'ForeignKey'는 many-to-one입니다. –

답변

26

하나는 num_members입니다. 대신, 얼마나 많은 회원이 mygroup.members.count()인지 확인할 수 있습니다. 둘째, 구성원을 두 번 이상 추가한다고해서 실제로 두 번 이상 추가되지 않으므로 괜찮습니다. User

member 포인팅을위한 GroupManyToManyFieldGroupUser에 외래 키가있는 별도의 테이블 (group_group_users 같은)로 구현된다. 사용자는 여러 그룹을 가질 수 있으며 그룹은 여러 사용자를 가질 수 있지만 동일한 관계 (즉, 고유 한 외래 키와 함께)에 대해 group_group_users에는 두 개의 행이있을 수 없습니다.

사용법 :

당신이 사용자에게 그룹에서 외부 키를하지 않는 이유는
>>> 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

이것이 내가 찾고 있던 것입니다. 왜 나는 이드를 사용하지 말아야 하는가? – JPC

+0

@JPC - 할 수 있지만'pk'를 사용하는 것이 좋습니다. 기본 키의 이름이 "id"인지 "identity"인지 여부와 관계없이 기본 키에 매핑됩니다. – orokusaki

+0

@JPC - 아, 그 id입니다. 메소드 매개 변수로'id'를 사용하지 말아야하는 이유는'id'가 빌트인 파이썬 함수이기 때문입니다. – orokusaki

13

중복 사용자는 admin 유틸리티에 표시되지 않습니다.

생성되지 않았습니다.

add()가 자동으로 실패합니까?

예.

추가하기 전에 이미 사용자가 포함되어 있는지 확인하면됩니까?

예. 또는 대신 수동으로 사용자를 계산, 당신은 당신을 위해 데이터베이스 수를 할 수 :

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

이 실제 모델의 num_members 필드에 대한 필요가 없습니다.

또한 함수에 대한 매개 변수 이름으로 id을 사용하지 않아야합니다.

+0

P. 'mygroup.members.count()'는 하나의 SQL 질의를 실행하여 count ('SELECT COUNT (*) FROM ... ')를 얻는 반면'annotate' 메소드는' Group.objects.filter (...)'를 실행하고 각 그룹에 대한 멤버 수를 얻습니다. 모두 그룹당 하나가 아닌 하나의 SQL 쿼리로 이루어집니다. 그리고'id'라는 매개 변수를 가지고 있으면 같은 이름의 내장 함수를 숨 깁니다. –

+0

사용자가 이미 포함되어 있는지 확인하면 concurency –

+0

으로 인해 정상적으로 작동하지 않을 수 있으며 사전에 확인해도 오류를 잡을 필요가 없습니다. 여기에서는 관리자를 동시에 사용할 수 있습니다. 그렇다면 "한 사용자가 이미 그룹에 누군가를 추가하면 그 동안 다른 사용자가 그 그룹에서 누군가를 제거합니다. 그룹 이냐 아니냐? " IMHO, 대답은 "중요하지 않습니다. 이것은 사용자 수준에서의 조정 실패이며 각 가능한 결과는 한 명의 사용자에게만 정확합니다." –

관련 문제