유형 힌트로 Django 설정 간소화: Pydantic 튜토리얼

게시 됨: 2022-07-22

Django 프로젝트는 새로운 환경을 추가할 수 있는 강력하고 확장 가능한 방법이 없었기 때문에 저를 좌절시켰습니다. pydantic 및 Python 유형 힌트를 결합하여 필요한 강력한 기반을 구축했습니다.

PEP 484에 설명된 대로 유형 힌트는 정적 분석을 지원하지만 이러한 동일한 주석은 런타임에도 사용할 수 있습니다. pydantic과 같은 타사 패키지는 이 추가 메타데이터를 사용하는 런타임 유형 검사를 제공합니다. Pydantic은 Python 유형 힌트를 사용하여 설정 메타데이터를 관리하고 런타임 데이터 유효성 검사를 수행하는 데 도움을 줍니다.

이 pydantic 튜토리얼은 Django에서 pydantic 설정 관리를 사용하는 광범위한 긍정적인 효과를 보여줍니다.

우리의 구성은 Twelve-Factor App 웹사이트에 설명된 모범 사례를 따릅니다.

  1. 비 상수 및 비밀 구성을 환경 변수로 정의하십시오.
  2. 개발 환경에서는 .env 파일에 환경 변수를 정의하고 .env.gitignore 에 추가합니다.
  3. 클라우드 공급자의 메커니즘을 사용하여 QA, 스테이징 및 프로덕션 환경에 대한 (비밀) 환경 변수를 정의합니다.
  4. 환경 변수에서 자체적으로 구성하는 단일 settings.py 파일을 사용합니다.
  5. pydantic을 사용하여 Django 구성을 정의하는 Python 변수에서 환경 변수를 읽고, 확인하고, 유효성을 검사하고, 유형 변환합니다.

또는 일부 개발자는 settings_dev.pysettings_prod.py 와 같은 여러 설정 파일을 만듭니다. 불행히도 이 접근 방식은 확장성이 좋지 않습니다. 코드 중복, 혼란, 찾기 힘든 버그 및 더 높은 유지 관리 노력으로 이어집니다.

앞서 언급한 모범 사례를 사용하여 여러 환경을 추가하는 것은 쉽고 잘 정의되어 있으며 오류가 없습니다. 더 복잡한 환경 구성을 탐색할 수도 있지만 명확성을 위해 개발과 프로덕션이라는 두 가지에 중점을 둘 것입니다.

이것은 실제로 어떻게 보입니까?

Pydantic 설정 관리 및 환경 변수

이제 우리는 개발 및 생산 모두의 예에 초점을 맞춥니다. 각 환경이 설정을 다르게 구성하는 방법과 pydantic이 각각을 지원하는 방법을 보여줍니다.

예제 애플리케이션에는 Django 지원 데이터베이스가 필요하므로 데이터베이스 연결 문자열을 저장해야 합니다. Python 패키지 dj-database-url을 사용하여 데이터베이스 연결 구성 정보를 환경 변수 DATABASE_URL 로 이동합니다. 이 변수는 str 유형이고 다음과 같이 형식화됩니다.

 postgres://{user}:{password}@{hostname}:{port}/{database-name} mysql://{user}:{password}@{hostname}:{port}/{database-name} oracle://{user}:{password}@{hostname}:{port}/{database-name} sqlite:///PATH

개발 환경에서는 사용 편의성을 위해 Docker 포함 PostgreSQL 인스턴스를 사용할 수 있지만 프로덕션 환경에서는 프로비저닝된 데이터베이스 서비스를 가리킵니다.

정의하려는 또 다른 변수는 부울 DEBUG 입니다. Django의 DEBUG 플래그는 프로덕션 배포에서 절대 켜지 않아야 합니다. 개발 중에 추가 피드백을 받기 위한 것입니다. 예를 들어 디버그 모드에서 Django는 예외가 발생하면 자세한 오류 페이지를 표시합니다.

개발 및 생산에 대한 서로 다른 값은 다음과 같이 정의할 수 있습니다.

