React + django Rest Framework

2022. 4. 4. 17:06프로그래밍 개발(Development)/React

반응형

리액트(React, React.js 또는 ReactJS)는 자바스크립트 라이브러리의 하나로서 사용자 인터페이스를 만들기 위해 사용된다. 페이스북과 개별 개발자 및 기업들 공동체에 의해 유지보수된다.

React는 싱글 페이지 애플리케이션이나 모바일 애플리케이션 개발에 사용될 수 있다. 대규모 또는 복잡한 리액트 애플리케이션 개발에는 보통 라우팅, API통신 등의 기능이 요구되는데 리액트에는 기본적으로 제공되지 않기 때문에 추가 라이브러리를 사용해야 한다.

페이스북에서 좋아요를 누르고 댓글을 달고 페메를 보내는 건 전부 한 페이지에서 이뤄진다. 넷플릭스 또한 어떤 작품을 누르든 장르 범주를 바꾸지 않는 이상 해당 페이지에서 계속해서 데이터가 바뀌고 DOM구조가 바뀐다. 지속적인 데이터 변화 및 구조가 변경되는 페이지를 전부 ajax와 js, jQuery만으로 구현하면 코드가 어지러워지고 또 이는 유지보수의 어려움을 야기하기 때문에 react가 나온 것이다. 그리고 이 react는 jsx라는 문법을 사용한다. 필수는 아니지만 이를 사용하면 코드 생산성과 퍼포먼스를 높일 수 있다.

 django는 python언어를 기반으로 한 경량 웹프레임워크이다. 더 할 말이 없다. 아무튼 서로 다른 언어로 만들어진 웹프레임워크와 라이브러리가 만나 하나의 서비스로 작동해야 한다.

React는 Node 서버에서 렌더링을 할 수도 있고, React Native를 이용하면 모바일 앱도 만들 수 있다.

 

React와 django rest framework 구조 frontend를 전부 react로 작성하고 그 데이터는 내부통신망의 django-rest-framework를 이용하여 가져오는 방식이다. 외부에는 front로 작성된 부분만 노출되고 동작이 이뤄질 때마다 내부에 개설된 django-rest-framework 네트워크를 통해 가져온다고 보면 된다. 그래서 비즈니스로직과 프론트엔드 동작을 완전히 분리할 수 있고 react의 기능도 온전히 사용가능할 수 있다.

 

React + django rest framework를 이용해서 간단한 어플리케이션을 구현해 보자.

 


개발 스펙

  • python 3.x (필자는 3.8 버전을 사용했다)
  • django
  • djngorestframework
  • npm <- Node.js를 설치하면 함께 설치 된다.
  • yarn <- npm으로 설치

 


django 구축

우선 작업 폴더를 react-django로 정하였다.

python env 가상 환경을 사용해도 되지만 필자는 anaconda의 가상환경을 사용 중이라서 anaconda를 사용해 react라는 가상 환경을 세팅했다.

 

# 가상 환경 실행
D:\work\python\react-django>conda activate react

# django를 설치한다.
(react) D:\work\python\react-django> pip install django

# backend 폴더를 생성하고 django 프로젝트를 생성한다.
# 프로젝트 명 : djangoreactapi
(react) D:\work\python\react-django> mkdir backend
(react) D:\work\python\react-django> cd backend
(react) D:\work\python\react-django\backend>django-admin startproject djangoreactapi .

api로 호출시킬 app을 생성하자.

manage.py가 있는 backend 폴더에서 아래 명령어를 실행하면 된다. 앱의 이름은 post로 하였다.

(react) D:\work\python\react-django\backend> python manage.py startapp post
# app 초기화
(react) D:\work\python\react-django\backend> python manage.py migrate
# migrate 실행. DB를 별도로 설정하지 않아서 sqlite 파일이 생성이 된다.

djangoreactapi/settings.py 파일에서 INSTALLED_APPS 목록에 post 앱을 추가한다.

#backend/djangoreactapi/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

     'post', # app 추가
]

django 내부 웹서버를 실행하여 확인해보자.

정상적으로 실행 됐을 경우 아래와 같이 django 페이지가 보일 것이다.


모델 정의

#backend/post/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200) # title 컬럼
    content = models.TextField()             # content 컬럼

    def __str__(self):
        """A string representation of the model."""
        return self.title

