Django의 View의 설계는 Model 단계에서 Table의 관계가 어떻게 만들어져 있는 지에 따라서 달라진다. 오늘은 Table들 간의 관계가 M2M 관계일 경우 View에서 Model의 객체를 가져오는 방법에 대해서 알아보고자 한다.
# models.py
from django.db import models
class Actor(models.Model):
first_name = models.CharField(max_length=45)
last_name = models.CharField(max_length=45)
date_of_birth = models.DateField()
class Meta:
db_table = 'actors'
class Movie(models.Model):
title = models.CharField(max_length=45)
release_date = models.DateField()
running_time = models.IntegerField()
actors = models.ManyToManyField(Actor, related_name='actors', through='ActorsMovies')
class Meta:
db_table = 'movies'
class ActorsMovies(models.Model):
actor = models.ForeignKey(Actor, on_delete=models.CASCADE)
movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
class Meta:
db_table = 'actors_movies'
위 models.py의 구성은 아래와 같다.
Actor와 Movie는 M2M 관계로 둘 중 하나의 class에 ManyToManyField를 생성한다. 위 코드에서는 class Movie에 ManyToManyField를 생성했으며 안에 몇 가지 옵션 값을 주었다.
models.py에서 설계 ERD를 바탕으로 views.py를 작성해보고자 한다. views.py의 목적은 아래와 같다.
- 등록된 배우 목록을 리턴해주는 GET 메소드를 구현
- 배우의 이름, 성, 그리고 출연한 영화 제목 목록
- 등록된 영화 목록을 리턴해주는 GET 메소드를 구현
- 영화의 제목, 상영시간, 출연한 배우 목록 (이름만)
import json
from django.http import JsonResponse
from django.views import View
from .models import Actor, Movie, ActorsMovies
class ActorView(View):
"""
목적: 모든 배우들의 정보를 client에 전달
1. last_name
2. first_name
3. date_of_birth
4. movies
"""
def get(self, request):
actors = Actor.objects.all()
results = []
for actor in actors:
movies = actor.actors.all()
results.append(
{
"1. last_name" : actor.last_name,
"2. first_name" : actor.first_name,
"3. date_of_birth" : actor.date_of_birth,
"4. movies" : [movie.title for movie in movies]
}
)
return JsonResponse({"results":results}, status=200)
class MovieView(View):
"""
목적: 모든 영화들의 정보를 client에 전달
1. title
2. release_date
3. runnging_time
4. actors
"""
def get(self, request):
movies = Movie.objects.all()
results = []
for movie in movies:
actors = movie.actors.all()
results.append(
{
"1. title" : movie.title,
"2. release_date" : movie.release_date,
"3. running_time" : movie.running_time,
"4. actors" : [actor.last_name for actor in actors]
}
)
return JsonResponse({"results" : results}, status=200)
1) 목적: class ActorView는 주석에 작성되어 있는 것처럼 모든 배우들의 모든 정보를 가져오는 것이다.
2) 4. movies 반환 방법
1) 목적: class MovieView는 모든 영화들의 모든 정보를 가져오는 것이다.
2) 4. actors 반환 방법:
비교적 간단하게 views.py를 작성한 것 같지만 ManyToManyField에 대한 명확한 이해가 없다면 간단히 작성하기 어렵다. 특히 참조, 역참조에 대한 개념과 이를 사용하는 _set() 혹은 related_name로 만든 함수는 해당 글의 핵심이므로 꼭 개념을 이해하고 사용해야 한다.