본문 바로가기
[Cloud & Infrastructure]/[Project]

Django + ReactJS를 이용한 프로젝트 만들기 [1/2]

by 코드몽규 2022. 6. 1.
반응형

 

 오랜만에 개인 관련 포스팅을 한다.

5월 2일 부터 팀 프로젝트 진행 때문에 블로그를 신경 쓸 시간이 없었는데

마침 1차 프로젝트가 끝나고 2차 프로젝트가 어느정도 진행되어 시간이 생겼다!!!!

이번 포스팅은 완성한 1차 프로젝트를 간단하게 정리하는 글이 될 것이다. 

 

나 또한 프로젝트를 진행하며 무수히 많은 블로그와 레퍼런스를 참고했기 때문에

누군가에게 도움이 되고자 정리해본다!

 

글의 순서는 아래와 같다!! 

1. 프로젝트의 주제 선정 및 목표

2. 사용된 라이브러리 / 환경

3. 어려웠던 기능 구현 

4. 배포

 

아래는 프로젝트 소스코드 주소이다 ㅎㅎ

😺Github

 

GitHub - codemonkyu/Movie_project: multicampus_cloud_team4

multicampus_cloud_team4. Contribute to codemonkyu/Movie_project development by creating an account on GitHub.

github.com


프로젝트 주제 선정 및 목표

  처음 주제를 선정할 때 어떤 주제를 선정할 지에 대한 고민이 많았다. 나뿐만 아니라 다른 팀원들도 주제 선정은 프로젝트 방향성을 결정하는 부분이라 선뜻 의견을 제시하지 못했다. 하지만 어떤 기술을 사용할 것 인지 미리 정해놓고 범위를 좁히니 쉽게 결정할 수 있었다.

 예를 들면, 우리 팀은 백엔드와 프론트엔드 프레임워크로 Django와 ReactJS를 사용하기 결정했다. 그 이후 ReactJS를 활용한 서비스들의 무엇이 있는지를 참고했다. 마침 ReactJS를 사용한 서비스들 중 넷플릭스가 있었으며 이를 "커져가는 국내 OTT 시장에 맞춘 영화 추천 서비스"라는 인사이트로 연결시킴으로써 주제와 목표까지 결정할 수 있었다!!!

 


사용된 라이브러리 및 환경 

 주제를 선정했으니 이제 Django와 ReactJS를 활용하여 어떻게 서비스를 구현할 것인지를 생각해봐야 한다. 찾아본 결과 이 부분은 2가지 방법으로 해결할 수 있다. 

 첫 번째 방법은 Django에서 기본 베이스 Template를 React로 설정해주는 것이다. 이렇게 하면 굳이 Backend와 Frontend를 구분하지 않고 django에서 개발환경을 구성할 수 있기 때문에 서비스의 스트럭처가 간단해진다. 하지만 React의 많은 기능들이 제약되며, 배포를 목적으로 하는 서비스 같은 경우 서버와 클라이언트를 분리해서 관리할 수없다는 유지보수 측면에서 치명적인 결함이 있다. 때문에 잘 사용되지 않는다. 

 두 번째 방법은 Django로 서버(backend)를 구성하고 React로 클라이언트(frontend)를 구성하여 이를 DRF(Django-Rest-Framework)를 이용한 API통신으로 연결하는 것이다. 즉 Django에서는 데이터베이스를 만들어 데이터를 저장하고 REST API를 이용한 CRUD를 구성한다. React에서는 이를 axios 나 Fetch를 통해 데이터를 갖고 와 화면에 뿌려주면 된다.

 두 번째 방법을 쓰면 일단 프론트와 백엔드를 나누어서 관리 할 수 있다. 이 둘을 나누어서 관리한다는 것은 유지보수 측면에서 엄청난 이점이다!!! 때문에 현업에서는 대부분 이 두번째 방법을 많이 사용한다. 나 또한 프로젝트의 최종적으로 배포까지 하는 것이었기 때문에 두번째 방법을 선택했다! 

 

 

사용할 라이브러리 

python
django
djangorestframework
djangorestframework-simplejwt
dj-rest-auth
npm
yarn
.........

(자세한 환경은 github의 소스 중 requirements.txt 파일을 참고!!)

 

환경 구성 순서

1. 가상 환경 설정

 프로젝트를  혼자 진행하는 것이 아니라면 가상 환경 설정은 필수이다. 개발시 사용하는 패키지의 버전을 동일시 해야 라이브러리의 의존성 문제 및 자잘한 오류를 막을 수 있다. 예상외로 이런 곳에서오는 오류가 잦기 때문에 가상환경을 만들어 주자!! 가상환경은 프로젝트를 생성할 디렉터리에 아래와 같은 명령어로 설정 가능하다.

