classPerson(models.Model): name = models.CharField(max_length=128) def__str__(self): return self.name classGroup(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') # through="Membership" 을 넣어줌으로, # Membership 이 Person 과 Group 사이의 중간 모델 역할을 하게 만들수 있음 def__str__(self): return self.name
classMembership(models.Model): # 중간 모델에서는, Person과 Group이 ForeignKey 로 등록 되어 있어야 함 person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
만약 중간 모델에 의해서, through 테이블이 커스텀 정의가 되었는데, (model1, model2 ) 페어에 강제적으로 고유성을 요구하지 않고, 다중의 값을 허용한다면, remove() 를 호출해서 모든 중간 모델 인스턴스들을 제거할수 있습니다.
1 2 3 4 5 6 7 8 9 10
In [14]: Membership.objects.create(person=ringo, group=beatles, date_joined=datetime.datetime(1968, 9, 4), invite_reason="You've been gone for a month and we miss you.") Out[14]: <Membership: Membership object (9)>
In [15]: beatles.members.all() Out[15]: <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: George Harrison>, <Person: Ringo Starr>]>
In [16]: beatles.members.remove(ringo)
In [17]: beatles.members.all() Out[17]: <QuerySet [<Person: Paul McCartney>, <Person: George Harrison>]>
clear() 메서드는,
하나의 인스턴스를 위한 모든 Many-to-Many 관계들을 없애줍니다.
1 2 3 4 5 6 7 8
In [18]: # 비틀즈가 해산
In [19]: beatles.members.clear()
In [20]: # 이 방식은 중간 모델 인스턴스를 삭제해줍니다
In [21]: Membership.objects.all() Out[21]: <QuerySet []>
한번 many-to-many 관계를 성립하였으면, 쿼리들을 발행할수 있습니다. 보통의 many-to-many 관계와 같이, many-to-many 로 관계된 모델들의 속성들을 사용하여 쿼리를 사용할수 있습니다.
1 2 3 4
# 멤버의 이름이 'Paul' 로 시작하는 그룹 찾기
In [39]: Group.objects.filter(members__name__startswith='Paul') Out[39]: <QuerySet [<Group: The Beatles>]>
중간 모델을 사용하면서, 중간 모델의 속성을 쿼리 조회 할수 있습니다.
1 2 3 4 5 6
# Person 중에, group 이름이 'The Beatles' 이면서 # Membership에 든 날짜가 1961년 1월 1일 보다 이후인 객체를 조회 In [40]: Person.objects.filter( ...: group__name='The Beatles', ...: membership__date_joined__gt=datetime.datetime(1961, 1, 1)) Out[40]: <QuerySet [<Person: Ringo Starr>]>
membership 의 정보를 바로 접근하고 싶으면,
바로 Membership 모델에 쿼리를 보내면 됩니다.
1 2 3 4 5 6 7
In [41]: ringos_membership = Membership.objects.get(group=beatles, person=ringo)
In [42]: ringos_membership.date_joined Out[42]: datetime.date(1962, 8, 16)
In [43]: ringos_membership.invite_reason Out[43]: 'Needed a new drummer.'
Person 객체에서 부터 거꾸로 가는
Many-To-Many reverse 관계도 존재합니다
1 2 3 4 5 6 7
In [44]: ringos_membership = ringo.membership_set.get(group=beatles)
In [45]: ringos_membership.date_joined Out[45]: datetime.date(1962, 8, 16)
In [46]: ringos_membership.invite_reason Out[46]: 'Needed a new drummer.'
마치며..
공식문서가 예시도 너무 불충분하고,, 뭐라 설명은 하는지는 잘 모르겠습니다.
다음 포스팅에서는, ManyToMany 예제를 좀 들어서, 데이터베이스 검색 및 쿼리문 사용을 좀 연습 해봐야 할것 같습니다.