[django] CRUD2 #2

ㅎㅎ·2021년 6월 22일
1

django

목록 보기
7/8

📌 django - CRUD2 #2 영화와 배우

ver. Foreign key 이용한 중간 테이블

  • 위의 모델링을 바탕으로 models.py 파일 만들기
  • 중간 테이블을 따로 만들어줌
#movies.models.py
from django.db import models
from django.db.models.deletion import CASCADE
from django.db.models.fields import DateField
from django.db.models.fields.related import ManyToManyField
# Create your models here.

class Actor(models.Model): #배우
    first_name = models.CharField(max_length=20) 
    last_name  = models.CharField(max_length=20) 
    date_of_birth = models.DateField()

    class Meta:
        db_table = 'actors'


class Movie(models.Model): # 영화 
    title = models.CharField(max_length=20) 
    release_date = models.DateField()
    running_time = models.DecimalField(max_digits=6,decimal_places=2)

    class Meta:
        db_table = "movies"


#배우- 영화 중간 테이블
class Actormovie(models.Model):
    actor =  models.ForeignKey('Actor',on_delete=CASCADE) #actor_id
    movie = models.ForeignKey('Movie',on_delete=CASCADE) #actor_id
    
    class Meta:   
        db_table = "actors_movies"

GET 구현하기

1. 배우의 이름, 성, 그리고 출연한 영화 제목 목록

from django.db.models.fields.related import ManyToManyField
from django.shortcuts import render

import json

from django.http     import JsonResponse
from django.views    import View
from movies.models import Actormovie, Actor, Movie , Actor2, Movie2


class ActorView(View):
    def get(self,request):
        actors = Actor.objects.all()
        results = []
        for actor in actors:
            actormovies = actor.actormovie_set.all() #역참조하기 : 테이블명소문자_set
            movie_list = []
            for actormovie in actormovies:
                movie_info = {
                    'title' : actormovie.movie.title, 
                }
                movie_list.append(movie_info)
            results.append(
                {
                    "first_name" : actor.first_name,
                    "last_name" :  actor.last_name,
                    "title" : movie_list #출연한 영화 제목 목록
                }
            )
        return JsonResponse({'results': results}, status = 200)

2. 영화의 제목, 상영시간, 출연한 배우 목록 (이름만)

class MovieView(View):
    def get(self, request):
        movies = Movie.objects.all()
        results = []
        for movie in movies:
            actormovies = movie.actormovie_set.all() #역참조
            actor_list = []
            for actormovie in actormovies:
                actor_info = {
                    'first_name' : actormovie.actor.first_name,
                    'last_name' : actormovie.actor.last_name,

                }
                actor_list.append(actor_info)
            results.append(
                {
                    "title" : movie.title,
                    "running_time" : movie.running_time,
                    # 출연한 배우 목록
                    "name" : actor_list
                }
            )
        return JsonResponse({'results': results },status=200 )



ver. ManyToManyField

  • 위의 모델링을 바탕으로 models.py 만들기
  • ManyToManyField을 만들었기 때문에 models.py에서 중간테이블을 직접 만들지 않고 django에서 중간테이블을 알아서 만들어줌. 하지만 데이터베이스에서 수정,관리 할수 없기 때문에 모델 클래스 중간테이블을 따로 만들어주는 것이 좋음.
#movies/models.py
class Movie2(models.Model): # 영화 
    title = models.CharField(max_length=20) 
    release_date = models.DateField()
    running_time = models.DecimalField(max_digits=6,decimal_places=2)

    class Meta:
        db_table = "movies2"


class Actor2(models.Model): #배우
    first_name = models.CharField(max_length=20) 
    last_name  = models.CharField(max_length=20) 
    date_of_birth = models.DateField()
    movie = models.ManyToManyField(Movie2, through='Movie2Actor2') 
    # 만약 중간테이블안만들고 manytomany 사용하면 데이터 베이스에 저절로 중간테이블을 만드나, 내용을 수정,입력할 수 없으니 밑의 클래스를 하나 더만들어 직접 fk로 연결해 만들어 주는 것이 좋음.  

    class Meta:
        db_table = 'actors2'
        