(mac에서는 가상환경 설정이 조금 다르기 때문에 mac을 사용 중이라면 따로 검색해서 설정한다.)

$python -m venv 가상환경이름
$cd 가상환경이름 
$cd Scripts
$activate

 

위와 같이 cmd 라인 앞에 (가상 환경 이름)이 나오면 활성화된 것이다.

2. Django환경 설정

 가상 환경을 설정했다면 django 프로젝트를 설정해주자! 먼저 django 프로젝트 생성 후 APP을 만들어 준다. 보통 app은 데이터를 관리할 app과 유저를 관리할 app으로 2가지를 만들어주면 된다. 아래 명령어는 기본적인 django 환경설정 명령어로 참고용으로 작성해 놓은 것이다. 

  실제로 처음 장고 프로젝트를 생성 후 기본 app을 마이그레이션 한다. 이후에는 데이터를 관리할 APP에서 DB를  모델링한 후 해당 APP만 마이그레이션 - 마이 그레이트 해주면 된다. 

 관련 내용은 = > https://tibetsandfox.tistory.com/24 여기를 참고하면 된다. (되게 잘 정리해놓으셨다 ㅎㅎ 장고를 사용할 때 마이그레이션을 잘 관리하면 유용하다!)

# django 최신 버전 설치
pip install django

# django 지정 버전 설치
pip install django==4.0.3

# django 프로젝트 생성
django-admin startproject 프로젝트 이름

# django app 생성 (생성한 프로젝트 디렉터리로 이동 후)
python manage.py startapp 앱이름 

# makemigrations
python manage.py makemigrations

# migrate
python manage.py migrate

# django 서버 실행
python manage.py runserver

 

3. ReactJS환경 설정

  자신만의 장고 환경을 설정했다면 이제는 React 환경을 설정할 때이다. 프로젝트르 진행하는 디렉터리 폴더에서 Reactjs 환경을 만들어준다. ( django 폴더 내에 생성하지 않도록 주의한다. 디렉터리 구조는 - 프로젝트 폴더 -> react / 가상 환경 / django프로젝트로 구성되어 있어야 한다.) 

  또한 리액트는 javascript 기반이기 때문에 node.js를 미리 설치해줘야 npm 명령어를 사용할 수 있다. 관련 과정은 => https://chanhuiseok.github.io/posts/react-2/ 이곳을 참고했다.

 

# node.js 설치 후 버전 확인
node -v

# 프로젝트 디렉터리에서 react설치
npx create-react-app 리액트 프로젝트 이름

# 리액트 프로젝트 디렉터리로 이동 후 리액트 프로젝트 실행
npm start

 

위의 과정을 따라 했다면 아래와 같은 디렉터리 구조가 완성되어야 한다. 

(kubernetes는 신경 쓰지 말자 프로젝트가 완성 후 배포를 위해 따로 만든 디렉터리이다.)


기능 구현 

 여기까지 기본적인 환경 설정이 끝났다.  이제는 프로젝트의 주요 기능에 대해 설명하고 특히 어려웠던 기능을 위주로 설명하겠다. 사실 아주 디테일한 부분까지 블로그에 포스팅하고 싶지만 시간적 여유가 없기 때문에 내가 참고한 레퍼런스, 블로그 주소를 첨부하며 넘어가겠다. 대신 기능을 구현하는데 확실히 도움이 된 자료들이기 때문에 이 글을 읽는 당신의 시간을 확실히 아껴 줄 수 있을 거라 생각한다. 

 

DRF(Django Rest Framework)로 JWT기반 인증 세팅하기 

  인증 처리는 보안과도 직접적으로 연관된 아주 중요한 작업이다. 세션과쿠키를 이용하는 법과 토큰방식의 JWT 형식을 사용하는 방식이 있다. 각각에 장점이 있지만 이번 프로젝트에서는 사용자 정보를 상세하게 다루기보다 로그인에 대한 유효성 검사에 초점을 맞추었기 때문에 이에 조금더 적합한 JWT형식을 이용했다.

  JWT(Json web token)은 세션 하나에 토큰 하나가 발급되며 로그인 시 accesstoken, refreshtoken이 같이 발급되며 이를 통해 token의 만료기간을 설정하여 보안상 유리하다.