변수 이름 개발 생산
DATABASE_URL postgres://postgres:mypw@localhost:5432/mydb postgres://foo1:foo2@foo3:5432/foo4
DEBUG True False

pydantic 설정 관리 모듈을 사용하여 환경에 따라 이러한 다양한 환경 변수 값 세트를 관리합니다.

준비 단계

이를 실행하기 위해 다음 콘텐츠로 단일 .env 파일을 생성하여 개발 환경 구성을 시작합니다.

 DATABASE_URL=postgres://postgres:mypw@localhost:5432/mydb DEBUG=True

다음으로 .env 파일을 프로젝트의 .gitignore 파일에 추가합니다. .gitignore 파일은 잠재적으로 민감한 정보를 소스 제어에 저장하는 것을 방지합니다.

이 접근 방식은 개발 환경에서 잘 작동하지만 프로덕션 환경 사양에서는 다른 메커니즘을 사용합니다. 우리의 모범 사례에 따르면 프로덕션 환경 변수는 환경 비밀을 사용합니다. 예를 들어 Heroku에서 이러한 비밀은 Config Vars라고 하며 Heroku 대시보드를 통해 구성됩니다. 배포된 애플리케이션에서 환경 변수로 사용할 수 있습니다.

Config Vars 웹 인터페이스의 스크린샷. 왼쪽 사이드바에는 다음과 같은 설명이 있습니다. "구성 변수는 앱이 작동하는 방식을 변경합니다. 직접 만드는 것 외에도 일부 추가 기능은 자체적으로 함께 제공됩니다." 기본 섹션에는 각각 2개의 텍스트 필드, 연필 아이콘 및 X 아이콘이 있는 2개의 행이 있습니다. 텍스트 필드에는 이전 테이블의 "변수 이름" 및 "생산" 열과 동일한 데이터가 있습니다. 오른쪽 상단 모서리에는 "구성 변수 숨기기"라는 버튼이 있습니다.

그런 다음 두 환경 중 하나에서 이러한 값을 자동으로 읽도록 응용 프로그램의 구성을 조정해야 합니다.

Django의 settings.py 구성

우리 예제의 필수 구조를 제공하기 위해 새로운 Django 프로젝트로 시작합시다. 다음 터미널 명령을 사용하여 새 Django 프로젝트를 스캐폴딩합니다.

 $ django-admin startproject mysite

이제 mysite 프로젝트에 대한 기본 프로젝트 구조가 생겼습니다. 프로젝트의 파일 구조는 다음과 같습니다.

 mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py

settings.py 파일에는 애플리케이션 구성을 관리할 수 있는 상용구 코드가 포함되어 있습니다. 관련 환경에 맞게 조정해야 하는 미리 정의된 기본 설정이 많이 있습니다.

환경 변수와 pydantic을 사용하여 이러한 애플리케이션 설정을 관리하려면 다음 코드를 settings.py 파일의 맨 위에 추가하세요.

 import os from pathlib import Path from pydantic import ( BaseSettings, PostgresDsn, EmailStr, HttpUrl, ) import dj_database_url # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent class SettingsFromEnvironment(BaseSettings): """Defines environment variables with their types and optional defaults""" DATABASE_URL: PostgresDsn DEBUG: bool = False class Config: """Defines configuration for pydantic environment loading""" env_file = str(BASE_DIR / ".env") case_sensitive = True config = SettingsFromEnvironment() os.environ["DATABASE_URL"] = config.DATABASE_URL DATABASES = { "default": dj_database_url.config(conn_max_age=600, ssl_require=True) } DEBUG = config.DEBUG

이 코드는 다음을 수행합니다.

  • pydantic의 BaseSettings 클래스에서 상속하는 SettingsFromEnvironment 클래스를 정의합니다.
  • DATABASE_URLDEBUG 를 정의하고 Python 유형 힌트를 사용하여 유형 및 선택적 기본값을 설정합니다.
  • 시스템 환경 변수에 없는 경우 .env 파일에서 변수를 찾도록 pydantic에 지시하는 Config 클래스를 정의합니다.
  • Config 클래스를 config 개체로 인스턴스화합니다. 원하는 변수는 config.DATABASE_URLconfig.DEBUG 로 사용할 수 있습니다.
  • 이러한 config 멤버에서 일반 Django 변수 DATABASESDEBUG 를 정의합니다.

