프로젝트[Admin Page] (1)

oswaldeff·2021년 2월 20일
post-thumbnail

어디 내보이기는 부족하지만 AWS연결부터 배포까지는 처음해보는 과정이라 시행착오를 기록으로 남기는게 발전할 수 있는 길일것 같아 포스팅을 시작했다.

기회가 되어 Python가상환경에서 Django프레임워크로 시작단계에 있는 한 서비스의 Admin Page를 배포까지 완성해보았다.

사실 Admin Page는 Models.py와 Admin.py, 관리자 계정만 만들면 CRUD기본설정이 되어있지만, 서비스와 DB가 Node.js로 이미 작업되있어서 나로 인해 기존DB들을 갈아엎게 될까봐 무작정 code를 run하는 대신 돌다리도 두들겨가며 진행했다.

📁 Project Tree

프로젝트의 Tree는 아래와 같다.

[name]_admin
├── Pipfile
├── Pipfile.lock
├── README.md
├── requirements.txt
└── [name]_admin_django
    ├── config
    │   └── nginx
    │       └── static.conf
    ├── static
    │   └── admin
    │       └── css
    │       └── fonts
    │       └── img
    │       └── js
    ├── import_export
    │   └── action_formats.js
    │       └── import.css
    ├── manage.py
    ├── .gitignore
    ├── [name]_admin_manager
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    └── [name]_admin_project
        ├── __init__.py
        ├── asgi.py
        ├── my_settings.py
        ├── settings.py
        ├── storages.py
        ├── urls.py
        └── wsgi.py

🗄 MySQL Workbench

이미 작성된 ERD와 DB를 보고 Models.py를 작성하기 위해 MySQL Workbench로 AWS RDS와 연결하였다.


AWS RDS권한을 가진 계정의 username과 host를 입력하고 Store in Keychain에서 password를 입력하고 확인을 눌러주면 연결이 완료되어 해당DB의 schema를 볼 수 있다.

📃 my_settings.py

# SECURITY WARNING: keep the secret key used in production secret!
KEY = '****'

# DATABASES
DB = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #check!
        'HOST': '****',
        'NAME': '****', #check!
        'USER': '****', #check!
        'OPTIONS': {'init_command': 'SET sql_mode="STRICT_TRANS_TABLES"'},
        'PASSWORD': '****', #check!
        'PORT': '3306' #check!
    }
}

DB엔진을 SQLite가 아닌 MySQL로 변경해주어야 한다.
AWS RDS에 대해 나머지 값들은 차례대로 설정.
(보안관련내용은 편의상 별로 표기하였다.)

📃 settings.py

보안을 위하여 Django에서 세션과 비밀번호, 쿠키, 암호화된 값들에 대한 SECRET_KEY와 AWS RDS의 연결정보가 기재된 DATABSES를 my_settings에 따로 선언하여 settings로 import해서 사용했다.
AWS S3연결시 ACESS_KEY 역시 my_settings에 선언할 것이다.

from pathlib import Path
from .my_settings import KEY, DB, MY_AWS_ACESS_KEY_ID, MY_AWS_SECRET_ACESS_KEY
import os
import pymysql
import boto3

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = KEY

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True #True -> False (on server)

ALLOWED_HOSTS = ['.compute.amazonaws.com', '127.0.0.1', 'localhost']

pymysql.version_info = (1, 4, 2, "final", 0)
pymysql.install_as_MySQLdb()

pymysql설치한 후, 속도와 호환성을 위해 MySQL형태로 사용하겠다는 pymysql.install_as_MySQLdb()을 작성했다.
MySQL client버전을 읽는부분이 pymysql 내부코드와 호환이 안될 수 있다고 하여 pymysql.version_info = (1, 4, 2, "final", 0)을 작성! (장고2.0부터 충돌이 나는 이슈가 있다고 한다.)

AWS EC2를 통해 runserver를 기동할 경우를 위해 ALLOWED_HOSTS에는 아마존url을 추가했다.

