WeniVooks

검색

Django 베이스캠프

settings 실습

Django 프로젝트가 커지면서 설정 파일(settings.py)도 복잡해지고, 개발환경과 운영환경의 설정이 달라져야 할 필요가 생깁니다. 또한 데이터베이스 비밀번호나 API 키와 같은 중요한 정보를 안전하게 관리해야 합니다. 이번 시간에는 앞서 배운 것과 더불어 settings.py를 여러개의 파일로 나누어 관리하는 방법에 대해 알아보도록 하겠습니다.

1. 개발 환경 설정

  1. Visual Studio Code를 실행하고 작업할 폴더를 엽니다. File > Open Folder에서 Django 프로젝트 폴더를 선택합니다.

  2. 상단의 메뉴 터미널 > 새 터미널 을 선택해 터미널을 엽니다.

  3. 터미널에서 다음 명령어를 실행하여 프로젝트 폴더를 생성하고 이동합니다.

    mkdir 06_2_settings
    cd 06_2_settings
    mkdir 06_2_settings
    cd 06_2_settings
  4. 가상 환경을 생성하고 활성화합니다.

    python -m venv venv
    .\venv\Scripts\activate  # Windows
    source venv/bin/activate  # macOS/Linux
    python -m venv venv
    .\venv\Scripts\activate  # Windows
    source venv/bin/activate  # macOS/Linux
  5. Django와 python-dotenv를 설치합니다.

    pip install django python-dotenv
    pip install django python-dotenv

2. 환경 변수 설정 (.env 파일)

환경 변수는 프로젝트의 설정값들을 외부 파일로 분리하여 관리하는 방법입니다. 특히 비밀번호나 API 키같은 민감한 정보를 코드에서 분리할 수 있습니다.

  1. 프로젝트 최상위 폴더에 .env 파일을 생성합니다.

  2. .env 파일에 다음과 같이 환경 변수를 설정합니다. 여기서 .env는 따옴표 없이 작성합니다. your-secret-key-value는 기존에 가지고 있던 settings.py 파일의 SECRET_KEY 값을 넣어주면 됩니다.

    # 기본 설정 (현재 사용)
    DEBUG=True
    SECRET_KEY=your-secret-key-value
    
    # 데이터베이스 설정 (필요시 사용)
    # DB_NAME=mydatabase
    # DB_USER=myuser
    # DB_PASSWORD=mypassword
    # DB_HOST=localhost
    # DB_PORT=5432
    # 기본 설정 (현재 사용)
    DEBUG=True
    SECRET_KEY=your-secret-key-value
    
    # 데이터베이스 설정 (필요시 사용)
    # DB_NAME=mydatabase
    # DB_USER=myuser
    # DB_PASSWORD=mypassword
    # DB_HOST=localhost
    # DB_PORT=5432
  3. .gitignore 파일에 .env를 추가하여 Git에 환경 변수가 올라가지 않도록 합니다.

    # .gitignore
    .env
    # .gitignore
    .env

3. settings 폴더 구성

