Apa Itu Pydantic?
Anda pada dasarnya sedang bermain roulette data ketika membangun aplikasi yang berinteraksi dengan dunia luar. Pengguna mungkin mengirim nomor telepon sebagai string alih-alih integer, sebuah API mungkin mengembalikan nilai null saat Anda mengharapkan angka, atau berkas konfigurasi mungkin berisi salah ketik yang membuat aplikasi Anda rusak pada pukul 3 pagi.
Pendekatan Python tradisional terhadap masalah ini cepat menjadi sulit diatur. Anda akhirnya menulis kode validasi seperti ini:
def create_user(data):
# Manual validation nightmare
if not isinstance(data.get('age'), int):
raise ValueError("Age must be an integer")
if data['age'] < 0 or data['age'] > 150:
raise ValueError("Age must be between 0 and 150")
if not isinstance(data.get('email'), str) or '@' not in data['email']:
raise ValueError("Invalid email format")
if not isinstance(data.get('is_active'), bool):
raise ValueError("is_active must be a boolean")
# Finally create the user...
return User(data['age'], data['email'], data['is_active'])
Kalikan ini dengan setiap struktur data dalam aplikasi Anda, dan Anda akan menghabiskan lebih banyak waktu menulis kode validasi daripada logika bisnis.
Pydantic menyelesaikan ini dengan menggabungkan tiga konsep kuat: type hint, validasi runtime, dan serialisasi otomatis. Alih-alih pengecekan manual, Anda mendefinisikan struktur data sekali saja menggunakan sintaks anotasi tipe Python, dan Pydantic menangani semua validasi secara otomatis:
from pydantic import BaseModel, EmailStr
from typing import Optional
class User(BaseModel):
age: int
email: EmailStr
is_active: bool = True
nickname: Optional[str] = None
# Pydantic automatically validates and converts data
user_data = {
"age": "25", # String gets converted to int
"email": "[email protected]",
"is_active": "true" # String gets converted to bool
}
user = User(**user_data)
print(user.age) # 25 (as integer)
print(user.model_dump()) # Clean dictionary output
Fitur-fitur Pydantic
Pendekatan Pydantic memberi Anda beberapa manfaat. Performa adalah keuntungan pertama yang akan Anda rasakan — logika inti validasi Pydantic ditulis dalam Rust, membuatnya lebih cepat daripada validasi Python yang ditulis manual dalam banyak kasus. Aplikasi Anda dapat memproses ribuan permintaan tanpa validasi menjadi hambatan.
Pydantic juga memungkinkan integrasi dengan framework modern. FastAPI, salah satu framework web Python yang tumbuh paling cepat, menggunakan model Pydantic untuk secara otomatis menghasilkan dokumentasi API, memvalidasi isi permintaan, dan menserialisasi respons. Saat Anda mendefinisikan model Pydantic, Anda mendapatkan pembuatan skema OpenAPI secara gratis:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
name: str
email: EmailStr
age: int
@app.post("/users/")
async def create_user(user: UserCreate):
# FastAPI automatically validates the request body
# and generates API docs from your Pydantic model
return {"message": f"Created user {user.name}"}
Pembuatan skema JSON terjadi secara otomatis pada setiap model Pydantic. Ini berarti struktur data Anda menjadi terdokumentasi sendiri, dan Anda dapat menghasilkan library klien, aturan validasi untuk aplikasi frontend, atau skema basis data dari sumber kebenaran yang sama.
Pydantic vs. Dataclasses vs. Marshmallow
Lalu, kapan Anda harus memilih Pydantic dibanding alternatifnya? Jika Anda membandingkan Pydantic vs dataclasses, keputusannya bermuara pada kebutuhan validasi. @dataclass Python ideal untuk kontainer data sederhana saat Anda memercayai inputnya, tetapi Pydantic unggul ketika Anda memerlukan validasi, serialisasi, dan integrasi dengan framework web:
from dataclasses import dataclass
from pydantic import BaseModel
# Dataclass: fast, simple, no validation
@dataclass
class UserDataclass:
name: str
age: int
# Pydantic: validation, serialization, framework integration
class UserPydantic(BaseModel):
name: str
age: int
Saat membandingkan Pydantic dengan Marshmallow, pendekatan type hint Pydantic terasa lebih alami bagi pengembang Python, sementara Marshmallow menggunakan kelas skema. Pydantic juga menawarkan performa lebih baik dan integrasi yang lebih mudah dengan framework async modern.
Pydantic bekerja paling baik saat Anda membangun API, memproses data eksternal, mengelola konfigurasi, atau skenario apa pun di mana kegagalan validasi data sebaiknya tertangkap lebih awal alih-alih menyebabkan bug misterius nanti. Ia mengubah error runtime menjadi pesan validasi yang jelas dan dapat ditindaklanjuti yang membantu pengembang dan pengguna memahami apa yang salah.
Memulai dengan Pydantic
Mari kita telusuri cara menggunakan Pydantic dalam proyek Anda, dari instalasi hingga membuat model data pertama.
Instalasi dan penyiapan
Menyiapkan Pydantic itu mudah, tetapi beberapa kesalahan umum dapat menjebak pemula. Saya akan memandu Anda melalui proses instalasi yang tepat dan membantu menghindari kesalahan yang menyebabkan debugging tidak perlu.
Pertama, buat lingkungan virtual untuk menjaga dependensi proyek Anda terisolasi. Ini mencegah konflik versi yang dapat menyebabkan error impor misterius di kemudian hari:
# Create and activate virtual environment (works in zsh and bash)
python -m venv pydantic_env
source pydantic_env/bin/activate # On macOS/Linux
# pydantic_env\Scripts\activate # On Windows
Sekarang, instal Pydantic dengan perintah berikut:
pip install pydantic
Untuk fungsionalitas validasi email, yang kemungkinan besar Anda perlukan dalam aplikasi nyata (dan di tutorial ini), instal email extras:
pip install "pydantic[email]"
Tanda kutip di sekitar pydantic[email] penting di hampir semua terminal. Tanpanya, Anda mungkin melihat error "no matches found".
Catatan: Jika Anda menemui ModuleNotFoundError: No module named 'pydantic', periksa hal-hal berikut:
- Lingkungan Python salah: Pastikan lingkungan virtual Anda aktif
- Beberapa versi Python: Pastikan Anda menggunakan versi Python yang sama dengan yang menginstal Pydantic
- Konfigurasi IDE: Editor kode Anda mungkin menggunakan interpreter Python yang berbeda
Peringatan penamaan kritis: Jangan pernah menamai berkas Python Anda pydantic.py. Ini menciptakan impor sirkular yang akan merusak kode Anda dengan pesan error membingungkan. Python akan mencoba mengimpor berkas Anda alih-alih pustaka Pydantic yang sebenarnya.
Model Pydantic pertama Anda
Mari membuat model pengguna sederhana untuk melihat Pydantic dalam aksi. Alih-alih memulai dengan contoh abstrak, kita akan menyelesaikan masalah nyata: memvalidasi data pendaftaran pengguna dari formulir web.
from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime
class User(BaseModel):
name: str
email: EmailStr
age: int
is_active: bool = True
created_at: datetime = None
# Test with clean data
clean_data = {
"name": "Alice Johnson",
"email": "[email protected]",
"age": 28
}
user = User(**clean_data)
print(f"User created: {user.name}, Age: {user.age}")
print(f"Model output: {user.model_dump()}")
Keluaran:
User created: Alice Johnson, Age: 28
Model output: {'name': 'Alice Johnson', 'email': '[email protected]', 'age': 28, 'is_active': True, 'created_at': None}
Mari uraikan apa yang terjadi dalam definisi model ini:
- Membuat model Pydantic: Kelas
UserAnda mewarisi dariBaseModel, yang memberinya seluruh kemampuan validasi dan serialisasi Pydantic. Pewarisan ini mengubah kelas Python biasa menjadi alat validasi data. - Definisi field: Setiap baris di kelas mendefinisikan field dengan tipe yang diharapkan. Sintaks
name: strmemberi tahu Pydantic bahwanameharus berupa string,age: intberarti age harus berupa integer, dan seterusnya. - Penjelasan EmailStr:
EmailStradalah tipe khusus Pydantic yang secara otomatis memvalidasi alamat email. Ini berasal dari paketpydantic[email]yang Anda instal sebelumnya dan menggunakan regular expression untuk memastikan format email valid. Jika seseorang memasukkan "not-an-email", Pydantic akan melempar error validasi. - Nilai default: Field seperti
is_active: bool = Truememiliki nilai default. Jika Anda tidak menyediakan field ini saat membuat pengguna, Pydantic akan menggunakan default.= Noneuntukcreated_atmembuat field ini opsional. - Instansiasi model: Saat Anda memanggil
User(**clean_data),**membongkar kamus Anda dan meneruskan setiap pasangan key-value sebagai argumen kata kunci ke konstruktor model.
Sekarang mari lihat konversi tipe otomatis Pydantic dalam aksi:
# Messy data that still works
messy_data = {
"name": "Bob Smith",
"email": "[email protected]",
"age": "35", # String instead of int
"is_active": "true" # String instead of bool
}
user = User(**messy_data)
print(f"Age type: {type(user.age)}") # <class 'int'>
print(f"Is active type: {type(user.is_active)}") # <class 'bool'>
Sekarang mari lihat konversi tipe otomatis Pydantic dalam aksi:
# Messy data that still works
messy_data = {
"name": "Bob Smith",
"email": "[email protected]",
"age": "35", # String instead of int
"is_active": "true" # String instead of bool
}
user = User(**messy_data)
print(f"Age type: {type(user.age)}") # <class 'int'>
print(f"Is active type: {type(user.is_active)}") # <class 'bool'>
Keluaran:
Age type: <class 'int'>
Is active type: <class 'bool'>
Seperti yang Anda lihat, field age dan is_inactive secara otomatis dikonversi ke format yang benar melalui validasi.
Saat validasi gagal, Pydantic memberikan pesan kesalahan yang jelas:
from pydantic import ValidationError
try:
invalid_user = User(
name="", # Empty string
email="not-an-email", # Invalid email
age=-5 # Negative age
)
except ValidationError as e:
print(e)
Keluaran:
# Shows exactly which fields failed and why
1 validation error for User
email
value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='not-an-email', input_type=str]
BaseModel vs. data classes
Memahami kapan harus menggunakan BaseModel Pydantic versus @dataclass Python membantu Anda memilih alat yang tepat untuk setiap situasi.
Dataclass Python sangat cocok untuk kontainer data sederhana saat Anda mengendalikan input:
from dataclasses import dataclass
@dataclass
class ProductDataclass:
name: str
price: float
in_stock: bool
# Fast, simple, but no validation
product = ProductDataclass("Laptop", 999.99, True)
# This also works, even though types are wrong:
broken_product = ProductDataclass(123, "expensive", "maybe")
Model Pydantic menambahkan validasi, serialisasi, dan integrasi framework:
from pydantic import BaseModel, Field
class ProductPydantic(BaseModel):
name: str = Field(min_length=1)
price: float = Field(gt=0) # Must be greater than 0
in_stock: bool
# Automatic validation prevents bad data
try:
product = ProductPydantic(name="", price=-10, in_stock="maybe")
except ValidationError as e:
print("Validation caught the errors!")
# Valid data works perfectly
good_product = ProductPydantic(
name="Laptop",
price="999.99", # String converted to float
in_stock=True
)
Kapan memilih masing-masing pendekatan:
- Gunakan dataclasses untuk struktur data internal, objek konfigurasi, atau saat performa sangat kritis dan Anda memercayai sumber data
- Gunakan Pydantic untuk endpoint API, input pengguna, parsing data eksternal, atau saat Anda memerlukan serialisasi JSON
Pydantic menambah sedikit overhead dibanding dataclasses, tetapi biayanya biasanya sepele dibanding bug yang dicegah dan waktu pengembangan yang dihemat. Untuk aplikasi web, integrasi otomatis dengan framework seperti FastAPI menjadikan Pydantic pilihan yang jelas.
Fitur validasi dan serialisasi menjadi semakin berharga seiring pertumbuhan aplikasi Anda. Memulai dengan model Pydantic memberi Anda fondasi yang kuat dan skalabel sesuai kebutuhan.
Membangun Model Data dengan Pydantic
Sekarang Anda memahami dasarnya, mari hadapi tantangan yang akan Anda temui saat membangun aplikasi siap produksi.
Validasi field dan kendala
Pertimbangkan API katalog produk di mana data harga berasal dari banyak vendor dengan standar pemformatan berbeda. Beberapa mengirim harga sebagai string, yang lain sebagai float, dan sesekali, seseorang mengirim harga negatif yang membuat sistem penagihan Anda rusak.
Fungsi Field() Pydantic mengubah type hint dasar menjadi aturan validasi canggih yang melindungi aplikasi Anda:
from pydantic import BaseModel, Field
from decimal import Decimal
from typing import Optional
class Product(BaseModel):
name: str = Field(min_length=1, max_length=100)
price: Decimal = Field(gt=0, le=10000) # Greater than 0, less than or equal to 10,000
description: Optional[str] = Field(None, max_length=500)
category: str = Field(..., pattern=r'^[A-Za-z\s]+$') # Only letters and spaces
stock_quantity: int = Field(ge=0) # Greater than or equal to 0
is_available: bool = True
# This works - all constraints satisfied
valid_product = Product(
name="Wireless Headphones",
price="199.99", # String converted to Decimal
description="High-quality wireless headphones",
category="Electronics",
stock_quantity=50
)
# This fails with clear error messages
try:
invalid_product = Product(
name="", # Too short
price=-50, # Negative price
category="Electronics123", # Contains numbers
stock_quantity=-5 # Negative stock
)
except ValidationError as e:
print(f"Validation errors: {len(e.errors())} issues found")
Setiap parameter Field() memiliki tujuan spesifik: min_length dan max_length mencegah pelanggaran skema basis data, gt dan le menciptakan batasan logika bisnis, dan pattern memvalidasi data terformat menggunakan regular expression. Sintaks Field(...) dengan elipsis menandai field yang wajib, sementara Field(None, ...) membuat field opsional dengan aturan validasi.
Koersi tipe vs validasi ketat
Secara default, Pydantic mengonversi tipe yang kompatibel alih-alih langsung menolaknya. Fleksibilitas ini bekerja baik untuk input pengguna, tetapi beberapa skenario membutuhkan kecocokan tipe yang presisi:
from pydantic import BaseModel, Field, ValidationError
# Default: lenient type coercion
class FlexibleOrder(BaseModel):
order_id: int
total_amount: float
is_paid: bool
# These all work due to automatic conversion
flexible_order = FlexibleOrder(
order_id="12345", # String to int
total_amount="99.99", # String to float
is_paid="true" # String to bool
)
# Strict validation when precision matters
class StrictOrder(BaseModel):
model_config = {"str_strip_whitespace": True, "validate_assignment": True}
order_id: int = Field(strict=True)
total_amount: float = Field(strict=True)
is_paid: bool = Field(strict=True)
Kamus model_config mengontrol perilaku validasi di seluruh model Anda. Opsi str_strip_whitespace membersihkan input string secara otomatis, sementara validate_assignment memastikan perubahan field setelah pembuatan model tetap memicu validasi. Field individual dapat menimpa pengaturan ini dengan Field(strict=True) untuk situasi yang memerlukan kecocokan tipe tepat, seperti perhitungan finansial atau data ilmiah.
Model bertingkat dan data kompleks
Aplikasi nyata menangani struktur data yang kompleks dan saling terkait. Pesanan e-niaga berisi informasi pelanggan, alamat pengiriman, dan beberapa item produk , masing-masing memerlukan validasi tersendiri:
from typing import List
from datetime import datetime
class Address(BaseModel):
street: str = Field(min_length=5)
city: str = Field(min_length=2)
postal_code: str = Field(pattern=r'^\d{5}(-\d{4})?$')
country: str = "USA"
class Customer(BaseModel):
name: str = Field(min_length=1)
email: EmailStr
shipping_address: Address
billing_address: Optional[Address] = None
class OrderItem(BaseModel):
product_id: int = Field(gt=0)
quantity: int = Field(gt=0, le=100)
unit_price: Decimal = Field(gt=0)
class Order(BaseModel):
order_id: str = Field(pattern=r'^ORD-\d{6}$')
customer: Customer
items: List[OrderItem] = Field(min_items=1)
order_date: datetime = Field(default_factory=datetime.now)
# Complex nested data validation
order_data = {
"order_id": "ORD-123456",
"customer": {
"name": "John Doe",
"email": "[email protected]",
"shipping_address": {
"street": "123 Main Street",
"city": "Anytown",
"postal_code": "12345"
}
},
"items": [
{"product_id": 1, "quantity": 2, "unit_price": "29.99"},
{"product_id": 2, "quantity": 1, "unit_price": "149.99"}
]
}
order = Order(**order_data)
print(f"Order validated with {len(order.items)} items")
Pydantic memvalidasi struktur bertingkat secara rekursif — field Customer menjadi objek Customer penuh, yang memvalidasi field Address miliknya. Sintaks List[OrderItem] memvalidasi setiap elemen daftar sebagai OrderItem, sementara Field(min_items=1) mencegah pesanan kosong mencapai sistem persediaan Anda. Menggunakan default_factory=datetime.now membuat cap waktu unik untuk setiap instance pesanan.
Field opsional dan penanganan None
Operasi yang berbeda membutuhkan persyaratan data yang berbeda. Pembuatan pengguna menuntut informasi lengkap, sementara pembaruan sebaiknya menerima perubahan parsial:
from typing import Optional
class UserCreate(BaseModel):
name: str = Field(min_length=1)
email: EmailStr
age: int = Field(ge=13, le=120)
phone: Optional[str] = Field(None, pattern=r'^\+?1?\d{9,15}$')
class UserUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1)
email: Optional[EmailStr] = None
age: Optional[int] = Field(None, ge=13, le=120)
phone: Optional[str] = Field(None, pattern=r'^\+?1?\d{9,15}$')
# PATCH request with partial data
update_data = {"name": "Jane Smith", "age": 30}
user_update = UserUpdate(**update_data)
# Serialize only provided fields
patch_data = user_update.model_dump(exclude_none=True)
print(f"Fields to update: {list(patch_data.keys())}")
Serialisasi mengonversi objek Pydantic kembali menjadi kamus atau string JSON untuk penyimpanan atau transmisi. Metode model_dump() menangani konversi ini, dengan exclude_none=True menghapus field yang tidak disediakan. Pola ini sangat cocok untuk permintaan PATCH di mana klien hanya mengirim field yang ingin diubah, mencegah penimpaan data yang tidak disengaja di basis data Anda.
Fondasi ini mempersiapkan Anda untuk tantangan berikutnya: menerapkan logika validasi kustom yang menangkap aturan bisnis unik aplikasi Anda.
Validasi Kustom dan Integrasi Dunia Nyata
Membangun aplikasi produksi berarti menangani data yang tidak sesuai dengan pola pemeriksaan tipe standar.
Pertimbangkan formulir pendaftaran pengguna di mana persyaratan kata sandi berbeda berdasarkan paket langganan, atau API yang menerima data alamat dari berbagai negara dengan format kode pos berbeda. Skenario ini memerlukan logika validasi kustom yang menangkap aturan bisnis spesifik Anda sekaligus terintegrasi mulus dengan framework web dan sistem konfigurasi.
Bagian ini menunjukkan cara menerapkan pola validasi kustom yang praktis, mengintegrasikan model Pydantic dengan FastAPI untuk dokumentasi API otomatis, dan mengelola pengaturan aplikasi melalui variabel lingkungan menggunakan pendekatan berkas .env yang diandalkan sebagian besar aplikasi produksi.
Validator field dan validasi model
Saat logika bisnis menentukan validitas data, dekorator @field_validator Pydantic mengubah fungsi validasi Anda menjadi bagian dari model itu sendiri. Pertimbangkan sistem pendaftaran pengguna di mana tiap tingkatan langganan memiliki persyaratan kata sandi berbeda:
from pydantic import BaseModel, field_validator, Field
import re
class UserRegistration(BaseModel):
username: str = Field(min_length=3)
email: EmailStr
password: str
subscription_tier: str = Field(pattern=r'^(free|pro|enterprise)$')
@field_validator('password')
@classmethod
def validate_password_complexity(cls, password, info):
tier = info.data.get('subscription_tier', 'free')
if len(password) < 8:
raise ValueError('Password must be at least 8 characters')
if tier == 'enterprise' and not re.search(r'[A-Z]', password):
raise ValueError('Enterprise accounts require uppercase letters')
return password
Dekorator @field_validator memberi Anda akses ke nilai field lain melalui parameter info.data, memungkinkan aturan validasi yang bergantung pada beberapa field. Validator dijalankan setelah pemeriksaan tipe dasar lolos, sehingga Anda dapat berasumsi dengan aman bahwa subscription_tier adalah salah satu nilai yang diizinkan.
Untuk validasi yang mencakup banyak field, dekorator @model_validator dijalankan setelah semua field individual divalidasi:
from datetime import datetime
from pydantic import model_validator
class EventRegistration(BaseModel):
start_date: datetime
end_date: datetime
max_attendees: int = Field(gt=0)
current_attendees: int = Field(ge=0)
@model_validator(mode='after')
def validate_event_constraints(self):
if self.end_date <= self.start_date:
raise ValueError('Event end date must be after start date')
if self.current_attendees > self.max_attendees:
raise ValueError('Current attendees cannot exceed maximum')
return self
Parameter mode='after' memastikan validator menerima instance model yang sepenuhnya dibangun, sehingga sempurna untuk logika bisnis yang memerlukan akses ke semua field yang sudah divalidasi. Validator harus mengembalikan self untuk menandakan validasi berhasil.
Integrasi FastAPI
Integrasi FastAPI dengan Pydantic menciptakan validasi permintaan dan dokumentasi API otomatis. Pola kuncinya melibatkan pembuatan model terpisah untuk operasi berbeda, memberi Anda kendali atas data apa yang mengalir di setiap arah:
from fastapi import FastAPI
from typing import Optional
from datetime import datetime
app = FastAPI()
class UserCreate(BaseModel):
username: str = Field(min_length=3)
email: EmailStr
password: str = Field(min_length=8)
class UserResponse(BaseModel):
id: int
username: str
email: EmailStr
created_at: datetime
@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
# FastAPI automatically validates the request body
new_user = {
"id": 1,
"username": user.username,
"email": user.email,
"created_at": datetime.now()
}
return UserResponse(**new_user)
Pemisahan antara model input dan output memberikan beberapa manfaat. Model input dapat menyertakan aturan validasi dan field wajib, sementara model output mengendalikan tepatnya data apa yang dikirim ke klien. FastAPI secara otomatis menghasilkan dokumentasi OpenAPI dari model Pydantic Anda, menciptakan dokumentasi API interaktif yang dapat digunakan pengembang untuk menguji endpoint.
Untuk operasi pembaruan, Anda dapat membuat model di mana semua field bersifat opsional:
class UserUpdate(BaseModel):
username: Optional[str] = Field(None, min_length=3)
email: Optional[EmailStr] = None
@app.patch("/users/{user_id}")
async def update_user(user_id: int, user_update: UserUpdate):
# Only update provided fields
update_data = user_update.model_dump(exclude_unset=True)
# Your database update logic here
return {"message": f"Updated user {user_id}"}
Parameter exclude_unset=True dalam operasi PATCH memastikan Anda hanya memperbarui field yang secara eksplisit disediakan, mencegah penimpaan tidak disengaja. Pola ini sangat cocok untuk REST API di mana klien mengirim pembaruan parsial.
Manajemen konfigurasi dengan variabel lingkungan
Aplikasi produksi membutuhkan manajemen konfigurasi yang aman dan ramah-deploy. BaseSettings Pydantic yang dikombinasikan dengan berkas .env menyediakan konfigurasi bertipe aman yang bekerja di lingkungan pengembangan, staging, dan produksi.
Pertama, buat berkas .env di root proyek Anda:
# .env file
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
SECRET_KEY=your-secret-key-here
DEBUG=false
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
Lalu definisikan model pengaturan Anda:
from pydantic import BaseSettings, Field
from typing import List
class AppSettings(BaseSettings):
database_url: str = Field(description="Database connection URL")
secret_key: str = Field(description="Secret key for JWT tokens")
debug: bool = Field(default=False)
allowed_hosts: List[str] = Field(default=["localhost"])
class Config:
env_file = ".env"
case_sensitive = False
# Load settings automatically from environment and .env file
settings = AppSettings()
Kelas BaseSettings secara otomatis membaca dari variabel lingkungan, berkas .env, dan argumen baris perintah. Variabel lingkungan memiliki prioritas lebih tinggi daripada nilai berkas .env, sehingga mudah menimpa pengaturan di lingkungan deployment berbeda. Pengaturan case_sensitive = False memungkinkan penamaan variabel lingkungan yang fleksibel.
Untuk aplikasi kompleks, Anda dapat mengelompokkan pengaturan ke dalam kelompok logis:
class DatabaseSettings(BaseSettings):
url: str = Field(env="DATABASE_URL")
max_connections: int = Field(default=5, env="DB_MAX_CONNECTIONS")
class AppSettings(BaseSettings):
secret_key: str
debug: bool = False
database: DatabaseSettings = DatabaseSettings()
class Config:
env_file = ".env"
settings = AppSettings()
# Access nested configuration
db_url = settings.database.url
Pendekatan bertingkat ini menjaga pengaturan terkait tetap bersama sambil mempertahankan pemisahan yang jelas antara berbagai komponen aplikasi Anda. Setiap grup pengaturan dapat memiliki prefiks variabel lingkungan dan aturan validasinya sendiri.
Pendekatan berkas .env berfungsi dengan platform deployment seperti Heroku, AWS, dan Docker, di mana variabel lingkungan adalah cara standar untuk mengonfigurasi aplikasi. Aplikasi Anda mendapatkan keamanan tipe dan validasi sambil mengikuti pola konfigurasi cloud-native yang diharapkan tim operasional.
Pola-pola ini membentuk fondasi untuk membangun aplikasi yang mudah dirawat yang menangani kompleksitas dunia nyata. Sistem validasi Pydantic beradaptasi dengan kebutuhan spesifik Anda sambil memberikan pesan kesalahan yang jelas dan dokumentasi otomatis yang membantu seluruh tim memahami struktur data yang diharapkan aplikasi Anda.
Kesimpulan
Anda kini telah melihat bagaimana Pydantic dapat menyelamatkan Anda dari pekerjaan membosankan menulis kode validasi secara manual. Alih-alih memenuhi fungsi Anda dengan pemeriksaan isinstance() dan penanganan error kustom, Anda dapat mendefinisikan struktur data sekali saja dan membiarkan Pydantic menangani sisanya.
Pastikan untuk membaca bagian FAQ di bawah untuk pertanyaan Pydantic yang lebih spesifik. Untuk dokumentasi komprehensif dan pola lanjutan, berikut beberapa sumber yang dapat Anda gunakan:
- Dokumentasi resmi:
- Dokumentasi Pydantic — Referensi lengkap dengan contoh dan praktik terbaik
- Panduan Migrasi Pydantic — Bacaan penting untuk peningkatan antar versi
- Dokumentasi FastAPI — Pelajari bagaimana Pydantic mendukung dokumentasi API otomatis
- Sumber belajar DataCamp terkait:
- Model Validation in Python — Telaah mendalam teknik validasi dengan scikit-learn
- Introduction to FastAPI — Bangun API produksi dengan integrasi Pydantic
- Introduction to APIs in Python — Bekerja dengan API eksternal dan validasi data JSON
- Intermediate Python — Kuasai dasar Python yang melengkapi penggunaan Pydantic
- Object-Oriented Programming in Python — Bangun fondasi untuk memahami model Pydantic
FAQs
Apakah validasi Pydantic memperlambat aplikasi saya?
Pydantic V2 dibangun dengan Rust di balik layar, sehingga sangat cepat. Untuk sebagian besar aplikasi, overhead validasi minimal dibanding bug yang dicegah. Anda dapat menggunakan model_construct() untuk melewati validasi bagi sumber data tepercaya saat performa sangat kritis.
Kapan saya harus menggunakan Pydantic alih-alih dataclasses Python?
Gunakan Pydantic saat Anda memerlukan validasi, bekerja dengan sumber data eksternal, atau membangun API. Gunakan dataclasses untuk struktur data internal sederhana saat Anda memercayai input. Pydantic unggul ketika data berasal dari pengguna, API, atau berkas konfigurasi.
Bagaimana cara menangani error validasi Pydantic di aplikasi produksi?
Tangkap pengecualian ValidationError dan ekstrak daftar .errors() untuk mendapatkan informasi kesalahan terstruktur. Setiap kesalahan berisi field loc, msg, dan type yang membantu Anda memberikan pesan kesalahan ramah pengguna atau mencatat informasi debugging yang mendetail.
Bisakah saya menambahkan Pydantic ke kode yang ada tanpa merusak semuanya?
Bisa! Mulailah dengan membungkus titik masuk data eksternal (permintaan API, parsing berkas) dengan model Pydantic. Anda dapat secara bertahap mengonversi struktur data internal. Pydantic bekerja berdampingan dengan kode yang ada dan tidak mengharuskan Anda mengubah seluruh basis kode sekaligus.
Apa kesalahan paling umum saat mulai menggunakan Pydantic?
Tidak memahami koersi tipe. Secara default, Pydantic mengonversi tipe yang kompatibel (seperti string "123" menjadi integer 123). Jika Anda memerlukan pemeriksaan tipe ketat, gunakan Field(strict=True) atau atur mode ketat di konfigurasi model Anda untuk mencegah konversi otomatis.