admin.py에 추가

#backend/post/admin.py
from django.contrib import admin

from .models import Post

admin.site.register(Post)

migrate로 변경된 DB를 적용하고, superuser 생성 과정을 알아보자.

# app의 모델 변경 사항을 체크한다
(react) D:\work\python\react-django\backend> python manage.py makemigrations

# 변경 사항을 DB에 반영한다
(react) D:\work\python\react-django\backend> python manage.py migrate

# superuser 생성
(react) D:\work\python\react-django\backend> python manage.py createsuperuser

# 아래와 같이 username, email, password 입력 한다
# email의 경우 필수 입력 사항은 아니다. Enter키로 패스 가능
Username (leave blank to use 'user'): admin
Email address: 
Password: 
Password (again):
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

# 웹 서버 실행하여 확인
(react) D:\work\python\react-django\backend> python manage.py runserver

localhost:8000/admin 주소로 실행하고, createsuperadmin 으로 만든 계정으로 로그인을 해보자.

 

로그인화면

로그인을 하게 되면 아래와 같은 화면이 나오며, 모델을 정의 했던 Post 컨텐츠가 보일것이다.

Post의 Add 버튼을 눌러서 몇개의 컨텐츠를 등록해보자.

모델에서 정의한 title과 content를 입력 하여 추가해보자

추가된 정보는 우측과 같이 리스트 형태로 확인할 수 있다.


django-rest-framework 구성

# djangorestframework를 설치한다.
(react) D:\work\python\react-django> pip install djangorestframework

설치 후 setting.py 파일에 'rest_framework' app을 추가해준다.

#backend/djangoreactapi/settings.py
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    'post',
    'rest_framework', # <- 추가
    
]

...

# ↓↓↓ 추가
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

참고해야할게 DRF는 자동으로 pk값을 index로 지정해서 뿌려준다는 점이다. 이제 api app을 추가하였으니 api루트로 들어왔을 때 데이터를 보낼 수 있게 해야한다. 어떤 형식의 데이터를 보낼지는 post app디렉토리 안의 view.py에서 정해진다. 그리고 중요한게 바로 serializers이다.

 

django + react 앱은 api요청을 통해 데이터를 주고 받는데 많은 사람들이 아다시피 api요청 및 반환값은 거진 데이터포멧이 JSON(JavaScript Object Notation)으로 되어있다. 그래서 반환값을 JSON으로 직렬화(Serialize)해주는 것이 필요하다. 이때 필요한 것이 DRF의 serializers이다. 만들어져있는 파일이 아니니 직접 만들어 작성해야한다.

# backend/post/serializers.py
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        fields = (
            'id',
            'title',
            'content',
        )
        model = Post

이제 view.py를 작성 하자.

# backend/post/views.py
from django.shortcuts import render
from rest_framework import generics

from .models import Post
from .serializers import PostSerializer

class ListPost(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

class DetailPost(generics.RetrieveUpdateDestroyAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

이제 api요청이 왔을 때 Post데이터를 보내야 하니 urls.py를 만들어서 작성하자.

# backend/post/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.ListPost.as_view()),
    path('<int:pk>/', views.DetailPost.as_view()),
]

Post내부의 urls.py를 정의하였으니 이제 루트 디렉토리에서의 urls.py에 이 내용을 반영시켜야 한다.

# backend/djangoreactapi/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('post.urls')),
]

이제 api요청이 제대로 작동하는지 확인해보자.

runserver를 실행하여 서버를 띄우고. localhost:8000/api 접속해보면 아래 화면을 확인해볼 수 있다.

아까 /admin에서 등록했던 내용들이며, 주소 뒤에 id를 지정해주면 post/urls.py에 선언해놨던 url패턴에 따라서 해당 Post만 조회할 수 있다.

이제 django api서버의 준비는 완료된 것이다. 그리고 마지막으로 script태그 안에서의 api를 통한 데이터의 접근제어를 위해 HTTP 접근제어 규약(CORS : Cross-Origin Resource Sharing)을 추가해야한다.

