TIL 33. Django - M:N 관계 Model과 View 작성하기 (배우와 영화)

문승준·2021년 9월 28일
0

Django

목록 보기
5/7
post-thumbnail

ManytoMany Table로 구성된 배우정보와 영화정보를 이용해 GET 메소드를 구현해보자.


Movies app View 작성하기


3-1. Model 작성

다대다 관계인 배우 테이블과 영화 테이블을 만들고 영화 테이블에 ManyToManyField 를 지정해주었다. 또한, 중간 테이블도 따로 만들어서 through로 연결했다.

# movies.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()
    actor        = models.ManyToManyField(Actor, through='ActorMovie')
     
    class Meta:
        db_table = 'movies'

-> 영화 테이블 작성

  • 배우 테이블과 연결되는 ManyToManyField를 영화 테이블에 넣어주었다.
    -> ManytoManyField 는 중간 테이블을 자동으로 생성해준다.
  • 아래처럼 중간테이블을 직접 만들고 through 값에 추가하면 중간 테이블에서 또다른 필드를 만드는 등 커스터마이징 가능하다. -> 확장성이 좋아진다.

class ActorMovie(models.Model):
    actor = models.ForeignKey(Actor, on_delete=models.CASCADE)
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)

    class Meta:
        db_table = "actors_movies"

-> 중간 테이블 작성

  • 두 개의 FK로 연결하면 영화 테이블에 ManytoManyField가 없어도 문제없다.

  • 하지만 ManytoManyFieldthrough로 지정해주지 않으면 다른 테이블로 접근할때 매번 중간 테이블을 거쳐야한다. -> 아주 비효율적이며 번거롭다.

  • ManyToManyField 뿐만 아니라 ForeignKey 필드에도 사용할 수 있는 옵션이다.

  • 참조 관계의 테이블에서 손쉽게 역참조/정참조를 할 수 있게 해 준다.

  • 옵션 값으로는 상대 테이블에서 해당 테이블을 참조할 때 쓰는 이름을 값으로 주면 된다.
    -> 위에서 related_name="actors" 로 하면 배우 테이블에서 actors라는 이름으로 출연 영화 정보를 가져올 수 있다.

  • 이 옵션은 M:N관계에서 사용하기보단 셀프 참조를 하는 테이블에 유용하게 쓰인다.(self 참조 시에는 related_name이 필수다)



3-2. View 작성

  1. 등록된 배우 목록을 가져올 수 있는 GET 메소드 구현하기.
    -> 이름, 출연 영화 제목
import json

from django.http  import JsonResponse
from django.views import View

from movies.models import Actor, Movie

class ActorView(View):
    def get(self, request):
        actor_list = []
        actors = Actor.objects.all()
        for actor in actors:
            movie_list = []
            movies = actor.movie_set.all() # 역참조
            for movie in movies:
                movie_list.append(movie.title)
            actor_info = {                    
                "name"  : actor.last_name + actor.first_name,

                "movie_list" : movie_list
            }
            actor_list.append(actor_info)

        return JsonResponse({'result':actor_list}, status=200)
  • 모든 배우 정보를 순회하며 출연 영화 정보를 반환한다.

  • 배우 테이블에서 영화 정보로 접근하기 위해 역참조를 한다. (actor.movie_set)

  • 배열에 담아 리턴한다.

  1. 등록된 영화 목록을 가져올 수 있는 GET 메소드 구현하기.
    -> 제목, 상영시간, 출연 배우 이름
class MovieView(View):
    def get(self, request):
        movie_list = []
        movies = Movie.objects.all()
        for movie in movies:
            actor_list = [{
                'name': actor.last_name + actor.first_name}
            for actor in movie.actor.all()]
            movie_list.append(
                {
                    "title"        : movie.title,
                    "running_time" : movie.running_time,
                    "actor_list"   : actor_list
                }
            )
            
        return JsonResponse({'result':movie_list}, status=200) 
  • 배우 정보와 비슷한 로직이지만 파이썬의 List Comprehension을 이용했다.

  • 특정 영화에 출연한 배우 정보를 순회하며 이름을 배열에 담는다.

  • 영화 테이블에서 배우 정보로 접근하는 것은 정참조이다.

3-3. URLconf 작성

from django.urls import path

from movies.views import ActorView, MovieView

urlpatterns = [
    path('/actor', ActorView.as_view()),
    path('/movie', MovieView.as_view()),
]
  • 작성한 두개의 view에 대해 urls.py를 작성해준다.

  • 프로젝트 폴더의 urls.py에는 include() 함수와 함께 movies 앱의 경로를 지정해준다.

추후 POST 메소드도 구현해보자.


profile
개발자가 될 팔자

0개의 댓글