# manytomany필드만 사용하고 fk를 사용안하면 migrions했을때 설계도에 아무것도 생기지 않음.
class Movie2Actor2(models.Model): 
    actor2 =  models.ForeignKey('Actor2',on_delete=CASCADE) #actor2_id
    movie2 = models.ForeignKey('Movie2',on_delete=CASCADE) #actor2_id

    class Meta:
        db_table = 'actors2_movies2'

GET 구현하기

1. 배우의 이름, 성, 그리고 출연한 영화 제목 목록

class ActorView2(View):
    def get(self,request): 
        actors = Actor2.objects.all() # 쿼리셋 반환, all(),get()같은 메소드들을 포함하는 클래스를 매니저라고 부름, 여기서는 objects가 매니저
        results = []
        for actor in actors:
            movies = actor.movie.all() #참조, 여기서는 movie가 매니저
            movie_list = []

            for movie in movies:
                movie_info = {
                    'title' : movie.title,
                }
                movie_list.append(movie_info)
            results.append(
                {
                    "first_name" : actor.first_name,
                    "last_name" :  actor.last_name,
                    "title" : movie_list #출연한 영화 제목 목록
                }
            )
        return JsonResponse({'results': results },status=200 )class ActorView2(View):
    def get(self,request): 
        actors = Actor2.objects.all() # 쿼리셋 반환, all(),get()같은 메소드들을 포함하는 클래스를 매니저라고 부름, 여기서는 objects가 매니저
        results = []
        for actor in actors:
            movies = actor.movie.all() #참조, 여기서는 movie가 매니저
            movie_list = []

            for movie in movies:
                movie_info = {
                    'title' : movie.title,
                }
                movie_list.append(movie_info)
            results.append(
                {
                    "first_name" : actor.first_name,
                    "last_name" :  actor.last_name,
                    "title" : movie_list #출연한 영화 제목 목록
                }
            )
        return JsonResponse({'results': results },status=200 )
  • 데이터를 넣었을 때 나오는 형태

2. 영화의 제목, 상영시간, 출연한 배우 목록 (이름만)

class MovieView2(View):
    def get(self,request): 
        movies = Movie2.objects.all()
        results = []
        for movie in movies:
            actors = movie.actor2_set.all() # 역참조
            actor_list = []

            for actor in actors:
                actor_info = {
                    'first_name' : actor.first_name,
                    'last_name' : actor.last_name,
                }
                actor_list.append(actor_info)
            results.append(
                {
                    "title" : movie.title,
                    "running_time" : movie.running_time,
                    # 출연한 배우 목록
                    "name" : actor_list
                }
            )
        return JsonResponse({'results': results },status=200 )
  • 여기서 두 view에서 하나는 참조, 하나는 역참조 해서 오는 이유는,
    밑의 models.py에서 ManyToManyField를 Actor2라는 클래스 안에 만들어 줬기 때문에 Actor2가 Movie2를 참조하기 때문에 Movie2에서 Actor2를 갖고오려면 역참조 해야한다.
#models.py
class Actor2(models.Model): #배우
    first_name = models.CharField(max_length=20) 
    last_name  = models.CharField(max_length=20) 
    date_of_birth = models.DateField() #후에 형태는 "1998-01-01"
    movie2 = models.ManyToManyField(Movie2) # Actor2가 Movie2를 참조한다.
  • 데이터 넣었을 때 나오는 형태

Q. 둘의 차이점

ManyToManyField 없이 Foreign Key 로만 이루어진 중간테이블을 선언하여 M2M 를 구현해도 되는데, ManyToManyField 를 사용하면 어떤 이점이 있는지?

  • 중간테이블을 선언했을시에는 중간테이블을 역참조한후 연결테이블을 통해서 값을 가져와야하는 번거로움이 있는 반면에, manytomanytable을 사용시 중간테이블을 거치지 않아도 쉽게 값을 가져올 수 있다.

+) related_name을 사용할 경우

  • 한 테이블의 속성 두개가 한 테이블을 참조한다고 했을때. 만약 역참조를 한다면 어떤 속성을 역참조 해야하는지 모르므로 그때 related_name을 설정해 어떤 속성을 사용할 것인지 정해줘야한다. ,,,,,(,,?)

0개의 댓글