Merampingkan Pengaturan Django Anda Dengan Petunjuk Jenis: Tutorial Pydantic
Diterbitkan: 2022-07-22Proyek Django dulu membuat saya frustrasi karena saya tidak memiliki cara yang kuat dan skalabel untuk menambahkan lingkungan baru. Dengan menyatukan petunjuk tipe pydantic dan Python, saya membangun fondasi kuat yang saya butuhkan.
Seperti yang dijelaskan dalam PEP 484, petunjuk jenis mendukung analisis statis, tetapi anotasi yang sama ini juga tersedia saat runtime. Paket pihak ketiga seperti pydantic menawarkan pemeriksaan jenis runtime yang menggunakan metadata tambahan ini. Pydantic menggunakan petunjuk jenis Python untuk membantu mengelola metadata pengaturan dan melakukan validasi data runtime.
Tutorial pydantic ini akan menunjukkan jangkauan luas, efek positif dari penggunaan manajemen pengaturan pydantic dengan Django.
Konfigurasi kami mematuhi praktik terbaik yang dijelaskan di situs web Aplikasi Dua Belas Faktor:
- Tentukan konfigurasi nonkonstan dan rahasia sebagai variabel lingkungan.
- Di lingkungan pengembangan, tentukan variabel lingkungan dalam file
.env
dan tambahkan.env
ke.gitignore
. - Gunakan mekanisme penyedia cloud untuk menentukan variabel lingkungan (rahasia) untuk lingkungan QA, staging, dan produksi.
- Gunakan satu file
settings.py
yang mengonfigurasi dirinya sendiri dari variabel lingkungan. - Gunakan pydantic untuk membaca, memeriksa, memvalidasi, dan mengetik variabel lingkungan ke variabel Python yang mendefinisikan konfigurasi Django.
Atau, beberapa pengembang membuat beberapa file pengaturan, seperti settings_dev.py
dan settings_prod.py
. Sayangnya, pendekatan ini tidak berskala dengan baik. Ini mengarah pada duplikasi kode, kebingungan, bug yang sulit ditemukan, dan upaya pemeliharaan yang lebih tinggi.
Menggunakan praktik terbaik yang disebutkan di atas, menambahkan sejumlah lingkungan mudah, terdefinisi dengan baik, dan tahan kesalahan. Meskipun kami dapat menjelajahi konfigurasi lingkungan yang lebih rumit, kami akan fokus pada dua untuk kejelasan: pengembangan dan produksi.
Seperti apa ini dalam praktiknya?
Manajemen Pengaturan Pydantic dan Variabel Lingkungan
Kami sekarang fokus pada contoh dalam pengembangan dan produksi. Kami menunjukkan bagaimana setiap lingkungan mengonfigurasi pengaturannya secara berbeda dan bagaimana pydantic mendukung masing-masing.
Aplikasi contoh kita memerlukan database yang didukung Django, jadi kita perlu menyimpan string koneksi database. Kami memindahkan informasi konfigurasi koneksi database ke dalam variabel lingkungan, DATABASE_URL
, menggunakan paket Python dj-database-url. Harap dicatat bahwa variabel ini bertipe str
dan diformat sebagai berikut:
postgres://{user}:{password}@{hostname}:{port}/{database-name} mysql://{user}:{password}@{hostname}:{port}/{database-name} oracle://{user}:{password}@{hostname}:{port}/{database-name} sqlite:///PATH
Di lingkungan pengembangan kami, kami dapat menggunakan instance PostgreSQL yang berisi Docker untuk kemudahan penggunaan, sementara di lingkungan produksi kami, kami akan menunjuk ke layanan basis data yang disediakan.
Variabel lain yang ingin kita definisikan adalah boolean, DEBUG
. Bendera DEBUG di Django tidak boleh dihidupkan dalam penyebaran produksi. Hal ini dimaksudkan untuk mendapatkan umpan balik tambahan selama pengembangan. Misalnya, dalam mode debug, Django akan menampilkan halaman kesalahan terinci saat pengecualian terjadi.
Nilai yang berbeda untuk pengembangan dan produksi dapat didefinisikan sebagai berikut:
Nama Variabel | Perkembangan | Produksi |
---|---|---|
DATABASE_URL | postgres://postgres:mypw@localhost:5432/mydb | postgres://foo1:foo2@foo3:5432/foo4 |
DEBUG | True | False |
Kami menggunakan modul manajemen pengaturan pydantic untuk mengelola kumpulan nilai variabel lingkungan yang berbeda ini tergantung pada lingkungan.
Langkah-Langkah Persiapan
Untuk mempraktikkannya, kami mulai mengonfigurasi lingkungan pengembangan kami dengan membuat file .env
tunggal kami dengan konten ini:
DATABASE_URL=postgres://postgres:mypw@localhost:5432/mydb DEBUG=True
Selanjutnya, kita tambahkan file .env
ke file .gitignore
proyek. File .gitignore
menghindari penyimpanan informasi yang berpotensi sensitif di kontrol sumber.
Sementara pendekatan ini bekerja dengan baik di lingkungan pengembangan kami, spesifikasi lingkungan produksi kami menggunakan mekanisme yang berbeda. Praktik terbaik kami menentukan bahwa variabel lingkungan produksi menggunakan rahasia lingkungan. Misalnya, di Heroku, rahasia ini disebut Config Vars dan dikonfigurasi melalui Dasbor Heroku. Mereka tersedia untuk aplikasi yang digunakan sebagai variabel lingkungan:
Setelah itu, kita perlu menyesuaikan konfigurasi aplikasi untuk membaca nilai-nilai ini dari kedua lingkungan secara otomatis.
Mengonfigurasi settings.py
Django
Mari kita mulai dengan proyek Django baru untuk menyediakan struktur penting untuk contoh kita. Kami membuat perancah proyek Django baru dengan perintah terminal berikut:
$ django-admin startproject mysite
Kami sekarang memiliki struktur proyek mysite
untuk proyek situs saya. Struktur file proyek adalah sebagai berikut:
mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py
File settings.py
berisi kode boilerplate yang memungkinkan kita mengelola konfigurasi aplikasi. Ini memiliki banyak pengaturan default yang telah ditentukan yang harus kita sesuaikan dengan lingkungan yang relevan.
Untuk mengelola pengaturan aplikasi ini menggunakan variabel lingkungan dan pydantic, tambahkan kode ini ke bagian atas file 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
Kode ini melakukan hal berikut:
- Mendefinisikan kelas
SettingsFromEnvironment
, mewarisi dari kelasBaseSettings
. - Mendefinisikan
DATABASE_URL
danDEBUG
, menyetel tipenya dan default opsional menggunakan petunjuk tipe Python. - Mendefinisikan kelas
Config
yang memberi tahu pydantic untuk mencari variabel dalam file.env
jika tidak ada dalam variabel lingkungan sistem. - Membuat instance kelas
Config
ke dalam objekconfig
; variabel yang diinginkan tersedia sebagaiconfig.DATABASE_URL
danconfig.DEBUG
. - Mendefinisikan variabel Django reguler
DATABASES
danDEBUG
dari anggotaconfig
ini.
Kode yang sama berjalan di semua lingkungan, dan pydantic menangani hal berikut:
- Itu mencari variabel lingkungan
DATABASE_URL
danDEBUG
.- Jika didefinisikan sebagai variabel lingkungan, seperti dalam produksi, ia akan menggunakannya.
- Jika tidak, itu menarik nilai-nilai itu dari file
.env
. - Jika tidak menemukan nilai, itu akan melakukan hal berikut:
- Untuk
DATABASE_URL
, itu menimbulkan kesalahan. - Untuk
DEBUG
, ini memberikan nilai defaultFalse
.
- Untuk
- Jika menemukan variabel lingkungan, ia akan memeriksa jenis bidang dan memberikan kesalahan jika salah satu dari mereka salah:
- Untuk
DATABASE_URL
, itu memverifikasi bahwa jenis bidangnya adalah URL gayaPostgresDsn
. - Untuk
DEBUG
, ia memverifikasi bahwa jenis bidangnya adalah boolean pydantic yang valid dan tidak ketat.
- Untuk
Harap perhatikan pengaturan eksplisit variabel lingkungan sistem operasi dari nilai konfigurasi untuk DATABASE_URL
. Tampaknya berlebihan untuk menetapkan os.environ["DATABASE_URL"] = config.DATABASE_URL
karena DATABASE_URL
sudah didefinisikan sebagai variabel lingkungan eksternal. Namun, ini memungkinkan pydantic untuk mengurai, memeriksa, dan memvalidasi variabel ini. Jika variabel lingkungan DATABASE_URL
hilang atau salah format, pydantic akan memberikan pesan kesalahan yang jelas. Pemeriksaan kesalahan ini sangat berharga saat aplikasi berpindah dari pengembangan ke lingkungan berikutnya.
Jika variabel tidak didefinisikan, baik default akan ditetapkan atau kesalahan akan meminta untuk didefinisikan. Setiap prompt yang dihasilkan juga merinci jenis variabel yang diinginkan. Manfaat sampingan dari pemeriksaan ini adalah bahwa anggota tim baru dan insinyur DevOps lebih mudah menemukan variabel mana yang perlu didefinisikan. Ini menghindari masalah yang sulit ditemukan yang terjadi saat aplikasi berjalan tanpa semua variabel yang ditentukan.
Itu dia. Aplikasi sekarang memiliki implementasi manajemen pengaturan yang dapat dipelihara menggunakan satu versi settings.py
. Keindahan dari pendekatan ini adalah memungkinkan kita untuk menentukan variabel lingkungan yang benar dalam file .env
atau cara lain yang diinginkan yang tersedia melalui lingkungan hosting kita.
Jalur yang Dapat Diukur
Saya telah menggunakan manajemen pengaturan Django dengan pengetikan runtime pydantic di semua proyek Django saya. Saya telah menemukan itu mengarah ke basis kode yang lebih kecil dan lebih dapat dipelihara. Ini juga menyediakan pendekatan yang terstruktur dengan baik, mendokumentasikan diri sendiri, dan skalabel untuk menambahkan lingkungan baru.
Artikel berikutnya dalam seri ini adalah tutorial langkah demi langkah dalam membangun aplikasi Django dari awal, dengan manajemen pengaturan pydantic, dan menyebarkannya ke Heroku.
Blog Toptal Engineering mengucapkan terima kasih kepada Stephen Davidson karena telah meninjau contoh kode yang disajikan dalam artikel ini.
Versi sebelumnya dari artikel ini menekankan rilis Python tertentu. Karena Python telah mendukung petunjuk jenis selama beberapa tahun, kami telah menggeneralisasi teks pengantar dengan menghapus referensi versi ini.