

from django.db import models
#배우 테이블 작성(이름, 성, 생일, 출연한 영화(M2M))
class Actor(models.Model):
first_name = models.CharField(max_length = 20)
last_name = models.CharField(max_length = 10)
date_of_birth = models.DateField(auto_now = False, auto_now_add = False) #안에 파라미터는 안적어도 상관 없음
movie = models.ManyToManyField('Movie') #Movie 테이블과 Many To Many 관계, 파라미터로 relative_name 넣어주면 역참조할 때 편함 :)
class Meta:
db_table = 'actors'
class Movie(models.Model):
title = models.CharField(max_length = 80)
release_date = models.DateField()
running_time = IntegerField()
class Meta:
db_table = 'movies'
Actor클래스에ManyToManyField를 선언해주어Movie테이블과 M2M관계가 되었다.
Django에서는ManyToManyField를 선언해 주면 알아서 중간 테이블(혹은 중계 테이블)이 생성된다. 따라서 따로 class를 만들어 주지 않아도 된다.그러나!
나중에 혹시 중간 테이블에 필드를 추가해야 할 경우가 있으면 수정을 하기 힘들다. 왜냐하면 django에서 자동으로 만들어주는 중계 테이블은 연결된 두 테이블의 각 id만 참조하여 만들어지기 때문이다.
이런 식으로...
Model을 다 정의했으면 migration을 해준다.
python manage.py makemigration
python manage.py migrate
import json
from django.http import JsonResponse
from django.views import View
class ActorView(View):
def get(self, request):
res = []
actors = Actor.objects.all()
for actor in actors:
movie = list(actor.movie.values('title')
res.append(
{
"last_name" : actor.last_name
"first_name" : actor.first_name
"movies" : movie
}
)
return JsonResponse({'results' : res}, status = 200)
class MovieView(View):
def get(self, request):
res = []
movies = Movie.objects.all()
for movie in movies:
actor_res = []
actors = movie.actor_set.all()
for actor in actors:
actor_res.append(
{
"name" : actor.name
}
)
res.append(
{
"movie name" : movie.title
"running time" : movie.running_time
"appearance" : actor_res
}
)
return JsonResponce({'results' : res}, status = 200)
View에서 로직을 다 구현했으면 각 엔드포인트를 등록해 준다.
# main(manage.py가 있는 디렉토리)에서의 urls.py
from django.urls import path, include
urlpatterns = [
path('movies/', include('movies.url')),
]
# app(movies 디렉토리)에서의 urls.py
from django.urls import path
from movies.views import *
urlpatterns = [
path('actor', ActorView.as_view()),
path('movie', MovieView.as_view())
]
처음에 main에 있는 urls.py를 통해 'movies/'를 url에 추가한다. 그리고 include에 있는 파일로 가서 path를 추가한다. 이제 가상의 클라이언트(httpie 유틸리티)를 설치하여 요청을 보내보자.
brew install httpie
설치가 완료되면 요청을 보내보자.
http -v GET 127.0.0.1:8000/movies/actor
일단 main에서 정의한 path인 movies를 통해서 movies.url을 호출하고 app에서 정의한 path인 actor를 통해 ActorView클래스의 로직을 실행한다. 현재 GET방식으로 요청이 들어왔으므로 get메소드가 실행된다.

ManyToManyField를 사용하면 자동으로 중계 테이블이 생성된다. 만약ManyToManyField를 사용하지 않고 따로 중계 테이블을 만들어서ForeignKey를 사용하여 두 테이블을 연결해 주면 불편함이 증가한다.예를 들어, 배우의 정보가 들어있는 테이블과 영화의 정보가 들어있는 테이블이 있다고 하면 한 배우는 여러 영화에 출현할 수 있다. 따라서 두 테이블은 ManyToMany관계이다.
배우가 출현한 영화의 목록을 확인하기 위해서는 중계테이블을 통해 해당 배우의 id와 매핑된 영화의 id를 찾아서 그 영화 id의 제목을 찾아가야 한다.
그러나ManyToManyField를 선언하면 배우가 출현한 영화의 제목을 조회하기 위해서는actor.movie.title이렇게 심플하게 접근할 수 있다.그렇다고 무조건
ManyToManyField가 좋다는 것은 아니다. 나중에 어떤 배우가 출연한 영화의 감독 필드를 추가하고 싶을 때MTMField를 선언하면 원하는 필드를 추가하는 것이 힘들다. 따라서 따로 테이블을 정의하는 것도 나쁘지 않은 방법이다.