초기 셋팅부터 처음부터 차근차근 해보며 오류가 나는 부분이나 모르는 부분에 대해 정리해가며 포스팅해 나갈 예정입니다.
잘못된 부분이 있으면 지적해주시면 감사하겠습니다!
가상환경을 생성하고 접속한 뒤 필요한 툴이나 패키지를 다운 받는다.
conda create -u Movie python=3.9
conda activate Movie
...
pip install django
pip install mysql-client
pip install django-cors-headers
pip install PyMySQL
프로젝트 생성
django-admin startproject movie
settings.py파일과 urls.py파일 수정
데이터베이스 생성
mysql -u root -p
mysql> create database M2Mmovie character set utf8mb4 collate utf8mb4_general_ci;
실행 오류 검증
python manage.py runserver
이러한 테이블을 만들어보자.
python manage.py startapp movies
앱 생성 후,
# movies/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()
actor = models.ManyToManyField('Actor', through='ActorMovie')
class Meta:
db_table='movies'
Movie class에 ManyToManyField()를 사용하여 연결한다.
그 후 , models.py에 작성한 코드를 database에 적용하기 위해서 migration파일을 생성한다.
python manage.py makemigrations movies(app이름)
다음으로 migrations파일을 database에 적용
python manage.py migrate
이후 mysql에 들어가 데이터베이스에서 테이블을 조회하면 다음과 같이 나올 것입니다.mysql> show tables;
+---------------------+
| Tables_in_m2mmovie |
+---------------------+
| actors |
| django_content_type |
| django_migrations |
| django_session |
| movies |
| movies_actor |
+---------------------+
6 rows in set (0.00 sec)
python manage.py shell
shell에 접속한 뒤 Actor,Movie를 import해와 데이터를 넣어준다.
In [1]: from movies.models import *
In [2]: import datetime
In [3]: d = datetime.date(2020, 2, 10)
In [4]: Actor.objects.create(first_name = '강호', last_name = '송', date_of_birth = d)
Out[4]: <Actor: Actor object (1)>
...
대략 이러한 테이블들이 만들어진다.
mysql> select * from movies;
+----+-----------------+--------------+--------------+
| id | title | release_date | running_time |
+----+-----------------+--------------+--------------+
| 1 | 택시운전사 | 2017-08-02 | 137 |
| 2 | 타짜 | 2006-09-28 | 139 |
| 3 | 변호인 | 2013-12-18 | 127 |
| 4 | 암살 | 2015-07-22 | 139 |
| 5 | 베테랑 | 2015-08-05 | 123 |
+----+-----------------+--------------+--------------+
mysql> select * from actors;
+----+------------+-----------+---------------+
| id | first_name | last_name | date_of_birth |
+----+------------+-----------+---------------+
| 1 | 강호 | 송 | 2020-02-10 |
| 2 | 승우 | 조 | 1980-03-17 |
| 3 | 해진 | 유 | 1970-01-04 |
| 4 | 달수 | 오 | 1968-06-15 |
+----+------------+-----------+---------------+
다음 문제는 이제 두 테이블을 연결해주는 manyrelatedmanager 테이블에 값을 어떻게 넣어주냐이다.
방법은 Movie class의 manytomanyfield를 넣어준 actor가 해답이였다.
In [8]: m1 = Movie.objects.get(id=1)
In [9]: m1.actor.add(4)
한 변수에 Movie의 한 객체를 가져온 뒤 그 객체의 actor와 Actor테이블의 id값과 매칭을 시켜주는 것이였다.
이 테이블에서 데이터를 가져오는 GET을 목표로 작성해보겠다.
import json
from django.http import JsonResponse
from django.views import View
from movies.models import Movie, Actor
class ActorView(View):
def get(self, request):
actors = Actor.objects.all()
result=[]
for actor in actors:
result.append(
{
"first_name" : actor.first_name,
"last_name" : actor.last_name,
"movie" : list(actor.movie_set.values("title"))
}
)
return JsonResponse({'result': result},status=200)
class MovieView(View):
def get(self, request):
movies = Movie.objects.all()
result=[]
for movie in movies:
result.append(
{
"title" : movie.title,
"running_time" : movie.running_time,
"first_name" : list(movie.actor.values("first_name"))
}
)
return JsonResponse({'result': result},status=200)
일단 각 테이블의 모든 객체를 가져와 각각 actors, movies에 저장을 한 후 빈 리스트하나를 선언한 뒤 반복문을 돌려 append()로 딕셔너리 형태로 추가한다. 그 안에 actor나 movie의 인자들은 일반적인 방법으로 넣는 것이 문제는 없었다. 하지만 M2M table을 통해 데이터 값을 가져오는 것은 생각이 많이 필요했다. 내가 찾아낸 방법은 models.py에서 manytomanyfield를 actor로 받아왔으므로 이를 사용할 수 있겠다 생각했다. 반복문 한번에 movie의 한 객체씩 받아오므로 movie.actor 로 연결된 Queryset을 가져온 후 .values("title")로 title에 관한 값들만 가져와 출력한다. 반대로 actor의 경우는 _set 을 사용하여 역 참조하여 값을 가져왔다.
클라이언트의 요청을 받아 적절한 view를 맵핑해주는 urls.py를 작성한다.
from django.urls import path, include
urlpatterns = [
path('movies/', include('movies.urls')),
]
.as_view()는 클래스형 뷰를 작성했기 때문에 사용해야한다.
main의 urls.py와 연결을 해주기 위해 앱 내에 새로운 urls.py를 작성한다.
from django.urls import path
from movies.views import ActorView, MovieView
urlpatterns = [
path('actor', ActorView.as_view()),
path('movie', MovieView.as_view()),
]
위와 같이 작성하면 2가지의 url이 가능한 것이다.(movies/actor, movies/movie)
=======================================
http -v GET 127.0.0.1:8000/movies/actor
=======================================
{
"result": [
{
"first_name": "강호",
"last_name": "송",
"movie": [
{
"title": "택시운전사"
},
{
"title": "변호인"
}
]
},
{
"first_name": "승우",
"last_name": "조",
"movie": [
{
"title": "타짜"
},
{
"title": "암살"
}
]
},
...
=======================================
http -v GET 127.0.0.1:8000/movies/movie
=======================================
{
"result": [
{
"first_name": [
{
"first_name": "강호"
},
{
"first_name": "해진"
},
{
"first_name": "달수"
}
],
"running_time": 137,
"title": "택시운전사"
},
{
"first_name": [
{
"first_name": "승우"
},
{
"first_name": "해진"
}
],
"running_time": 139,
"title": "타짜"
},
...
model.py부터 보면 테이블을 생성할 때부터 같은 app안에 같이 생성을 해버리니 데이터 호출도 같은 곳에서 하게되고 url도 구분이 잘되진 않았다. 처음에 선언을 다른 app으로 해서 만든 후에 manytomany로 연결 할 수 있다는 것을 후에 알게 되었다.