(refresh token의 유효기간이 access token의 유효기간보다 길게 설정하는데 그 이유는 refresh token의 유효기간 안에 새로운 accesstoken을 요청할 수 있기 때문이다.

 또한 JWT의 가장 큰 핵심은 토큰 자체에 사용자의 권한 정보나 서비스를 사용할 정보가 포함되어 있다는 것이다. 세션을 사용할 경우 쿠키 등을 발행해 사용자를 식별하고 서버에 세션을 저장하지만 JWT는 토큰을 클라이언트에 저장하고 요청 시 Header에 토큰을 첨부하는 것만으로도 데이터 응답을 받아올 수 있다. 즉 사용자의 Session id를 관리할 db가 따로 필요없다. 

 

 일반적인 JWT 작동방식이다. 

1. 클라이언트가 ID, PW를 통해 웹서비스 인증

2. 서버에서 JWT를 생성하여 클라이언트에 응답으로 돌려주기

3. 클라이언트가 서버에 데이터를 추가적으로 요구할 때 JWT를 Header에 첨부

(깃 헙의 React부문의 코드를 보면 RestAPI와 통신할 때 로컬 스토리지에 JWT를 넣고 Header에 붙여주는 모습을 볼 수 있다.)

4. 서버에서 클라이언트로부터 온 JWT를 검증하고 응답한다. 

 

  * 장고에 JWT 적용하 법에 대한 글이다.

(정말 많은 자료를 찾아보았지만 제일 정리를 잘해놓으셨다..! 블로그 주인이신 Chanjong Park 님께 다시 한번 감사함을 전한다!😀😀)

 

Django-Rest-Framework(DRF)로 JWT 기반 Authentication 세팅하기(with simplejwt) — 초기 환경 세팅(1)

앞서 포스팅했던 소셜 로그인 구현에서 생각보다 많은 개발자 분들이 봐주신 덕분에 상위노출도 되어 기뻤지만, 이전 코드를 다시 보니 많이 부족하단 생각이 들었다. 특히 JWT 부분에서 이해력

medium.com


dj - rest - auth 활용하기

  JWT를 통해 인증방식을 구현했다면 이제는 로그인 방식을 선택할 때이다. 나는 dj-rest-auth라는 편리한 패키지를 사용했다. 하지만 그 이전에 장고에서 기본적으로 유저 기능을 구현하기 위해 어떤 유저 모델이 있는지 알고 넘어가는 편이 좋다. 장고에는 기본적으로 django.contrib.auth라는 기본 유저 모델을 제공해주는 패키지가 있다. 여기서 주로 AbstractUser와 AbstractBaseUser를 사용하는데 이 둘의 차이점을 살펴보자 

 

 

 차이점은 간단하다. AbstractUser은 기존 User 모델에서 제공하는 필드 중 상속하고 싶은 것만 정의하면 된다. 반대로 AbstractBaseUser 유저에게 필요한 모든 필드를 직접 정의해줘야 한다. 

 

  따라서 AbstractUser를 통해 user 모델링을 해주고 이를 dj-rest-auth의 로그인 폼으로 사용하면 내가 원하는 정보를 통해 인증을 처리하고 토큰을 발급할 수 있는 것이다. 

 

dj-rest-auth 적용방법은 아래를 참고했다. (위와 같은 블로그 ㅎㅎ)

 

Django-Rest-Framework(DRF)로 JWT 기반 Authentication 세팅하기(with simplejwt) — dj_rest_auth로 회원가입부터

저번 포스트에서 DRF로 JWT 인증을 위한 기본적인 세팅을 완료했다. 이제 직접 회원가입과 로그인을 진행해보자.

medium.com


TMDB API를 이용한 Movie 데이터 갖고 오기 

 로그인 기능 다음으로 조금 애를 먹었던 부분이 TMDB api를 사용하여 영화 정보를  갖고 오고 이를 장고의 기본 db인 dbsqlite3에 넣는 과정이었다. 어찌어찌하여 관련 정보를 찾아서 해결하였지만 그 과정 중 너무나도 많은 고통이 있었다!

나 같은 시행착오를 겪지 않길 바라며 API를 사용해서 영화 DB를 가져오는 코드와 DB에 넣는 법을 공유하겠다.

 

TMDB API를 사용하여 영화 데이터 받기 (JSON형식으로 저장)

  아래 코드를 실행하기 전에 반드시 확인해야 할 부분이 있다. 바로 코드의 fileds 부분의 개체들이 실제로 model.py에서 모델링한 한 속성과 같아야 한다는 것이다.

import requests
import json

TMDB_API_KEY = "tmdb api" # 이곳에 본인의 TMDB API 를 넣으면된다. 


def get_movie_datas():
    total_data = []
    #for 문의 범위를 조절해서 데이터 양을 조절할 수 있다. 
    for i in range(1, 151):
        request_url = f"https://api.themoviedb.org/3/movie/popular?api_key={TMDB_API_KEY}&language=ko-KR&page={i}"
        res = requests.get(request_url)
        movies = res.json()

        print(movies['total_results'])
        print(movies['total_pages'])
        for movie in movies['results']:
            if movie.get('release_date', ''):
                movie_id = movie['id']
                url = f"https://api.themoviedb.org/3/movie/{movie_id}?api_key={TMDB_API_KEY}&language=ko-KR"
                movie_detail = requests.get(url).json()
                print(movie_detail)
                fields = {
                    'title': movie['title'],
                    'release_date': movie['release_date'],
                    'vote_count': movie['vote_count'],
                    'vote_average': movie['vote_average'],
                    'overview': movie['overview'],
                    'poster_path': movie['poster_path'],
                    'genres': movie['genre_ids'],
                    'runtime': movie_detail['runtime'],
                    'original_title': movie['original_title'],
                    'popularity':movie['popularity'],
                    'adult':movie['adult'],
                    'backdrop_path':movie['backdrop_path']
                }

                data = {
                    "model": "movies.movie",
                    "pk": movie['id'],
                    "fields": fields
                }

                total_data.append(data)

    with open("./movies.json", "w", encoding="utf-8") as w:
        json.dump(total_data, w, ensure_ascii=False, indent=4)


get_movie_datas()

  나는 Moive라는 모델을 아래와 같은 속성들로 구성했다! 즉 모델의 속성과 api로 가져오는 필드의 이름은 같아야 한다.. 오타를 주의하자! 만약 같지 않다면 나중에 만들어진 db에 데이터를 넣을 수 없다..!!! 컬럼의 값이 다르니까 데이터가 당연히 안 들어가는 것이다. 

class Movie(models.Model):
    title = models.TextField()  # 영화제목
    original_title = models.TextField() #원 제목
    release_date = models.TextField()  # 개봉연도
    genres = models.ManyToManyField(Genre, blank=True)  # 장르
    poster_path = models.TextField()  # 포스터
    backdrop_path = models.TextField() #백그라운드 포스터
    overview = models.TextField()  # 줄거리
    adult = models.BooleanField()  # 19금
    runtime = models.IntegerField(validators=[MinValueValidator(0)]) #상영시간
    vote_average = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(10)])  # 평점
    vote_count = models.IntegerField(validators=[MinValueValidator(0)])  # 평점 투표 수 
    popularity = models.FloatField(validators=[MinValueValidator(0)]) #인기점수
    like = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='like_movies')

  api를 통해 데이터를 갖고 왔다면 디렉터리에 movies.json 이 생긴다.