settings.py 파일을 여러 개의 파일로 나누어 관리하면 설정을 목적별로 구분하여 관리할 수 있습니다.

  1. config 폴더 안에 settings 폴더를 생성하고, 다음과 같은 구조로 파일들을 만듭니다.

    config/
    ├── settings/
    │   ├── __init__.py
    │   ├── base.py
    │   ├── development.py
    │   └── production.py
    config/
    ├── settings/
    │   ├── __init__.py
    │   ├── base.py
    │   ├── development.py
    │   └── production.py
  2. 기존의 settings.py 파일의 내용을 base.py로 이동하고, settings.py 파일은 삭제합니다. __init__.py 파일은 비워둡니다.

  3. base.py에서 환경 변수를 사용하도록 수정합니다.

    # config/settings/base.py
    import os
    from pathlib import Path
    from dotenv import load_dotenv
     
    # .env 파일 로드
    load_dotenv()
     
    # Build paths inside the project like this: BASE_DIR / 'subdir'.
    BASE_DIR = Path(__file__).resolve().parent.parent.parent
     
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = os.getenv('SECRET_KEY')
     
    # Application definition
    # 기본 장고 앱
    DJANGO_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
     
    # 프로젝트 앱
    PROJECT_APPS = [
        # 'main',
        # 'blog',
    ]
     
    # 서드파티 앱
    THIRD_PARTY_APPS = [
        # 'django_debug_toolbar',
        # 'django_extensions',
    ]
     
    # 설치된 앱
    INSTALLED_APPS = DJANGO_APPS + PROJECT_APPS + THIRD_PARTY_APPS
     
    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
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.getenv('DB_NAME'),
            'USER': os.getenv('DB_USER'),
            'PASSWORD': os.getenv('DB_PASSWORD'),
            'HOST': os.getenv('DB_HOST'),
            'PORT': os.getenv('DB_PORT'),
        }
    }
     
    # Password validation
    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
    LANGUAGE_CODE = 'ko-kr'
    TIME_ZONE = 'Asia/Seoul'
    USE_I18N = True
    USE_TZ = True
     
    # Static files (CSS, JavaScript, Images)
    STATIC_URL = 'static/'
    STATIC_ROOT = BASE_DIR / 'static'
     
    # Default primary key field type
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
    # config/settings/base.py
    import os
    from pathlib import Path
    from dotenv import load_dotenv
     
    # .env 파일 로드
    load_dotenv()
     
    # Build paths inside the project like this: BASE_DIR / 'subdir'.
    BASE_DIR = Path(__file__).resolve().parent.parent.parent
     
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = os.getenv('SECRET_KEY')
     
    # Application definition
    # 기본 장고 앱
    DJANGO_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
     
    # 프로젝트 앱
    PROJECT_APPS = [
        # 'main',
        # 'blog',
    ]
     
    # 서드파티 앱
    THIRD_PARTY_APPS = [
        # 'django_debug_toolbar',
        # 'django_extensions',
    ]
     
    # 설치된 앱
    INSTALLED_APPS = DJANGO_APPS + PROJECT_APPS + THIRD_PARTY_APPS
     
    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
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.getenv('DB_NAME'),
            'USER': os.getenv('DB_USER'),
            'PASSWORD': os.getenv('DB_PASSWORD'),
            'HOST': os.getenv('DB_HOST'),
            'PORT': os.getenv('DB_PORT'),
        }
    }
     
    # Password validation
    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
    LANGUAGE_CODE = 'ko-kr'
    TIME_ZONE = 'Asia/Seoul'
    USE_I18N = True
    USE_TZ = True
     
    # Static files (CSS, JavaScript, Images)
    STATIC_URL = 'static/'
    STATIC_ROOT = BASE_DIR / 'static'
     
    # Default primary key field type
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
  4. development.py 파일 작성:

    # config/settings/development.py
    from .base import *
     
    DEBUG = True
    ALLOWED_HOSTS = ['*']
     
    # 개발 환경 전용 앱 추가
    INSTALLED_APPS += [
        'debug_toolbar',
    ]
     
    # 개발 환경 전용 미들웨어 추가
    MIDDLEWARE += [
        'debug_toolbar.middleware.DebugToolbarMiddleware',
    ]
     
    # 개발 환경 전용 설정
    INTERNAL_IPS = [
        "127.0.0.1",
    ]
    # config/settings/development.py
    from .base import *
     
    DEBUG = True
    ALLOWED_HOSTS = ['*']
     
    # 개발 환경 전용 앱 추가
    INSTALLED_APPS += [
        'debug_toolbar',
    ]
     
    # 개발 환경 전용 미들웨어 추가
    MIDDLEWARE += [
        'debug_toolbar.middleware.DebugToolbarMiddleware',
    ]
     
    # 개발 환경 전용 설정
    INTERNAL_IPS = [
        "127.0.0.1",
    ]
  5. production.py 파일 작성:

    # config/settings/production.py
    from .base import *
     
    DEBUG = False
    ALLOWED_HOSTS = ['www.mysite.com']
     
    # 운영 환경 전용 보안 설정
    SECURE_SSL_REDIRECT = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True
    # config/settings/production.py
    from .base import *
     
    DEBUG = False
    ALLOWED_HOSTS = ['www.mysite.com']
     
    # 운영 환경 전용 보안 설정
    SECURE_SSL_REDIRECT = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True

4. 환경 선택하기

개발 환경과 운영 환경 중 어떤 설정을 사용할지 선택하는 방법은 두 가지가 있습니다.

  1. 환경 변수 사용:

    # manage.py
    import os
    import sys
    from dotenv import load_dotenv
     
    def main():
        load_dotenv()
        """Run administrative tasks."""
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development')
        try:
            from django.core.management import execute_from_command_line
        except ImportError as exc:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            ) from exc
            execute_from_command_line(sys.argv)
     
    if __name__ == '__main__':
        main()
    # manage.py
    import os
    import sys
    from dotenv import load_dotenv
     
    def main():
        load_dotenv()
        """Run administrative tasks."""
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development')
        try:
            from django.core.management import execute_from_command_line
        except ImportError as exc:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            ) from exc
            execute_from_command_line(sys.argv)
     
    if __name__ == '__main__':
        main()
  2. 서버 실행 시 설정 지정:

    # 개발 환경으로 실행
    python manage.py runserver --settings=config.settings.development
     
    # 운영 환경으로 실행
    python manage.py runserver --settings=config.settings.production
    # 개발 환경으로 실행
    python manage.py runserver --settings=config.settings.development
     
    # 운영 환경으로 실행
    python manage.py runserver --settings=config.settings.production

주의사항:

  1. .env 파일은 절대로 Git에 포함시키지 마세요.
  2. 운영 환경의 .env 파일은 별도로 안전하게 보관하세요.
  3. SECRET_KEY는 각 환경마다 다르게 설정하는 것이 좋습니다.
  4. DEBUG는 운영 환경에서 절대 True로 설정하지 마세요.

5. 실행 및 테스트

  1. 개발 환경으로 서버를 실행합니다.

    python manage.py runserver --settings=config.settings.development
    python manage.py runserver --settings=config.settings.development
  2. 브라우저에서 접속하여 개발 환경이 제대로 설정되었는지 확인합니다.

    • DEBUG 모드가 활성화되어 있는지 확인
    • 환경 변수가 제대로 로드되었는지 확인
    • 개발용 도구(예: debug_toolbar)가 정상적으로 동작하는지 확인

이렇게 설정을 분리하면 다음과 같은 장점이 있습니다.

  • 환경별로 다른 설정을 쉽게 관리할 수 있습니다.
  • 보안에 민감한 정보를 코드에서 분리할 수 있습니다.
  • 설정 파일을 목적별로 구분하여 관리할 수 있습니다.
  • 팀원들과 협업할 때 설정 충돌을 줄일 수 있습니다.
6.1 settings6.3 Class Based Views