ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Django] DRF를 이용한 API 서버 만들기 (1)
    개발/Python 2021. 12. 24. 20:19

    새로운 프로젝트를 시작하면서 장고를 사용했다.

    웹 서비스를 만드는 프로젝트고 흔히들 사용하는 기본적인 게시판 기능이 포함된 서비스를 만들었다.

     

    이전에 소개딩이랑 이것저것 준비하면서 장고를 사용했고 이번 프로젝트를 마무리하면서 한번 정리 해보고자 한다.

    사실 내용은 볼품없다. 그냥 뻔한 내용이고 장고를 장고답게 사용하지 못한 것 같다.

     

    개발 환경은 다음과 같다.

    Ubuntu 20.04 LTS + MySQL + Python 3.8

     

    개발 서버는 내 개인 서버와 AWS 라이트 세일을 사용했다.

    파이썬과 기타 도구들은 기본적으로 설치되어있다고 가정하겠다.

     

    기본적으로 이 글을 작성하는 이유는 '검색의 불편함' 때문이다. 

    물론 나의 글과 구현 방법은 정말 야매고 비효율적인 스파게티 코드로 이루어져 있다.

    하지만, 이런 저런 기능들을 구현하면서 여기 저기를 찾아봐도 내가 이해를 못한건지...

    설명이 부족하다고 느껴진 부분이 있었다. 또, 사람마다 구현 방법이 달라 적용법이 달라지는 경우도 있었다.

     

    이를 위해 전체 과정을 적어보려 한다.

     

    1. 장고 설치

    python3 -m virtualenv venv
    source ./venv/bin/activate
    pip3 install django wheel mysqlclient djangorestframework

    우선 내 환경에 장고를 사용하기 위해서 파이썬 가상환경을 설치했다.

    그 후 가상환경에 기본적인 파이썬 패키지를 설치한다.

    mysqlclient를 설치하면서 에러가 하나 발생한다면 다음 링크를 확인해자.

     

    https://floodnut.tistory.com/15

     

    OSError: mysql_config not found

    OSError: mysql_config not found mysql_config --version mariadb_config --version mysql_config --libs ---------------------------------------- Command "python setup.py egg_info" failed with error code..

    www.floodnut.com

     

    django-admin startproject <프로젝트디렉토리명>
    django-admin startproject config
    cd ./config

    장고를 설치했다면 기본 프로젝트를 만들 수 있다.

    위와 같이 장고 프로젝트를 생성해보자.

    장고 프로젝트 생성

    장고 프로젝트를 생성했다면 위와 같은 파일들을 볼 수 있다.

    그렇다면, 이제 서비스 로직을 담당할 앱을 생성해보자.

    앱을 통해 서비스를 기능 별로 나눌 수 있다.

     

    django-admin startapp <앱명>
    django-admin startapp app1

     

    장고 앱 생성

     

    장고는 프로젝트로 생성된 파일을 통해 장고의 전체적인 설정을 관리할 수 있다.

    앱에서는 세부적인 기능을 구현하면 된다.

     

    2. 장고 기본 설정

    더보기
    from pathlib import Path
    
    # Build paths inside the project like this: BASE_DIR / 'subdir'.
    BASE_DIR = Path(__file__).resolve().parent.parent
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 'django-insecure--hyg^7zd&1z5b8+@8*epa&00bm9nqy3hnmj^3fvro(@0tkn@2l'
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
    
    MIDDLEWARE = [
        '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',
    ]
    
    ROOT_URLCONF = 'config.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'config.wsgi.application'
    
    # Database
    # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    
    # Password validation
    # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    # Internationalization
    # https://docs.djangoproject.com/en/3.2/topics/i18n/
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.2/howto/static-files/
    
    STATIC_URL = '/static/'
    
    # Default primary key field type
    # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
    
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

     

    전체 코드는 조금 길어 접었다. 프로젝트 디렉토리의 settings.py의 세부적인 코드를 따로 보자.

    우리가 기본적으로 먼저 신경써줘야하는 부분이 있다.

    ## 기본 값
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = "서버_비밀키"
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    ## 변경한 값
    
    import sys
    
    ...
    
    # json parse for key
    with open('config/keys.json') as key_file:
        json_file = json.load(key_file)
        json_secret_key = json_file["settings-secret-key"]
        
    
    SECRET_KEY = json_secret_key

    기본 값과 변경한 값을 비교해보자.

    서버 비밀키는 서버 구동을 위해 필수적으로 작성해야한다.

    이를 관리하기 위해 실 서비스에서는 환경 변수나 외부 파일을 통해 키를 넣어줘야 한다.

    나는 외부에 JSON 파일을 생성하고 서버의 중요한 설정 값들을 불러오도록 했다.

    더 나은 방안은 .env를 활용해서 서버 구동 시점에서 환경변수로 넣는 편이 더 좋을 것 같다.

     

    DEBUG 옵션은 개발 단계를 도와주는 옵션이다. 당연히 실 서비스 단계에서는 False 처리 해야한다.

     

     

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        
        ##내가 생성한 장고 앱 추가
        'app1',
    ]

     

    두 번째로는 기능적인 면이다.

    INSTALLED_APPS는 리스트로 관리되는데 앞서 생성한 장고 앱들 이 곳에 추가해줘야 앱을 사용할 수 있다.

     

    ## 기본값 SQLite3
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    
    ## 변경한 값 MySQL
    DATABASES = {
        'default': {
            'ENGINE': "django.db.backends.mysql",
            'NAME': '데이터베이스명',
            'USER': '데이터베이스계정명',
            'PASSWORD': '데이터베이스계정패스워드',
            'HOST': '접근할 호스트, 기본 값은 localhost',
            'PORT': '접근할 데이터베이스 포트, 기본 값은 3306',
        }
    }

    또, 데이터베이스는 MySQL을 사용하기로 했으니 위와 같은 형태로 변경한다.

    물론 데이터베이스의 계정과 계정 권한, 데이터베이스는 이미 생성했다고 가정하겠다.

     

     

    # 허용할 호스트
    ALLOWED_HOST = []
    
    # 전체 허용
    ALLOWED_HOST ['*']
    
    # 특정 호스트 허용
    ALLOWED_HOST ['127.0.0.1', ...]

    장고 서버에 접근할 수 있는 호스트들을 위와 같이 지정할 수 있다.

    이를 통해 특정 호스트만 장고 서버에 접근할 수 있게 된다.

     

    AUTH_USER_MODEL = 'accounts.User'

    추가적으로 위와 같은 옵션을 추가해서 기본 유저 테이블명을 변경하겠다.

    장고는 기본적으로 유저관리를 위한 auth_user라는 테이블을 데이터베이스에 생성한다.

    나는 DRF를 활용한 구글 소셜 인증 기능을 추가하기 위해 위와 같이 설정했다.

     

     

    3. 장고 서버 실행

    # 서버가 실행되는 기본 포트는 8000번임.
    python3 manage.py runserver
    
    # 포트를 변경하고자 한다면?
    python3 manage.py runserver <포트번호>
    
    # 특정 ip를 통해 포트로 포워딩 하고자 한다면?
    python3 manage.py runserver ip:포트번호
    
    # 접근하는 소스의 전체 ip를 포트로 포워딩 하고자 한다면?
    python3 manage.py runserver 0:포트번호

    장고 서버 실행

     

     

    위와 같이 장고 서버는 여러 옵션을 통해 실행 할 수 있다.

    브라우저에서 다음과 같은 화면을 본다면 장고 서버가 실행된 것이다.

     

    만약 데이터베이스나 여러 serializers 등에 추가, 변경이 생긴다면 그냥 서버를 실행시키지말고 마이그레이션을 적용해야한다. 이 부분은 차차 알아보겠다.

     

     

     

     

    여기까지는 모든 장고 튜토리얼에서 확인할 수 있는 기본적인 내용이다. 내용을 보완하면서 포스트를 계속 작성해보겠다.

    댓글

Designed by Tistory.