[Django] C.R.U.D -2 (2)


俳優と映画


# movies.models.py
from django.db import models

class Actor(models.Model):
    first_name    = models.CharField(max_length=20)
    last_name     = models.CharField(max_length=20)
    date_of_birth = models.DateField()
    # though를 지정해주지 않으면 다른 테이블로 접근할 때 매번 중간 테이블을 거쳐야한다.
    # actor -> movie 정참조, movie -> actor 역참조
    movies        = models.ManyToManyField("Movie", through="Actor_Movie", related_name="actors")
    # related_name을 지정해주면 역참조할 때 사용할 수 있다.
    

    class Meta:
        db_table = 'actors'

# MTM를 사용하면 자동으로 Class_Class형태로 DB에 중간table이 생성된다.
# 사용자가 직접 중간테이블을 만들고 through값에 추가하면 중간테이블에서 필드를 추가하는 커스터마이징 가능하다. -> 확장성 ↑
# 두 개의 FK로 연결하면 MTM필드가 없어도 오류는 없으나 다른 테이블로 접근할때마다 매번 중간테이블을 거쳐야한다. -> 비효율적
class Actor_Movie(models.Model):
    actor = models.ForeignKey('Actor', on_delete=models.CASCADE)
    movie = models.ForeignKey('Movie', on_delete=models.CASCADE)

    class Meta:
        db_table = 'actors_movies'

class Movie(models.Model):
    title        = models.CharField(max_length=20)
    release_date = models.DateField()
    running_time = models.IntegerField()

    class Meta:
        db_table = 'movies'
# main/urls.py
from django.urls import path, include

urlpatterns = [
    path('', include('movies.urls'))
]
# movies/urls.py
from django.urls import path

from movies.views import ActorsView, MoviesView

urlpatterns = [
    path('actors', ActorsView.as_view()),
    path('movies', MoviesView.as_view())
]
# movies/views.py
from django.http  import JsonResponse
from django.views import View

from movies.models import Actor, Movie

class ActorsView(View):
    def get(self, request):
        actors   = Actor.objects.all() # actor테이블의 모든 레코드를 querySet으로 가져온다.
        results  = [] # 배우의 이름과 성, 출연한 영화 제목 목록을 출력할 리스트
        for actor in actors: # actor테이블의 모든 레코드를 돈다.
            movie_lists = [] # movie를 담을 리스트 생성
            movies      = actor.movies.all() # MTM관계 지정을 했으므로 중간 테이블없이 movies 값을 가져올 수 있다.
            for movie in movies: # movie테이블의 모든 레코드를 돈다.
                # 각 actor에 맞는 movie리스트를 추가한다.
                movie_lists.append({ 
                    "title" : movie.title # 영화 제목을 가져온다.
                })
            results.append({ # 배우의 이름, 영화 목록을 추가한다.
                "first_name" : actor.first_name,
                "last_name" : actor.last_name,
                "movie" : movie_lists
            })

        return JsonResponse({'resutls':results}, status=200)

class MoviesView(View):
    def get(self, request): 
        movies   = Movie.objects.all()
        results  = []
        for movie in movies:
            actor_lists = [] # actor를 담을 리스트 생성
            # movies안의 각각의 movie에 맞는 actors객체를 전부 가져온다.
            # MTM을 사용하지 않는다면 중간테이블에서 값을 가져와야한다.
            actors      = movie.actors.all() 
            # movie에서 actor 참조는 역참조이다. actor_set
            # related_name에 actors를 대입해주었기에 사용가능하다.
            for actor in actors: 
            # actor테이블의 모든 레코드를 돈다.
                # 각 movie에 맞는 actor리스트를 추가한다.
                actor_lists.append({ 
                    "name" : actor.first_name
                })
            results.append( # 영화의 제목, 러닝타임, 배우 목록을 추가한다.
                {
                   "title" : movie.title,
                   "running_time" : movie.running_time,
                   "actor" : actor_lists
                }
            )
       
        return JsonResponse({'resutls':results}, status=200)
http -v GET 127.0.0.1:8080/movies
http -v GET 127.0.0.1:8080/actors

なぜManyToManyFieldを使うのですか?

  • の中間テーブルを必要とせず、いつでも簡単にデータを追加およびインポートできます.
  • メンテナンスが便利です.
  • MTMフィールドを使用すると、自動的にClass Class形式でデータベースにテーブルが作成されます.
  • MTMフィールドの名前はrelated_name+sです.
    ex) movie_set (x) -> movies
  • (修正)俳優と映画のPOSTを実現!

    # movies/urls.py
    from django.urls import path
    
    from movies.views import ActorsView, MoviesView, Actors_MoviesView
    
    urlpatterns = [
        path('actors', ActorsView.as_view()),
        path('movies', MoviesView.as_view()),
        path('actors_movies', Actors_MoviesView.as_view())
    ]
    # movies/views.py
    import json
    
    from django.http  import JsonResponse
    from django.views import View
    
    from movies.models import Actor, Actor_Movie, Movie
    
    class ActorsView(View):
        def get(self, request):
            actors   = Actor.objects.all()
            results  = [] 
            for actor in actors: 
                movie_lists = [] 
                movies      = actor.movies.all() 
                for movie in movies:
                    movie_lists.append({ 
                        "title" : movie.title 
                    })
                results.append({ 
                    "first_name" : actor.first_name,
                    "last_name"  : actor.last_name,
                    "movie"      : movie_lists
                })
    
            return JsonResponse({'resutls':results}, status=200)
    
        def post(self, request):
            try:
                data = json.loads(request.body)
                Actor.objects.create( 
                    first_name    = data['first_name'], 
                    last_name     = data['last_name'], 
                    date_of_birth = data['date_of_birth'] 
                )
                return JsonResponse({'messasge':'created'}, status=201) 
        
            except KeyError:
                return JsonResponse({'message' : 'KEY_ERROR'},status=400)
    
    class MoviesView(View):
        def get(self, request): 
            movies   = Movie.objects.all()
            results  = []
            for movie in movies:
                actor_lists = [] 
                actors      = movie.actors.all() 
                for actor in actors: 
                    actor_lists.append({ 
                        "name" : actor.first_name
                    })
                results.append( 
                    {
                       "title"        : movie.title,
                       "running_time" : movie.running_time,
                       "actor"        : actor_lists
                    }
                )
           
            return JsonResponse({'resutls':results}, status=200)
    
        def post(self, request):
            try:
                data      = json.loads(request.body)
                Movie.objects.create( 
                    title        = data['title'], 
                    release_date = data['release_date'], 
                    running_time = data['running_time'] 
                )
                return JsonResponse({'messasge':'created'}, status=201) 
        
            except KeyError:
                return JsonResponse({'message' : 'KEY_ERROR'},status=400)
    
    
    class Actors_MoviesView(View):
        def post(self, request):
            try:
                data = json.loads(request.body)
                Actor_Movie.objects.create( 
                    actor_id = data['actor_id'], 
                    movie_id = data['movie_id'], 
                )
                return JsonResponse({'messasge':'created'}, status=201) 
        
            except KeyError:
                return JsonResponse({'message' : 'KEY_ERROR'},status=400)