[RWDRFP] 프로젝트 구조



관련글을 전부 보고싶으시다면
모바일일 경우, 이 글 하단
PC일 경우, 우측 상단
검색 창에서 RWDRFP를 검색해 주세요
(Real World Django Rest Framework Project)



1. 프로젝트 구조

어제 프로젝트를 만들었습니다. 그리고 제가 이것저것 정리하고 작성해서 Github에 올려두었습니다.



어제는 blog만 앱을 만들었었는데요. 아래에 파일 스트럭처 스크린샷을 올려 두었습니다. 자세히보면, blog, authentication, core 3개의 폴더가 apps 안에 있습니다. blog와 authentication은 앱입니다. 그리고 core는 그냥 폴더에요. 


어제 만들지 않았던 authentication 앱을 만들어 줍니다.

$ django-admin startapp authentication




2. settings 폴더 만들기

그리고 파일 세팅을 시작합니다.

여기서 나오는 모든 파일세팅은 제 스타일 입니다. Django 개발자 분들마다 본인들이 편한 스타일이 있고 기업에서 한개의 프로젝트를 여러명에서 진행 할 때에는 미리 이런 구조를 먼저 정해놓고 시작합니다. 옳고 그름은 없습니다. 보기 편하고 자신한테 편하면 그게 맞는 구조 입니다. 


우선 저는 처음 시작할때 5개의 setting 파일을 settings 폴더를 하나 만든 후 넣습니다.

그리고 settings 폴더에 __init__.py를 만들어 다음 처럼 입력해 줍니다.

from dingrr.settings.keys import *
from dingrr.settings.settings import *
from dingrr.settings.external import *
from dingrr.settings.dist import *
from dingrr.settings.debug import *

너무 명료하지만 소개를 해드리겠습니다.


keys.py프로젝트 폴더 안에 .key_store 라는 파일이 있습니다. 그 파일에서 민감한 정보를 가지고 있는 키 정보를 파싱합니다.
settings.pyDjango가 기본적으로 만들어주는 기본적인 setting(기존 settings.py 내용들)
external.pyDjango는 사용하고 있는 서비스 지만, 해당 서비스는 Django가 없어도 잘 돌아가는 서비스들 (예, MySQL, Redis, AWS 세팅 등)
dist.py프로덕션 환경 세팅
debug.py개발 환경 세팅


한 파일로 해도 됩니다.

하지만, 개발이 거의 끝날때 되면 1000줄이 넘어갈 수도..



그리고 바꿔 주어야 하는 사항

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

** 위 부분을 아래와 같이 변경합니다.

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

** BASE DIR 까지 가는데 settings 라는 폴더가 하나 더 생겼으니까요.



윈도우를 쓰신다면 아래처럼!

import platform
# SECURITY WARNING: don't run with debug turned on in production!
if platform.system() == "Windows":
DEBUG = True
ALLOWED_HOSTS = ['*']
BASE_URI = 'http://127.0.0.1:8000'
else:
DEBUG = False
ALLOWED_HOSTS = ['*']
BASE_URI = 'https://dingrr.com'



지난 편에 설치했던 라이브러리를 설정

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

'corsheaders',
'django_extensions',
'rest_framework',

'apps.blog',
'apps.authentication',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

미들웨어에 CorsMiddleware 추가


** CORS란? Cross-Origin Resource Sharing의 준말로, 다른 도메인에서 실행 중인 어플리케이션에서 우리 백엔드 서버에 접근 권한을 부여할 수 있도록합니다. 프론트엔드는 추후 dingrr.com 에서 실행 될 것이고 우리 DRF는 api.dingrr.com 에서 실행될 것이라 도메인이 달라 해당 설정이 없으면 접근할 수 없습니다.


.key_store 예시

[THIS_IS_INTERNAL_USE_ONLY]
NEVER_SHARE = Please
NEVER_UPLOAD = Anywhere
IF_YOU_DONT_KNOW = JUST_LEAVE_IT


[DB]
HOST_DEBUG = localhost
HOST_PROD = localhost
PORT = 3306
USER = your_user
PW = your_pw
CHARSET = utf8mb4
DB_NAME = your_db_name



해당 텍스트는 configparser 라는 라이브러로 파싱이 가능합니다. 아래는 keys.py  입니다.

from configparser import ConfigParser


conf = ConfigParser()
conf.read('.key_store')
CONST_DB_HOST_DEBUG = conf['DB']['HOST_DEBUG']
CONST_DB_HOST_PROD = conf['DB']['HOST_PROD']
CONST_DB_PORT = int(conf['DB']['PORT'])
CONST_DB_USER = conf['DB']['USER']
CONST_DB_PW = conf['DB']['PW']
CONST_DB_NAME = conf['DB']['DB_NAME']
CONST_DB_CHARSET = conf['DB']['CHARSET']



뿐만아니라, 데이터베이스 세팅을 external.py로 옮기고 mysql을 사용하도록 세팅해 줍니다.

from dingrr.settings import *

