View

M to M _ManyToManyField의 역할

 

Django ORM 에서는 ManyToManyField 를 사용하여 두 개의 테이블 사이에서 M to M 관계 구현이 가능하다.

예시 ) 배우 : 영화 

 

작업 시작전 개발환경 세팅 및 사전 아래 세팅들을 모두 완료 후 진행해주자!!

  1. movies라는 app을 생성
  2. url.py 설정
  3. app.py 설정
  4. settings.py 설정

 

모델링하기

1. 모델링할 ERD 을 먼저 만들고, 이를 참고하여 modeling을 시작한다.

ERD

 

2. 영화배우 명단을 담을 테이블에 대한 클래스와 영화 목록을 담을 테이블에 대한 클래스가 필요하며, 

actors 테이블의 id 필드와  movies 테이블의 id 필드를 참조하는 중간 테이블 생성이 필요함을 알 수 있다.

이제  (field) name과 (data) type을 고려하여 models.py를 작성해준다.

방법은 actors와 movies 테이블을 만들면서 중간테이블을 수동으로 생성하느냐, 자동으로 생성시키느냐에 따라 2가지 방법으로 나뉜다.

 

models.py 작성

방법 1 : 중간 테이블을 수동으로 생성하는  방법(Foreign Key)

class Actor(models.Model):                           # through에 중간 테이블을 지정해준다. # 관계이름을 지정해준다.
    movies        = models.ManyToManyField("Movie"), through="Actor_Movie", related_name="actors of movies")
    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()

    class Meta:
        db_table = "movies"

 
 # 중간테이블 형성
 class Actor_Movie():
     actor = models.ForeignKey("Actor", on_delete=models.CASCADE)
     movie = models.ForeignKey("Movie", on_delete=models.CASCADE)

     class Meta:
         db_table = "actors_movies"

 

 

방법 2  : 중간 테이블을 자동으로  생성하는  방법(ManyToManyField)

class Actor(models.Model):                          # 관계에 대한 이름을 지어줌.
    movies        = models.ManyToManyField("Movie", related_name="actors of movies")
    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()

    class Meta:
        db_table = "movies"

 


테이블 생성 (migrations ==> migrate)

python manage.py makemigrations movies(app의 이름)
python manage.py migrate movies(app의 이름)

 


Modeling 완료 후 View만들기

 

 

잠깐 ‼️import 잊지말기

import json

from django.views import View
from django.http import JsonResponse
from movies.models(app의 이름.models) import Actor, Movie(models의 class 명)

👉 방법 1의 View 만들기(중간 테이블 수동 생성)

 

Post Method :  데이터베이스에 생성된 테이블에 data를 저장

1) 받아온 "first_name", "last_name", "birth date" 를 배우(Actors) 테이블 저장하기

class ActorsView(View):

    def post(self,request):
        data = json.loads(request.body)
        actor = Actor.objects.create(
            first_name    = data["first_name"], 
            last_name     = data["last_name"], 
            date_of_birth = data["birth_date"] 
        )

        movie = Movie.objects.get(title=data['title'])
        
         # 수동으로 선언한 중간 테이블 있는 경우 중간 테이블의 객체를 생성하여 바로 데이터 값을 넣는다.
         Actor_Movie.objects.create(
             actor = actor,
             movie = movie
         )
               
        return JsonResponse({"MESSAGE" : "CREATE" }, status=200)

2)  받아온 "title", "date", "time" 영화(Movies) 테이블저장하기

class MoviesView(View):

  def post(self,request):
        
        data = json.loads(request.body)

        Movies.objects.create(

            title        = data["title"],
            release_date = data["date"],
            running_time = data["time"]
            
        )    
        return JsonResponse({"MESSAGE" : "CREATE" }, status=200)

 

Get Method : 데이터베이스에 생성된 테이블에 저장된 data들을 조회

1) 배우(Actors) 테이블 에 저장된 배우(actor)"first_name", "last_name"과 

    그  배우(actor)가  출연한 영화들(movies_list)"title"(movie.title)을 가져오기

 

ManyToManyFeild로 Actor와 Movie 테이블 사이에 중간 테이블이 형성되어있는 상태이다.

이때 ManyToManyField의 위치가 중요하며, 여기서는 Actor 클래스가 가지고 있다.

Actor로부터 파생된 객체(actor)로 시작해서 중간 테이블 값들을 가져와야하는 것을 고려할때,

Movie가 ManyToManyField를 가지고 있는 Actor에서 파생된 객체(actor)가

Movie 클래스로부터 파생된 여러 movie들을 참조하여 중간 테이블에 접근하는 것이므로 actor.movies.all() 명령문 사용.

 

이것이 바로  🤟 순참조!!!

 