기존의 HTTP요청에서는 img나 link태그 등으로 다른 호스트의 css나 이미지파일 등의 리소스를 가져오는 것이 가능한데 script태그로 쌓여진 코드에서의 다른 도메인에 대한 요청은 Same-origin policy에 대한 규약으로 인해 접근이 불가하다. 하지만 아다시피 react는 거의가 script요청에 의해 페이지를 그리는 방식이므로 이제 대한 제약 해제가 필요하다. django로 돌아가고 있는 api서버와 페이지를 그려주는 react서버는 명목상 아예 다른 서버로 구분되기 때문이다.

 

이러한 작업을 패키지 하나를 설치하여 추가함으로써 해결할 수 있다.

# django-cors-headers를 설치한다.
(react) D:\work\python\react-django> pip install django-cors-headers

setting.py파일의 INSTALLED_APPS과 MIDDLEWARE에 추가해주며, CORS_ORIGIN_WHITELIST를 추가해 준다.

# backend/djangoreactapi/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    'post',
    'rest_framework',
    'corsheaders', # <- 추가
]

...

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',     # <- 추가
    'django.middleware.common.CommonMiddleware', # <- 추가
    
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

...

# script안에서의 리소스 요청을 허용할 도메인 추가
# ↓↓ 추가
CORS_ORIGIN_WHITELIST = [
    'localhost:3000/'
]

간단한 react앱을 작성하여 django에서 전송해주는 데이터를 받아보자.


React 앱 생성

작업 초반에 backend디렉토리를 만들었던 django-react디렉토리로 돌아가서 create-react-app을 통해서 react앱을 작성할 수 있는 환경을 조성할 것이다. 일단 그전에 create-react-app이 필요하다.

create-react-app 설치 하는 방법은 npm, yarn 둘중에 아무거나 사용해도 무방하다.

yarn 사용 이유는 패키지 설치가 빠르고 보안성이 좋기 때문에 사용한다.

# yarn 설치
(react) D:\work\python\react-django> npm install -g yarn

# npm을 이용해서 react app 설치
(react) D:\work\python\react-django> npm install -g create-react-app

# yarn을 이용해서 react app 설치
(react) D:\work\python\react-django> yarn global add create-react-app

-----------------------------------------------------------------------

(react) D:\work\python\react-django> create-react-app frontend # cra로 frontend이라는 리액트 앱 만들기
(react) D:\work\python\react-django> cd frontend
(react) D:\work\python\react-django\frontend> yarn start

http://localhost:3000/에 들어가면 react 앱을 볼 수 있다.

이제부터는 frontend요청을 처리할 웹서버와 backend api요청을 처리할 두 개의 웹서버가 작동돼야한다. 아마 이 react앱을 만드는 과정에서 django웹서버가 중지됐을 것이다. 내부 웹서버를 실행하면 cli가 http요청을 출력해주는 형태로 freeze되기 때문이다.

커맨드창을 하나 더 열어서 django 서버와 react 서버를 동시에 실행을 하자.

(react) D:\work\python\react-django\backend> python manage.py runserver
(react) D:\work\python\react-django\frontend> yarn start

(좌) django (우) react

이제는 react앱에서 django가 보내주는 데이터를 받아볼 차례이다. create-react-app 명령어로 생성된 frontend디렉토리에서 src/App.js를 아래와 같이 수정하자.

# frontend/src/App.js
import React, { Component } from 'react';

class App extends Component {
    state = {
        posts: []
    };

    async componentDidMount() {
        try {
            const res = await fetch('http://127.0.0.1:8000/api/');
            const posts = await res.json();
            this.setState({
                posts
            });
        } catch (e) {
            console.log(e);
        }
    }

    render() {
        return (
            <div>
                {this.state.posts.map(item => (
                    <div key={item.id}>
                        <h1>{item.title}</h1>
                        <span>{item.content}</span>
                    </div>
                ))}
            </div>
        );
    }
}

export default App;

npm start로 실행된 localhost:3000 웹 화면을 보면 아래와 같이 데이터를 확인 할 수 있다.

완료된 폴더 구조는 아래와 같다.

react와 django rest framework를 연동하여 기본적인 앱을 만들어 보았다. 상황에 따라서 django template의 페이지를 제공할 수도 있고, react로 만들어진 SPA를 제공할 수도 있다.

 

github  : https://github.com/Byeongin-Jeong/react-django

반응형