Django에서 Many To Many 필드 다루기

2019. 3. 27. 11:51개발을 파헤치다/Django

반응형
Many To Many 관계란?
 
Django에서 Many To Many 관계는 하나의 모델이 다른 여러 모델과 관계를 가질 수 있고, 이것의 역도 가능한 관계입니다.
 
 

 

 
위의 그림에서 사람과 고양이가 존재합니다. 
 
Mike는 Tigger와 Max의 주인입니다만, Max는 또 다른 주인으로 Eva를 섬기고 있습니다.
이렇게 모델들이 서로 다 대 다의 관계를 가지는 것이 바로 Many To Many 관계라고 할 수 있습니다.
 
One To Many 관계라면 Max는 Mike나 Eva 둘 중 한명을 주인으로 정해야 할 것입니다.
 
위의 관계를 Django는 아래처럼 데이터베이스에 관계가 저장되는 테이블을 생성합니다.
 

 

 
 
자, 이제 코드를 살펴봅시다.
 
Many To Many구조가 아래와 같이 잡혀있다고 가정합니다.
# models.py
from django.db import models

class User(models.Model):
    id = models.Autofield(primary=True)
    name = models.Charfield(max_length=10)
    
class Star(models.Model):
    id = models.Autofield(primary=True)
    followers = models.ManyToManyField(User, related_name="following")
Model에 대하여 간단하게 설명하자면 User는 일반 사용자이고 Star는 스타 즉, 연예인을 뜻합니다.
 
사용자는 어떤 스타이던 팔로우할 수 있고 스타 입장에서는 어떤 사용자던지 팔로워가 될 수 있는 것입니다.
그렇기 때문에 다 대 다 관계로 표현하고 Star에 Many To Many 필드로 User 모델을 선언했습니다.
 
Star 모델에서는 아래와 같이 Many To Many 필드에 접근할 수 있습니다.
# Star를 팔로우하고 있는 모든 User 목록을 불러옵니다.
star = Star.objects.all().first()
following_user_list = star.followers.all()
그렇다면 반대로 User 입장에서 자신이 팔로우하고 있는 Star의 목록을 얻고 싶다면 어떻게 해야 할까요?
 
Model상에서는 Star에만 followers라는 필드가 있을 뿐 User에는 이에 관련된 필드가 정의되어 있지 않습니다.
 
결론부터 말하자면 User에서도 당연히 팔로우하고 있는 Star의 목록을 얻을 수 있습니다.
 
먼저, Many To Many 필드가 실제로 데이터베이스 상에서 어떻게 구현되는지 알 필요가 있습니다.
 
 

 

 
 
Many To Many 필드를 생성하게 되면 위와 같이 관계를 나타내는 테이블을 Django에서 알아서 만들어 관리해줍니다.
 
그렇기 때문에 Star 모델에 followers라는 Many To Many 필드를 만들게 되면 Star와 User에서 모두 참조할 수 있는 관계 테이블이 생성되는 것입니다.
 
하지만 아래처럼 User가 팔로잉하는 Star의 목록을 가져오는 것은 직관성이 조금 떨어집니다.
user = User.objects.all().first()
user.followers.all()
위 코드만 봐서는 User를 팔로잉하고 있는 누군가(?)의 목록이 나타날 것만 같습니다.
 
위와 같은 문제를 해결하기 위해서 Many To Many 필드를 저의할 때 related_name 속성을 활용합니다.
    followers = models.ManyToManyField(User, related_name="following")
앞서 Models.py에는 위와 같이 정의가 되어있었습니다.
 
즉, 위의 Many To Many 필드는 Star에게는 followers라는 이름으로, 그리고 연관이 되는 User에게는 following이라는 이름으로 존재하게 됩니다.
 
따라서 아래와 같이 표현할 수 있습니다.
user = User.objects.all().first()
following_star_list = user.following.all()

 

 

반응형