[Django] M2M과 View

그냥·2022년 6월 9일
0

django

목록 보기
5/20

Django의 View의 설계는 Model 단계에서 Table의 관계가 어떻게 만들어져 있는 지에 따라서 달라진다. 오늘은 Table들 간의 관계가 M2M 관계일 경우 View에서 Model의 객체를 가져오는 방법에 대해서 알아보고자 한다.

1. Model

# 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()
    actors = models.ManyToManyField(Actor, related_name='actors', through='ActorsMovies')

    class Meta:
        db_table = 'movies'

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

    class Meta:
        db_table = 'actors_movies'

위 models.py의 구성은 아래와 같다.

  1. class Actor(table명 actors)
  2. class Movie(table명 movies)
  3. class ActorsMovies(table명 actors_movies): M2M의 중간 테이블

Actor와 Movie는 M2M 관계로 둘 중 하나의 class에 ManyToManyField를 생성한다. 위 코드에서는 class Movie에 ManyToManyField를 생성했으며 안에 몇 가지 옵션 값을 주었다.

  • Actor: ManyToManyField를 연결한 class 이름을 작성, 위에서 먼저 class가 선언되었으면 "" 안쓰고 작성 가능
  • related_name: 참조 혹은 역참조 할 경우 <소문자로 변형된 클래스명>_set() 를 사용한다. related_name을 사용할 경우 위 형태에서 related_name에 넣은 값으로 변형해서 참조 혹은 역참조 할 수 있다. 단, 참조를 하기 위해서는 QuerySet이 아닌 객체에서만 할 수 있다.
    (ex. Movie QuerySet 가져오기 : Actor.objects.all().actors.all())
  • through: ManyToManyField를 만들고 makemigration - migrate를 할 경우 DB 내에 자동적으로 중간 테이블이 생성된다. through="중간 테이블명"을 사용할 경우 우리가 원하는 중간 테이블을 models.py에 선언할 수 있다.



2. View

models.py에서 설계 ERD를 바탕으로 views.py를 작성해보고자 한다. views.py의 목적은 아래와 같다.

  1. 등록된 배우 목록을 리턴해주는 GET 메소드를 구현
  • 배우의 이름, 성, 그리고 출연한 영화 제목 목록
  1. 등록된 영화 목록을 리턴해주는 GET 메소드를 구현
  • 영화의 제목, 상영시간, 출연한 배우 목록 (이름만)


import json

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

from .models import Actor, Movie, ActorsMovies


class ActorView(View):
    """
    목적: 모든 배우들의 정보를 client에 전달

    1. last_name
    2. first_name
    3. date_of_birth
    4. movies

    """

    def get(self, request):
        actors = Actor.objects.all()
        results = []

        for actor in actors:
            movies = actor.actors.all()

            results.append(
                {
                    "1. last_name" : actor.last_name,
                    "2. first_name" : actor.first_name,
                    "3. date_of_birth" : actor.date_of_birth,
                    "4. movies" : [movie.title for movie in movies]
                }
            )
        return JsonResponse({"results":results}, status=200)

class MovieView(View):
    """
    목적: 모든 영화들의 정보를 client에 전달

    1. title
    2. release_date
    3. runnging_time
    4. actors

    """
    def get(self, request):
        movies = Movie.objects.all()
        results = []

        for movie in movies:
            actors = movie.actors.all()
            results.append(
                {
                    "1. title" : movie.title,
                    "2. release_date" : movie.release_date,
                    "3. running_time" : movie.running_time,
                    "4. actors" : [actor.last_name for actor in actors]
                }
            )

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

class ActorView

1) 목적: class ActorView는 주석에 작성되어 있는 것처럼 모든 배우들의 모든 정보를 가져오는 것이다.

2) 4. movies 반환 방법

  • movies는 출연한 모든 영화 정보를 가져오는 것이다.
  • 1~3번은 actors = Actor.objects.all() QuerySet에서 정보를 가져오면 된다.
  • 4번인 movies는 Movie를 참조하여 정보를 가져와야 한다.
  • 방법은 for actor in actors 내에서 movies = actor.actors.all() 를 선언하는 것이다.
  • actor는 Actor QuerySet 내 들어있던 객체 중 하나이다.
  • actor에 .actors 라는 참조함수는 Modeling 과정 중 ManyToManyField 옵션값으로 선언한 related_name=actors 를 사용한 것이다.
  • actor 객체에서 Movie를 바라보는 QuerySet인 movies가 만들어진 것이다. - movies는 이름처럼 여러 개일 수 있으므로 [movie.title for movie in movies] list comprehension을 통해서 response 값으로 반환한다.

class MovieView

1) 목적: class MovieView는 모든 영화들의 모든 정보를 가져오는 것이다.

2) 4. actors 반환 방법:

  • class ActorView에서와 같은 방법을 사용한다.
  • for문을 돌리기 위한 iterator로 movies = Movie.objects.all() 를 선언한다.
  • 이를 중심으로 actors 정보를 참조하여 가져오고 위와 마찬가지로 list comprehension을 사용하여 그 값을 반환한다.



비교적 간단하게 views.py를 작성한 것 같지만 ManyToManyField에 대한 명확한 이해가 없다면 간단히 작성하기 어렵다. 특히 참조, 역참조에 대한 개념과 이를 사용하는 _set() 혹은 related_name로 만든 함수는 해당 글의 핵심이므로 꼭 개념을 이해하고 사용해야 한다.

0개의 댓글

관련 채용 정보