장고 프로젝트 폴더 -> movie app 폴더 -> fixtures라는 폴더를 생성해서 생성된 movies.json을 넣어준다.

(나는 장르 테이블도 따로 만들어놓아서 장르 json도 만들었다)

 

fixtures에 대한 내용은 아래 공식 레퍼런스를 참고했다.  내용을 요약하자면 장고는 loaddata때 고정주소를 활용하는데 데이터를 넣을 모델이 있는 app에 fixtures폴더를 생성하고 데이터를 넣어놓으면

맨 아래의 명령어를 실행해서 테이블에 데이터를  넣어준다는 것이다.

 

How to provide initial data for models | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

예) 디렉터리 구조

 위와 같이 구성했다면 이제는 쉽다.  

(반드시 이 과정 이전에  movies앱의 models.py에 테이블을 모델링한 후 makemigrations - migrate를 통해서

db에 테이블을 만들어 놓아야 한다. 아래와 같이 테이블이 만들어져 있어야 한다.)

 

db.sqlite3을 VScode 상에서 열어보려면 다음 익스텐션을 설치해주자 

 

SQLite - Visual Studio Marketplace

Extension for Visual Studio Code - Explore and query SQLite databases.

marketplace.visualstudio.com

 

이제 아래 명령어로 만들어놓은 테이블에 데이터를 넣어주면 된다. 

$ python manage.py loaddata movies.json 

 


 이상으로 내가 장고 쪽에서 작업을 하면서 어려움을 겪었던 부분에 대해 포스팅해보았다.

다음 포스팅에서는 ReactJS와 배포에 대한 내용을 중심으로 포스팅해보겠다. 

 

첫 프로젝트를 회고하려고 시작한 포스팅이지만 너무 두서없이 적은 거 같은 느낌이 없지 않아 있다. 

그래서 다음 포스팅은 조금 더 신경 써야 할 거 같다. 

  

반응형

댓글