if DEBUG:
DATABASES = {
'default': {
'NAME': CONST_DB_NAME,
'ENGINE': 'django.db.backends.mysql',
'USER': CONST_DB_USER,
'PASSWORD': CONST_DB_PW,
'HOST': CONST_DB_HOST_DEBUG,
'PORT': CONST_DB_PORT,
'OPTIONS': {
'charset': CONST_DB_CHARSET,
},
}
}
else:
DATABASES = {
'default': {
'NAME': CONST_DB_NAME,
'ENGINE': 'django.db.backends.mysql',
'USER': CONST_DB_USER,
'PASSWORD': CONST_DB_PW,
'HOST': CONST_DB_HOST_PROD,
'PORT': CONST_DB_PORT,
'OPTIONS': {
'charset': CONST_DB_CHARSET,
},
}
}




4. Core 폴더는 뭐하는 폴더?

Core는 제가 앞으로 상속 받아올 Parent 모델이나, 각종 세팅등을 모아 놓는 곳입니다. DB모델링을 할때 DB에 해당 데이터 생성일자와 업데이트 일자는 기본적으로 찍기 때문에 core폴더안에 models.py를 다음 처럼 설정해 줍니다.

from django.db import models


class TimestampedModel(models.Model):
datetime_update = models.DateTimeField(auto_now=True)
datetime_created = models.DateTimeField(auto_now_add=True)


class Meta:
abstract = True
ordering = ['-datetime_update', '-datetime_created']




5. Hello World.

Hello World를 할 것은 아니고요. DB조회 후 API 제공 한번 해보겠습니다. 잘 작동하는지 샘플 예제 이므로,  Django RestFramework 공홈에 있는 Quickstart 예제를 따왔습니다.

우선 DB를 마이그레이션 합니다.

$ python manage.py makemigrations
$ python manage.py


authentication  앱에 serializers.py 가 없다면 만들어 주고 있다면 이렇게 작성합니다.

from django.contrib.auth.models import User, Group
from rest_framework import serializers



class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ['url', 'name']


class UserSerializer(serializers.HyperlinkedModelSerializer):
groups = serializers.HyperlinkedRelatedField(         many=True, view_name='authentication:user-detail', read_only=True)
class Meta:
model = User
fields = ['url', 'username', 'email', 'groups', 'date_joined']
extra_kwargs = {'url': {'view_name': 'authentication:user-detail'}}

장고는 직렬화(시리얼라이저가 따로 있어서 쿼리셋을 이렇게 해야합니다. 시간을 표기하는 방식도 다르고 해서 JSON으로 만들어주는 과정입니다. 또한 DRF는 기본적으로 url 필드가 (모델이름)-detail 로 설정되는데 우리는 현재 다수의 앱이 있고 네임스페이스도 설정하여 user-detail을 찾을 수 없을 것입니다. 그래서 위처럼 user-detail에 대한 자세한 정의를 추가 키워드인수로 전달하여 처리합니다.

DRF 공식 홈페이지에 가면 Group과 User 시리얼라이져가 같은데 그렇게 하면 우리 프로젝트에서는 에러를 뿜을 거에요~ 


**다른 방법:

다른 방법 있는데 무시합니다. 추천 방법이 아닙니다! (절대 귀찮아서가 아님!!) 네임스페이스 사용은 권장 사항이기 때문입니다.(여기까지만 말씀드리면 아시는 분은 다 아실.. 딩글아.. 이거 칠 시간에 설명하지 그랬어..?)


auth앱에 views.py 작성

from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from rest_framework import permissions
from apps.authentication.serializers import UserSerializer, GroupSerializer


class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
print(1)
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]


class GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
permission_classes = [permissions.IsAuthenticated]


auth앱에 URL 작성

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import (
UserViewSet, GroupViewSet
)

router = DefaultRouter(trailing_slash=False)
router.register(r'auth', UserViewSet)
router.register(r'groups', GroupViewSet)

urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]



이제 실행 해 보아요.

$ python manage.py

그리고 http://127.0.0.1:8000/api/auth 로 이동 해 봅니다. GUI이니 이것 저것 눌러보며 확인해 보세요.



POSTMAN 같은 외부 프로그램이나 Curl로도 테스트 가능합니다.


이제 디펜던시 리스트를 만들어 줍니다. (내가 설치하고 있는 라이브러리까지 통째로 올려서 공유하는 자원낭비를 할수 없어서 이렇게 진행합니다.

$ pip freeze > requirements.txt => 디펜던시 리스트를 만들어 줍니다
$ pip install -r requirements.txt => 디펜던시 리스트로 설치



  • [[a.original_name]] ([[a.file_size | fileSizer]])
좋아요[[ postLike | likePlus ]]
공유
라이언

“Lead Python Engineer”

댓글 [[totalCommentCount]]
[[ comment.author__nick_name ]] [[ comment.datetime_updated | formatDate]] (수정됨)

[블라인드 처리된 글 입니다.]

답장
[[ sub.author__nick_name ]] [[ sub.datetime_created | formatDate ]] (수정됨)

취소
댓글을 남겨주세요.
'Django' 관련 최신 포스트
[[ post.title ]]
[[ post.datetime_published_from | DateOnly ]]