class ActorsView(View):

    # 배우의 이름, 성, 그리고 출연한 영화 제목 목록
    def get(self,request):
        actors = Actor.objects.all()
        result =[]

        for actor in actors:
            movies_list = []
    
            actor_movies = actor.movies.all()


            for movie in actor_movies:
            
                movies_list.append(
                    {
                        "movie_name": movie.title
                    }
                )
            
            result.append(
                {
                    "Actor_first_name" : actor.first_name,
                    "Actor_last_name"  : actor.last_name, 
                    "movies_list"      : movies_list
                }
            )


        return JsonResponse({"result" : result }, status=200)

2) 영화(Movies) 테이블 에 저장된 영화들의(Movies) "title", "running_time"과 

    영화(Movie)에 출연한 배우들의(actors_list)의 "first_name"(actor.first_name)을 가져오기

 

ManyToManyFeild로 Actor와 Movie 테이블 사이에 중간 테이블이 형성되어있는 상태이다.

이때 ManyToManyField의 위치가 중요하며, 여기서는 Actor 클래스가 가지고 있다.

 

1. Movie로부터 파생된 객체(movie)로 시작해서 중간 테이블 값들을 가져와야하는 것을 고려할때,

Movie에서 파생된 객체(movie)가 ManyToManyField를 가지고 있는 Actor 클래스로 부터 파생된

여러 actor들을 참조하여 중간 테이블에 접근하는 것이므로 movie.actors_set.all() 명령문 사용.

또는

2. related_named="actors of movies" 을 사용해서  actor.actors of movies.all() 로 가져오면 됨.(아래 모델 참고)

class Actor(models.Model):                           # through에 중간 테이블을 지정해준다. # 관계이름을 지정해준다.
    movies        = models.ManyToManyField("Movie"), through="Actor_Movie", related_name="actors of movies")
    first_name    = models.CharField(max_length=45)
    last_name     = models.CharField(max_length=45)
    date_of_birth = models.DateField()
    
    class Meta:
        db_table = "actors"

 

예시 ) MY유저 VS AUTH_유저

class MyUser(AbstractUser):
    # user_nickname = models.CharField(max_length=30)
    # user_photo = models.ImageField(upload_to="images", default='images/santa.png', blank=True)
    # user_intro = models.TextField(blank=True)

    # 좋아요 객체
    follower = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='following')

=> 참조되어지고 있는 모델 (AUTH_USER_MODEL)에서 MyUser를 보고 싶으면 'following'을 통해서 접근하면 된다.

MyUser.following.all()

 

이것이 바로  🤟 역참조!!!

 

class MoviesView(View):
    
    # 영화의 제목, 상영시간, 출연한 배우 목록 (이름만)
    def get(self,request):

        result =[]

        movies = Movie.objects.all()

        
        for movie in movies:
            
            actors_list =[]   
            
            actors = movie.actors_set.all()
    
            for actor in actors:
    
                actors_list.append(
                    {
                        "actor_name" : actor.first_name
                    }
                )

            result.append(
                {
                    "Movie_title" : movie.title,
                    "Movie_time"  : movie.running_time,
                    "Actors"       : actors_list
                }
            )

        return JsonResponse({ "result" : result }, status=200)

👉 방법 2의 View 만들기(중간 테이블 자동 생성)

Post Method : 데이터베이스에 생성된 테이블에 data를 저장

1) 받아온 "first_name", "last_name", "birth date" 를 배우(Actors) 테이블 저장하기

class ActorsView(View):

    def post(self,request):
        data = json.loads(request.body)
        
        actor = Actor.objects.create(
            first_name    = data["first_name"], 
            last_name     = data["last_name"], 
            date_of_birth = data["birth_date"] 
        )

        movie = Movie.objects.get(title=data['title'])
 		
        # 중간테이블이 ManyToManyField로 자동 생성된 경우
        
        actor.Movie.add(movie)
        
        
        return JsonResponse({"MESSAGE" : "CREATE" }, status=200)

🧐 add() 쿼리문에 대한 공식문서 : https://docs.djangoproject.com/en/3.2/topics/db/queries/


2)  받아온 "title", "date", "time" 영화(Movies) 테이블 저장하기

👆 방법 1과 동일

 


Get Method :  데이터베이스에 생성된 테이블에 저장된 data들을 조회

 

👆 방법 1과 동일

 


 

< 생각하기 >

Foreign Key 로만 이루어진 중간테이블을 선언하여 M2M 를 구현해도 되는데,

ManyToManyField 를 사용하면 어떤 이점이 있을까? 

 

"중간 테이블로 연결된  A와 B 테이블이 있을 때,

A에서 B로 접근하고자 한다면,

중간테이블을 거치지 않고 바로  A -> B,  B -> A 로 접근이 가능하다."

Share Link
reply
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31