📃 Models.py

class shop(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=255, null=True)
    .
    .
    .
    def __str__(self):
        return self.name
        
class shop_review(models.Model):
    id = models.AutoField(primary_key=True)
    userId = models.ForeignKey(user, blank=True, null=True, on_delete=models.SET_NULL, db_column='userId')
    createdAt = models.DateTimeField(auto_now_add=True)
    updatedAt = models.DateTimeField(auto_now=True)
    '
    '
    '
    class Meta:
        db_table = 'shop_reviews'

기존의 DB Field와 호환이 되도록 모델들을 작성하였다.

장고는 기본적으로 id를 따로 선언하지 않아도 models.AutoField(primary_key=True)로 알아서 작성해주지만 id값은 필수요건이니 아직 생략을 멋대로 하고싶지는 않아서 작성해주었다.

만약 처음부터 임의로 Field들을 작성하여 model들을 구축했다면 아래사항들을 몰랐을텐데, 이래서 혼자하는 프로젝트보다 협업할 때 배우는 점이 많다는 말이 더 크게 와닿는 것 같다.

  1. str method: 위와 같이 작성된 shop모델의 경우, default는 shop.object이기 때문에 테이블에 생성된 객체가 admin page에서 shop이 되도록 만들어준다.
    ex) admin page에서 데이터 생성시, shop.object(1)가 아닌 shop(1)이 된다.

  2. db_column: 컬럼명의 디폴트값은 필드명인데, 다르게 쓸 경우 지정한다고 한다.

  3. DataTimeField: settings에서 TIME_ZONE과 DATETIME_FORMAT을 통해 형식지정.
    추가적으로, USE_TZ값은 한국(Asia/Seoul)에서는 일광절약시간제를 사용하지 않으므로 False로 해주는것이라고 한다.
    (일광절약시간제란 하절기에 표준시를 원래 시간보다 한 시간 앞당긴 시간을 쓰는 것을 말한다고 한다는데.. 처음 들어봤다.)

  4. db_table: Meta클래스 아래에서 db_table을 통해 호환면에서 오류가 나지않도록 기존 작성된 테이블명과 동일하게 작성해주었다. db_table을 사용하지 않는다면 모델명 앞에 앱 이름이 붙어서 온다. 즉, [name]_admin_manager_shop_review로 생성된다.

📃 Admin.py

class shop_admin(ImportExportModelAdmin):
    # resource_class = shop_resource
    list_display = [
    	'id',
        'name',
        .
        .
        .
        ]
    
    #list_per_page
    
    list_filter = [
    	.
        .
        .
        ]
    
    search_fields = [
    	.
        .
        .
        ]
    
    ordering = [
        '-updatedAt',
        '-createdAt'
    	]
.
.
.
# regester
admin.site.register(shop, shop_admin)

# page header
admin.site.site_header = '[name] Admin Page'
admin.site.index_title = ''

당연히 가능할 것이라 생각했지만 역시 django admin이 아닌 다른 header를 선언할 수 있었다.

admin.ModelAdmin이 아닌 ImportExportModelAdmin을 사용한 이유는 django-import-export모듈로 csv파일로도 DB를 관리하기 위함이었는데 영어는 제대로 되고, 한글로 된 데이터에서만 문제가 계속 발생하여 일단 보류하였다.
(아무래도 cpc949 <-> utf-8의 인코딩 문제일것 같은데, github에서 django-import-export 코드를 뜯어봐도 인코딩 방식에 손을 댈 수 있는 부분을 찾지못하였다. 일단 보류! 직접 추가 페이지를 만드는 경우도 있지만 widget형태인 해당 모듈로 해결해보고 싶다.)

만약 나중에 서비스의 실사용자가 어느정도 생기고나면 admin.py에서 import matplotlib을 통해 그래프 기능도 추가로 넣어볼 수 있을 것 같다.

0개의 댓글