모든 환경에서 동일한 코드가 실행되고 pydantic은 다음을 처리합니다.

  • 환경 변수 DATABASE_URLDEBUG 를 찾습니다.
    • 프로덕션에서와 같이 환경 변수로 정의된 경우 해당 변수를 사용합니다.
    • 그렇지 않으면 .env 파일에서 해당 값을 가져옵니다.
    • 값을 찾지 못하면 다음을 수행합니다.
      • DATABASE_URL 의 경우 오류가 발생합니다.
      • DEBUG 의 경우 기본값 False 를 할당합니다.
  • 환경 변수를 찾으면 필드 유형을 확인하고 둘 중 하나가 잘못된 경우 오류를 표시합니다.
    • DATABASE_URL 의 경우 필드 유형이 PostgresDsn 스타일 URL인지 확인합니다.
    • DEBUG 의 경우 필드 유형이 유효하고 엄격하지 않은 pydantic 부울인지 확인합니다.

DATABASE_URL 에 대한 구성 값에서 운영 체제 환경 변수의 명시적 설정에 유의하십시오. DATABASE_URL 이 이미 외부 환경 변수로 정의되어 있으므로 os.environ["DATABASE_URL"] = config.DATABASE_URL 을 설정하는 것이 중복되어 보일 수 있습니다. 그러나 이를 통해 pydantic은 이 변수를 구문 분석, 확인 및 검증할 수 있습니다. 환경 변수 DATABASE_URL 이 없거나 형식이 잘못된 경우 pydantic은 명확한 오류 메시지를 표시합니다. 이러한 오류 검사는 애플리케이션이 개발 환경에서 후속 환경으로 이동할 때 매우 중요합니다.

변수가 정의되지 않은 경우 기본값이 지정되거나 정의하라는 오류 메시지가 표시됩니다. 생성된 프롬프트는 원하는 변수 유형도 자세히 설명합니다. 이러한 검사의 부수적인 이점은 새로운 팀 구성원과 DevOps 엔지니어가 정의해야 하는 변수를 더 쉽게 찾을 수 있다는 것입니다. 이렇게 하면 정의된 모든 변수 없이 응용 프로그램이 실행될 때 발생하는 찾기 어려운 문제를 방지할 수 있습니다.

그게 다야 이제 애플리케이션에는 단일 버전의 settings.py 를 사용하여 유지 관리 가능한 설정 관리 구현이 있습니다. 이 접근 방식의 장점은 .env 파일에 올바른 환경 변수를 지정하거나 호스팅 환경을 통해 사용할 수 있는 기타 원하는 수단을 지정할 수 있다는 것입니다.

확장 가능한 경로

저는 모든 Django 프로젝트에서 pydantic 런타임 타이핑과 함께 Django 설정 관리를 사용해 왔습니다. 나는 그것이 더 작고 유지하기 쉬운 코드베이스로 이어진다는 것을 발견했습니다. 또한 새로운 환경을 추가하기 위해 잘 구조화되고 자체 문서화되고 확장 가능한 접근 방식을 제공합니다.

이 시리즈의 다음 기사는 pydantic 설정 관리를 사용하여 Django 애플리케이션을 처음부터 빌드하고 Heroku에 배포하는 단계별 자습서입니다.


Toptal 엔지니어링 블로그는 이 기사에 제공된 코드 샘플을 검토한 Stephen Davidson에게 감사의 말을 전합니다.

이 기사의 이전 버전에서는 특정 Python 릴리스를 강조했습니다. Python은 몇 년 동안 유형 힌트를 지원했기 때문에 이 버전 참조를 제거하여 소개 텍스트를 일반화했습니다.