Saya adalah kreator konten data science dengan pengalaman lebih dari 2 tahun dan salah satu dengan jumlah pengikut terbesar di Medium. Saya suka menulis artikel mendalam tentang AI dan ML dengan sedikit gaya sarkastik—karena harus ada sesuatu untuk membuatnya tidak terlalu membosankan. Saya telah menghasilkan lebih dari 130 artikel dan satu kursus di DataCamp, dengan satu lagi sedang dalam proses. Konten saya telah dilihat oleh lebih dari 5 juta pasang mata, dan 20 ribu di antaranya menjadi pengikut di Medium dan LinkedIn.

Pydantic adalah pustaka validasi data paling populer di Python yang dapat mengubah type hint menjadi aturan validasi saat runtime.
Alih-alih menulis banyak if
isinstance()dan fungsi validasi khusus, Anda mendefinisikan struktur data sekali saja menggunakan sintaks Python yang familier.Pydantic menangani sisanya: memvalidasi data masuk, mengonversi tipe saat sesuai, dan memberikan pesan kesalahan yang jelas ketika validasi gagal.
Pertimbangkan fungsi Python sederhana berikut dengan type hint dan dokumentasi yang memadai:
Melihat tandatangannya, Anda tahu persis jenis data apa yang diterima dan dihasilkan di ujung lain. Namun, bisakah hal yang sama dikatakan tentang pengguna akhir? Bagaimanapun, type hint ini hanya untuk tujuan dokumentasi — jika seseorang mengirimkan tipe data yang salah, interpreter Python tidak akan mempermasalahkannya:
Ini adalah contoh klasik pengetikan dinamis Python. Ini memberi pengembang kecepatan dan kebebasan, tetapi dengan konsekuensi munculnya masalah validasi tipe yang sering baru terlihat di produksi.
Dalam tutorial ini, saya akan menjelaskan cara menggunakan Pydantic untuk aplikasi dunia nyata. Kita akan mulai dengan model data pertama Anda dan melanjutkan ke pola lanjutan yang digunakan dalam sistem produksi. Anda akan mempelajari cara memvalidasi struktur data bertingkat, menulis validator kustom untuk aturan bisnis yang kompleks, dan mengintegrasikan Pydantic dengan framework populer seperti FastAPI dan SQLAlchemy.
Di bawah ini, Anda juga dapat menonton video tutorial kami tentang dasar-dasar Pydantic.