TIL | Django - Actor & Movie

송치헌·2021년 8월 20일
0

TIL | Wecode - Django

목록 보기
10/18
post-thumbnail

📑ERD 모델


📔Models.py 작성


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

🔗views.py 작성


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에서 로직을 다 구현했으면 각 엔드포인트를 등록해 준다.

✉️urls.py 작성

main의 urls.py

# main(manage.py가 있는 디렉토리)에서의 urls.py
from django.urls import path, include

urlpatterns = [
    path('movies/', include('movies.url')),
]

app의 urls.py

# 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를 사용하면 자동으로 중계 테이블이 생성된다. 만약 ManyToManyField를 사용하지 않고 따로 중계 테이블을 만들어서 ForeignKey를 사용하여 두 테이블을 연결해 주면 불편함이 증가한다.

예를 들어, 배우의 정보가 들어있는 테이블과 영화의 정보가 들어있는 테이블이 있다고 하면 한 배우는 여러 영화에 출현할 수 있다. 따라서 두 테이블은 ManyToMany관계이다.
배우가 출현한 영화의 목록을 확인하기 위해서는 중계테이블을 통해 해당 배우의 id와 매핑된 영화의 id를 찾아서 그 영화 id의 제목을 찾아가야 한다.
그러나 ManyToManyField를 선언하면 배우가 출현한 영화의 제목을 조회하기 위해서는 actor.movie.title이렇게 심플하게 접근할 수 있다.

그렇다고 무조건 ManyToManyField가 좋다는 것은 아니다. 나중에 어떤 배우가 출연한 영화의 감독 필드를 추가하고 싶을 때 MTMField를 선언하면 원하는 필드를 추가하는 것이 힘들다. 따라서 따로 테이블을 정의하는 것도 나쁘지 않은 방법이다.

profile
https://oraange.tistory.com/ 여기에도 많이 놀러와 주세요

0개의 댓글