कोर्स
Pydantic Python का सबसे लोकप्रिय डेटा वैलिडेशन लाइब्रेरी है, जो टाइप हिंट्स को रनटाइम वैलिडेशन नियमों में बदल सकती है।
दर्जनों if isinstance() जाँचें और कस्टम वैलिडेशन फंक्शन्स लिखने के बजाय, आप परिचित Python सिंटैक्स का उपयोग करके एक बार अपना डेटा स्ट्रक्चर परिभाषित करते हैं।
बाकी काम Pydantic संभालता है: आने वाले डेटा को सत्यापित करना, उपयुक्त होने पर टाइप्स को कन्वर्ट करना, और वैलिडेशन असफल होने पर स्पष्ट त्रुटि संदेश देना।
इस सरल Python फ़ंक्शन पर विचार करें जिसमें टाइप हिंट्स और उपयुक्त प्रलेखन है:
def calculate_user_discount(age: int, is_premium_member: bool, purchase_amount: float) -> float:
"""Calculate discount percentage based on user profile and purchase amount."""
if age >= 65:
base_discount = 0.15
elif is_premium_member:
base_discount = 0.10
else:
base_discount = 0.05
return purchase_amount * base_discount
इसके सिग्नेचर को देखते ही आपको ठीक-ठीक पता चल जाता है कि यह किस तरह का डेटा स्वीकार करता है और अंत में क्या आउटपुट देता है। लेकिन क्या अंतिम उपयोगकर्ता के बारे में आप यही कह सकते हैं? आखिरकार, ये टाइप हिंट्स केवल दस्तावेज़ीकरण के लिए हैं—यदि कोई गलत डेटा टाइप पास कर दे, तो Python का इंटरप्रेटर परेशान नहीं होता:
# यह बिना त्रुटि के चलता है, भले ही टाइप्स पूरी तरह गलत हों!
discount = calculate_user_discount(True, 1, 5)
print(discount) # Output: 0.5 (True 1 बन जाता है, 1 truthy है, इसलिए 5 * 0.10)
यह Python की डायनेमिक टाइपिंग का एक क्लासिक उदाहरण है। यह डेवलपर्स को तेज़ विकास और स्वतंत्रता देता है, लेकिन इसकी कीमत टाइप वैलिडेशन समस्याओं के रूप में चुकानी पड़ती है, जो अक्सर प्रोडक्शन में सामने आती हैं।
इस ट्यूटोरियल में, मैं बताऊँगा कि वास्तविक-world एप्लिकेशनों के लिए Pydantic का उपयोग कैसे करें। हम आपके पहले डेटा मॉडल से शुरू करेंगे और प्रोडक्शन सिस्टम्स में उपयोग होने वाले उन्नत पैटर्न तक बढ़ेंगे। आप जानेंगे कि नेस्टेड डेटा स्ट्रक्चर्स को कैसे मान्य करें, जटिल बिजनेस नियमों के लिए कस्टम वेलिडेटर्स कैसे लिखें, और Pydantic को FastAPI और SQLAlchemy जैसे लोकप्रिय फ्रेमवर्क्स के साथ कैसे एकीकृत करें।
नीचे, आप Pydantic की बुनियादी बातों पर हमारा वीडियो ट्यूटोरियल भी देख सकते हैं।
Pydantic क्या है?
जब आप ऐसी एप्लिकेशंस बनाते हैं जो बाहरी दुनिया के साथ इंटरैक्ट करती हैं, तो आप मूल रूप से डेटा रूलेट का खेल खेल रहे होते हैं। उपयोगकर्ता फोन नंबर को integer के बजाय string के रूप में सबमिट कर सकते हैं, कोई API वहाँ null मान लौटा सकता है जहाँ आप संख्या की अपेक्षा करते हैं, या कोई कॉन्फ़िगरेशन फ़ाइल में टाइपो हो सकता है जो आपकी एप्लिकेशन को रात 3 बजे तोड़ दे।
इस समस्या के पारंपरिक Python दृष्टिकोण जल्दी ही बोझिल हो जाते हैं। आप इस तरह का वैलिडेशन कोड लिखते-लिखते रह जाते हैं:
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'])
इसे अपनी एप्लिकेशन के हर डेटा स्ट्रक्चर से गुणा करें, और आप बिजनेस लॉजिक से अधिक समय वैलिडेशन कोड लिखने में बिताएँगे।
Pydantic इसे तीन शक्तिशाली अवधारणाओं को जोड़कर हल करता है: टाइप हिंट्स, रनटाइम वैलिडेशन, और स्वचालित सीरियलाइज़ेशन। मैनुअल चेक्स के बजाय, आप Python की टाइप एनोटेशन सिंटैक्स का उपयोग करके एक बार अपना डेटा स्ट्रक्चर परिभाषित करते हैं, और Pydantic स्वतः सभी वैलिडेशन संभाल लेता है:
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": "john@example.com",
"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
Pydantic की विशेषताएँ
Pydantic का दृष्टिकोण आपको कई लाभ देता है। प्रदर्शन पहला फायदा है जो आप नोटिस करेंगे—Pydantic का कोर वैलिडेशन लॉजिक Rust में लिखा गया है, जो अधिकांश मामलों में हाथ से लिखे Python वैलिडेशन से तेज़ है। आपकी एप्लिकेशन हज़ारों अनुरोध प्रोसेस कर सकती है बिना वैलिडेशन के बाधा बनने के।
Pydantic आधुनिक फ्रेमवर्क्स के साथ एकीकरण भी सक्षम करता है। FastAPI, Python के सबसे तेज़ी से बढ़ते वेब फ्रेमवर्क्स में से एक, Pydantic मॉडल्स का उपयोग करके स्वतः API दस्तावेज़ बनाता है, अनुरोध बॉडीज़ को वैलिडेट करता है, और प्रतिक्रियाओं को सीरियलाइज़ करता है। जब आप एक Pydantic मॉडल परिभाषित करते हैं, तो आपको OpenAPI स्कीमा जेनरेशन मुफ़्त में मिल जाता है:
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}"}
हर Pydantic मॉडल के साथ JSON स्कीमा जेनरेशन स्वतः होता है। इसका मतलब है कि आपके डेटा स्ट्रक्चर स्वयं-दस्तावेज़ी बन जाते हैं, और आप इसी स्रोत से क्लाइंट लाइब्रेरीज़, फ्रंटएंड एप्लिकेशनों के लिए वैलिडेशन नियम, या डेटाबेस स्कीमा जनरेट कर सकते हैं।
Pydantic बनाम Dataclasses बनाम Marshmallow
लेकिन आपको विकल्पों की तुलना में कब Pydantic चुनना चाहिए? यदि आप Pydantic बनाम dataclasses की तुलना कर रहे हैं, तो निर्णय आपकी वैलिडेशन आवश्यकताओं पर निर्भर करता है। Python का @dataclass सरल डेटा कंटेनरों के लिए उपयुक्त है जहाँ आप इनपुट पर भरोसा करते हैं, लेकिन जब आपको वैलिडेशन, सीरियलाइज़ेशन, और वेब फ्रेमवर्क एकीकरण की ज़रूरत हो, तो Pydantic उत्कृष्ट है:
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
Pydantic की Marshmallow से तुलना करते समय, Pydantic का टाइप हिंट दृष्टिकोण Python डेवलपर्स को अधिक स्वाभाविक लगता है, जबकि Marshmallow स्कीमा क्लासेज़ का उपयोग करता है। Pydantic बेहतर प्रदर्शन और आधुनिक async फ्रेमवर्क्स के साथ आसान एकीकरण भी प्रदान करता है।
Pydantic तब सबसे अच्छा काम करता है जब आप APIs बना रहे हों, बाहरी डेटा प्रोसेस कर रहे हों, कॉन्फ़िगरेशन प्रबंधित कर रहे हों, या ऐसी किसी भी स्थिति में जहाँ डेटा वैलिडेशन असफलता को जल्द पकड़ना चाहिए ताकि बाद में रहस्यमयी बग्स न हों। यह रनटाइम त्रुटियों को स्पष्ट, क्रियात्मक वैलिडेशन संदेशों में बदल देता है जो डेवलपर्स और उपयोगकर्ताओं दोनों को समझने में मदद करते हैं कि क्या गलत हुआ।
Pydantic के साथ शुरुआत करना
आइए इंस्टॉलेशन से लेकर अपना पहला डेटा मॉडल बनाने तक, आपके प्रोजेक्ट्स में Pydantic का उपयोग कैसे करें, इसमें गहराई से उतरते हैं।
इंस्टॉलेशन और सेटअप
Pydantic सेट करना सरल है, लेकिन कुछ सामान्य गलतियाँ नए उपयोगकर्ताओं को परेशान कर सकती हैं। मैं आपको उचित इंस्टॉलेशन प्रक्रिया से गुज़ारूँगा और उन गलतियों से बचने में मदद करूँगा जो अनावश्यक डिबगिंग का कारण बनती हैं।
सबसे पहले, अपने प्रोजेक्ट की निर्भरताएँ अलग-थलग रखने के लिए एक वर्चुअल एनवायरनमेंट बनाएं। यह संस्करण टकरावों को रोकता है जो बाद में रहस्यमयी इम्पोर्ट त्रुटियों का कारण बन सकते हैं:
# 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
अब, निम्न कमांड से Pydantic इंस्टॉल करें:
pip install pydantic
ईमेल वैलिडेशन फ़ंक्शनैलिटी के लिए, जिसकी आपको वास्तविक एप्लिकेशनों (और इस ट्यूटोरियल) में सम्भवतः आवश्यकता होगी, ईमेल एक्स्ट्राज़ इंस्टॉल करें:
pip install "pydantic[email]"
pydantic[email] के चारों ओर उद्धरण चिह्न लगभग सभी टर्मिनल्स में महत्वपूर्ण हैं। इनके बिना, आपको "no matches found" त्रुटि दिख सकती है।
ध्यान दें: यदि आपको ModuleNotFoundError: No module named 'pydantic' मिलती है, तो इन मुद्दों की जाँच करें:
- गलत Python एनवायरनमेंट: सुनिश्चित करें कि आपका वर्चुअल एनवायरनमेंट सक्रिय है
- एकाधिक Python संस्करण: सत्यापित करें कि आप वही Python संस्करण उपयोग कर रहे हैं जिससे Pydantic इंस्टॉल किया गया था
- IDE कॉन्फ़िगरेशन: आपका कोड एडिटर किसी अन्य Python इंटरप्रेटर का उपयोग कर सकता है
महत्वपूर्ण नामकरण चेतावनी: अपनी Python फ़ाइल का नाम कभी भी pydantic.py न रखें। यह एक सर्कुलर इम्पोर्ट बनाता है जो भ्रमित करने वाले एरर संदेशों के साथ आपके कोड को तोड़ देगा। Python असली Pydantic लाइब्रेरी के बजाय आपकी फ़ाइल को इम्पोर्ट करने की कोशिश करेगा।
आपका पहला Pydantic मॉडल
Pydantic को एक्शन में देखने के लिए एक सरल यूज़र मॉडल बनाते हैं। अमूर्त उदाहरणों से शुरू करने के बजाय, हम एक वास्तविक समस्या हल करेंगे: वेब फ़ॉर्म से उपयोगकर्ता पंजीकरण डेटा का वैलिडेशन।
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": "alice@example.com",
"age": 28
}
user = User(**clean_data)
print(f"User created: {user.name}, Age: {user.age}")
print(f"Model output: {user.model_dump()}")
आउटपुट:
User created: Alice Johnson, Age: 28
Model output: {'name': 'Alice Johnson', 'email': 'alice@example.com', 'age': 28, 'is_active': True, 'created_at': None}
आइए देखें कि इस मॉडल परिभाषा में क्या हो रहा है:
- Pydantic मॉडल बनाना: आपकी
Userक्लासBaseModelसे इनहेरिट करती है, जो इसे Pydantic की सभी वैलिडेशन और सीरियलाइज़ेशन क्षमताएँ देती है। यह इनहेरिटेंस एक सामान्य Python क्लास को डेटा वैलिडेशन टूल में बदल देता है। - फ़ील्ड परिभाषाएँ: क्लास में प्रत्येक पंक्ति अपेक्षित टाइप के साथ एक फ़ील्ड परिभाषित करती है।
name: strसिंटैक्स Pydantic को बताता है किnameएक string होना चाहिए,age: intका मतलब है age एक integer होना चाहिए, आदि। - EmailStr का अर्थ:
EmailStrएक विशेष Pydantic टाइप है जो ईमेल पतों को स्वतः वैलिडेट करता है। यह उसpydantic[email]पैकेज से आता है जिसे आपने पहले इंस्टॉल किया था और ईमेल फ़ॉर्मेट मान्य होने के लिए रेगुलर एक्सप्रेशन का उपयोग करता है। यदि कोई "not-an-email" देता है, तो Pydantic वैलिडेशन त्रुटि उठाएगा। - डिफ़ॉल्ट मान:
is_active: bool = Trueजैसे फ़ील्ड्स के डिफ़ॉल्ट मान होते हैं। यदि आप यूज़र बनाते समय ये फ़ील्ड नहीं देते, तो Pydantic डिफ़ॉल्ट्स का उपयोग करता है।created_atके लिए= Noneइसे वैकल्पिक बनाता है। - मॉडल इंस्टीएशन: जब आप
User(**clean_data)कॉल करते हैं, तो**आपके डिक्शनरी को अनपैक करता है और प्रत्येक key-value जोड़ी को मॉडल कन्स्ट्रक्टर में कीवर्ड आर्ग्युमेंट्स के रूप में पास करता है।
अब Pydantic के स्वचालित टाइप कन्वर्ज़न को एक्शन में देखते हैं:
# Messy data that still works
messy_data = {
"name": "Bob Smith",
"email": "bob@company.com",
"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'>
अब Pydantic के स्वचालित टाइप कन्वर्ज़न को एक्शन में देखते हैं:
# Messy data that still works
messy_data = {
"name": "Bob Smith",
"email": "bob@company.com",
"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'>
आउटपुट:
Age type: <class 'int'>
Is active type: <class 'bool'>
जैसा कि आप देख सकते हैं, age और is_inactive फ़ील्ड्स वैलिडेशन के माध्यम से स्वतः अपने उपयुक्त फ़ॉर्मैट्स में कन्वर्ट हो जाते हैं।
जब वैलिडेशन असफल होता है, तो Pydantic स्पष्ट त्रुटि संदेश देता है:
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)
आउटपुट:
# 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 बनाम data classes
यह समझना कि कब Pydantic के BaseModel के बजाय Python के @dataclass का उपयोग करना है, आपको हर स्थिति के लिए सही टूल चुनने में मदद करता है।
Python dataclasses सरल डेटा कंटेनरों के लिए उपयुक्त हैं जहाँ आप इनपुट नियंत्रित करते हैं:
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")
Pydantic मॉडल वैलिडेशन, सीरियलाइज़ेशन, और फ्रेमवर्क इंटीग्रेशन जोड़ते हैं:
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
)
कब किस दृष्टिकोण को चुनें:
- Dataclasses उपयोग करें आंतरिक डेटा स्ट्रक्चर, कॉन्फ़िगरेशन ऑब्जेक्ट्स के लिए, या जब प्रदर्शन महत्वपूर्ण हो और आप अपने डेटा स्रोतों पर भरोसा करते हों
- Pydantic उपयोग करें API एंडपॉइंट्स, उपयोगकर्ता इनपुट, बाहरी डेटा पार्सिंग, या जब आपको JSON सीरियलाइज़ेशन चाहिए
Dataclasses की तुलना में Pydantic कुछ ओवरहेड जोड़ता है, लेकिन यह लागत आमतौर पर उन बग्स की तुलना में नगण्य होती है जिन्हें यह रोकता है और जो विकास समय यह बचाता है। वेब एप्लिकेशनों के लिए, FastAPI जैसे फ्रेमवर्क्स के साथ स्वचालित एकीकरण Pydantic को स्पष्ट पसंद बनाता है।
जैसे-जैसे आपकी एप्लिकेशन बढ़ती है, वैलिडेशन और सीरियलाइज़ेशन सुविधाएँ अधिक मूल्यवान हो जाती हैं। Pydantic मॉडल्स से शुरुआत करना आपको एक ठोस नींव देता है जो आपकी आवश्यकताओं के साथ स्केल करती है।
Pydantic के साथ डेटा मॉडल बनाना
अब जब आप बुनियादी बातें समझ चुके हैं, तो आइए उन चुनौतियों का सामना करें जो आप प्रोडक्शन-रेडी एप्लिकेशन्स बनाते समय देखेंगे।
फ़ील्ड वैलिडेशन और बाधाएँ
एक प्रोडक्ट कैटलॉग API पर विचार करें जहाँ मूल्य डेटा कई विक्रेताओं से अलग-अलग फॉर्मेटिंग मानकों के साथ आता है। कुछ कीमतें strings के रूप में भेजते हैं, कुछ floats के रूप में, और कभी-कभी कोई नकारात्मक कीमत भेज देता है जो आपकी बिलिंग प्रणाली को क्रैश कर देती है।
Pydantic का Field() फ़ंक्शन बुनियादी टाइप हिंट्स को उन्नत वैलिडेशन नियमों में बदल देता है जो आपकी एप्लिकेशन की सुरक्षा करते हैं:
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")
प्रत्येक Field() पैरामीटर का एक विशिष्ट उद्देश्य है: min_length और max_length डेटाबेस स्कीमा उल्लंघनों को रोकते हैं, gt और le बिजनेस लॉजिक सीमाएँ बनाते हैं, और pattern रेगुलर एक्सप्रेशन का उपयोग करके फ़ॉर्मैटेड डेटा को वैलिडेट करता है। Field(...) सिंटैक्स में इलिप्सिस आवश्यक फ़ील्ड्स को चिह्नित करता है, जबकि Field(None, ...) वैलिडेशन नियमों के साथ वैकल्पिक फ़ील्ड्स बनाता है।
टाइप coercion बनाम सख्त वैलिडेशन
डिफ़ॉल्ट रूप से, Pydantic संगत टाइप्स को अस्वीकार करने के बजाय कन्वर्ट कर देता है। यह लचीलापन उपयोगकर्ता इनपुट के लिए अच्छा काम करता है, लेकिन कुछ परिदृश्यों में सटीक टाइप मिलान की आवश्यकता होती है:
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)
model_config डिक्शनरी आपके पूरे मॉडल में वैलिडेशन व्यवहार को नियंत्रित करती है। str_strip_whitespace विकल्प स्वतः string इनपुट को साफ करता है, जबकि validate_assignment यह सुनिश्चित करता है कि मॉडल बनने के बाद भी फ़ील्ड में बदलाव वैलिडेशन ट्रिगर करें। व्यक्तिगत फ़ील्ड्स इन सेटिंग्स को Field(strict=True) से ओवरराइड कर सकते हैं, खासतौर पर तब जब सटीक टाइप मिलान ज़रूरी हो, जैसे वित्तीय गणनाएँ या वैज्ञानिक डेटा।
नेस्टेड मॉडल्स और जटिल डेटा
वास्तविक एप्लिकेशन्स जटिल, परस्पर जुड़े डेटा स्ट्रक्चर्स को संभालती हैं। एक ई-कॉमर्स ऑर्डर में ग्राहक जानकारी, शिपिंग पते, और कई प्रोडक्ट आइटम होते हैं—प्रत्येक को अपने स्वयं के वैलिडेशन की आवश्यकता होती है:
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": "john@example.com",
"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 नेस्टेड स्ट्रक्चर्स को रिकर्सिवली वैलिडेट करता है—Customer फ़ील्ड एक पूर्ण Customer ऑब्जेक्ट बन जाता है, जो अपने Address फ़ील्ड को वैलिडेट करता है। List[OrderItem] सिंटैक्स सूची के प्रत्येक तत्व को OrderItem के रूप में वैलिडेट करता है, जबकि Field(min_items=1) आपके इन्वेंटरी सिस्टम तक खाली ऑर्डर पहुँचने से रोकता है। default_factory=datetime.now का उपयोग प्रत्येक ऑर्डर इंस्टेंस के लिए यूनिक टाइमस्टैम्प बनाता है।
वैकल्पिक फ़ील्ड्स और None हैंडलिंग
अलग-अलग ऑपरेशन्स को अलग-अलग डेटा आवश्यकताओं की ज़रूरत होती है। उपयोगकर्ता निर्माण में पूरी जानकारी चाहिए होती है, जबकि अपडेट्स को आंशिक बदलाव स्वीकार करने चाहिए:
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())}")
सीरियलाइज़ेशन Pydantic ऑब्जेक्ट्स को वापस डिक्शनरीज़ या JSON स्ट्रिंग्स में बदलता है ताकि उन्हें संग्रहीत या स्थानांतरित किया जा सके। model_dump() यह कन्वर्ज़न संभालता है, और exclude_none=True अनप्रोवाइडेड फ़ील्ड्स को हटा देता है। यह पैटर्न उन PATCH अनुरोधों के लिए बिल्कुल सही काम करता है जहाँ क्लाइंट्स केवल वे फ़ील्ड्स भेजते हैं जिन्हें वे बदलना चाहते हैं, जिससे आपके डेटाबेस में आकस्मिक डेटा ओवरराइट्स रुकते हैं।
यह नींव आपको अगली चुनौती के लिए तैयार करती है: कस्टम वैलिडेशन लॉजिक लागू करना जो आपकी एप्लिकेशन के विशिष्ट बिजनेस नियमों को कैप्चर करता है।
कस्टम वैलिडेशन और वास्तविक-world इंटीग्रेशन
प्रोडक्शन एप्लिकेशन्स बनाना ऐसे डेटा को संभालना होता है जो मानक टाइप-चेकिंग पैटर्न में फिट नहीं बैठता।
एक यूज़र रजिस्ट्रेशन फ़ॉर्म पर विचार करें जहाँ पासवर्ड आवश्यकताएँ सब्सक्रिप्शन प्लान के आधार पर बदलती हैं, या एक API जो अलग-अलग देशों से अलग-अलग पोस्टल कोड फ़ॉर्मैट्स के साथ एड्रेस डेटा प्राप्त करता है। इन परिदृश्यों में कस्टम वैलिडेशन लॉजिक की आवश्यकता होती है, जो आपके विशिष्ट बिजनेस नियमों को कैप्चर करता है और वेब फ्रेमवर्क्स व कॉन्फ़िगरेशन सिस्टम्स के साथ सहजता से एकीकृत होता है।
यह अनुभाग आपको व्यावहारिक कस्टम वैलिडेशन पैटर्न लागू करना, Pydantic मॉडल्स को FastAPI के साथ इंटीग्रेट करके स्वचालित API दस्तावेज़ीकरण प्राप्त करना, और .env फ़ाइल एप्रोच का उपयोग करके एनवायरनमेंट वेरिएबल्स के माध्यम से एप्लिकेशन सेटिंग्स प्रबंधित करना सिखाता है, जिस पर अधिकांश प्रोडक्शन एप्लिकेशन्स निर्भर करते हैं।
फ़ील्ड वेलिडेटर्स और मॉडल वैलिडेशन
जब बिजनेस लॉजिक डेटा की वैधता निर्धारित करता है, तो Pydantic का @field_validator डेकोरेटर आपकी वैलिडेशन फ़ंक्शन्स को मॉडल का हिस्सा बना देता है। एक यूज़र रजिस्ट्रेशन सिस्टम पर विचार करें जहाँ अलग-अलग सब्सक्रिप्शन टियर्स की अलग-अलग पासवर्ड आवश्यकताएँ हों:
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
@field_validator डेकोरेटर आपको info.data पैरामीटर के माध्यम से अन्य फ़ील्ड मानों तक पहुँच देता है, जिससे बहु-फ़ील्ड पर निर्भर वैलिडेशन नियम संभव होते हैं। वेलिडेटर बेसिक टाइप जाँच पास होने के बाद चलता है, इसलिए आप सुरक्षित रूप से मान सकते हैं कि subscription_tier अनुमत मानों में से एक है।
कई फ़ील्ड्स में फैले वैलिडेशन के लिए, @model_validator डेकोरेटर सभी व्यक्तिगत फ़ील्ड्स के वैलिडेट होने के बाद चलता है:
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
mode='after' पैरामीटर सुनिश्चित करता है कि वेलिडेटर को पूरी तरह निर्मित मॉडल इंस्टेंस मिले, जो ऐसे बिजनेस लॉजिक के लिए उपयुक्त है जिसे सभी वैलिडेटेड फ़ील्ड्स तक पहुँच चाहिए। सफल वैलिडेशन दर्शाने के लिए वेलिडेटर को self लौटाना चाहिए।
FastAPI इंटीग्रेशन
FastAPI का Pydantic के साथ एकीकरण स्वतः अनुरोध वैलिडेशन और API दस्तावेज़ीकरण बनाता है। मुख्य पैटर्न विभिन्न ऑपरेशन्स के लिए अलग-अलग मॉडल बनाना है, जिससे आपको हर दिशा में प्रवाहित होने वाले डेटा पर नियंत्रण मिलता है:
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)
इनपुट और आउटपुट मॉडल्स के बीच पृथक्करण कई लाभ देता है। इनपुट मॉडल्स में वैलिडेशन नियम और आवश्यक फ़ील्ड्स शामिल हो सकते हैं, जबकि आउटपुट मॉडल्स नियंत्रित करते हैं कि क्लाइंट्स को क्या डेटा भेजा जाए। FastAPI आपके Pydantic मॉडल्स से स्वतः OpenAPI दस्तावेज़ बनाता है, जो इंटरैक्टिव API डॉक्स तैयार करता है जिन्हें डेवलपर्स एंडपॉइंट्स की जाँच के लिए उपयोग कर सकते हैं।
अपडेट ऑपरेशन्स के लिए, आप ऐसे मॉडल्स बना सकते हैं जिनमें सभी फ़ील्ड्स वैकल्पिक हों:
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}"}
PATCH ऑपरेशन्स में exclude_unset=True पैरामीटर सुनिश्चित करता है कि आप केवल उन्हीं फ़ील्ड्स को अपडेट करें जो स्पष्ट रूप से प्रदान किए गए थे, जिससे आकस्मिक ओवरराइट्स रुकते हैं। यह पैटर्न उन REST APIs के लिए बिल्कुल उचित है जहाँ क्लाइंट्स आंशिक अपडेट्स भेजते हैं।
एनवायरनमेंट वेरिएबल्स के साथ कॉन्फ़िगरेशन प्रबंधन
प्रोडक्शन एप्लिकेशन्स को सुरक्षित, डिप्लॉयमेंट-फ्रेंडली कॉन्फ़िगरेशन प्रबंधन की आवश्यकता होती है। Pydantic का BaseSettings .env फ़ाइलों के साथ मिलकर टाइप-सुरक्षित कॉन्फ़िगरेशन प्रदान करता है जो डेवलपमेंट, स्टेजिंग और प्रोडक्शन एनवायरनमेंट्स में काम करता है।
सबसे पहले, अपने प्रोजेक्ट रूट में एक .env फ़ाइल बनाएं:
# .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
फिर अपनी सेटिंग्स मॉडल परिभाषित करें:
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()
BaseSettings क्लास स्वतः एनवायरनमेंट वेरिएबल्स, .env फ़ाइलों, और कमांड-लाइन आर्ग्युमेंट्स से पढ़ता है। एनवायरनमेंट वेरिएबल्स को .env फ़ाइल मानों पर प्राथमिकता मिलती है, जिससे अलग-अलग डिप्लॉयमेंट एनवायरनमेंट्स में सेटिंग्स को ओवरराइड करना आसान हो जाता है। case_sensitive = False सेटिंग एनवायरनमेंट वेरिएबल्स के नामों को लचीला बनाती है।
जटिल एप्लिकेशन्स के लिए, आप सेटिंग्स को तार्किक समूहों में व्यवस्थित कर सकते हैं:
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
यह नेस्टेड एप्रोच संबंधित सेटिंग्स को एक साथ रखता है, जबकि आपकी एप्लिकेशन के अलग-अलग घटकों के बीच स्पष्ट विभाजन बनाए रखता है। प्रत्येक सेटिंग्स समूह की अपनी एनवायरनमेंट वेरिएबल प्रीफिक्स और वैलिडेशन नियम हो सकते हैं।
.env फ़ाइल एप्रोच Heroku, AWS, और Docker जैसे डिप्लॉयमेंट प्लेटफॉर्म्स के साथ काम करता है, जहाँ एनवायरनमेंट वेरिएबल्स एप्लिकेशन्स को कॉन्फ़िगर करने का मानक तरीका हैं। आपकी एप्लिकेशन को टाइप सेफ़्टी और वैलिडेशन मिलता है, जबकि वह क्लाउड-नेटिव कॉन्फ़िगरेशन पैटर्न का पालन करती है जिसकी ऑपरेशन्स टीमें अपेक्षा करती हैं।
ये पैटर्न वास्तविक-world जटिलता को संभालने वाली मेंटेनेबल एप्लिकेशन्स बनाने की नींव तैयार करते हैं। Pydantic की वैलिडेशन प्रणाली आपकी विशिष्ट आवश्यकताओं के अनुरूप ढलती है और स्पष्ट त्रुटि संदेश व स्वचालित दस्तावेज़ीकरण प्रदान करती है, जो आपकी पूरी टीम को समझने में मदद करता है कि आपकी एप्लिकेशन किन डेटा स्ट्रक्चर्स की अपेक्षा करती है।
निष्कर्ष
अब आपने देखा कि Pydantic आपको हाथ से वैलिडेशन कोड लिखने के उबाऊ काम से कैसे बचा सकता है। अपने फ़ंक्शन्स को isinstance() चेक्स और कस्टम एरर हैंडलिंग से भरने के बजाय, आप एक बार अपना डेटा स्ट्रक्चर परिभाषित करते हैं और बाकी Pydantic संभाल लेता है।
नीचे दिए गए FAQs अनुभाग को ज़रूर पढ़ें, जहाँ अधिक विशिष्ट Pydantic प्रश्नों के उत्तर हैं। व्यापक दस्तावेज़ और उन्नत पैटर्न्स के लिए, आप इन संसाधनों का उपयोग कर सकते हैं:
- आधिकारिक दस्तावेज़:
- Pydantic Documentation—उदाहरणों और सर्वोत्तम प्रथाओं के साथ पूर्ण संदर्भ
- Pydantic Migration Guide—संस्करण उन्नयन के लिए आवश्यक पठन
- FastAPI Documentation—जानें कि Pydantic कैसे स्वचालित API दस्तावेज़ीकरण को शक्ति देता है
- संबंधित DataCamp लर्निंग संसाधन:
- Model Validation in Python—scikit-learn के साथ वैलिडेशन तकनीकों में गहराई
- Introduction to FastAPI—Pydantic इंटीग्रेशन के साथ प्रोडक्शन APIs बनाएँ
- Introduction to APIs in Python—बाहरी APIs और JSON डेटा वैलिडेशन के साथ कार्य करें
- Intermediate Python—Pydantic उपयोग को पूरक करने वाली Python मूल बातें में महारत हासिल करें
- Object-Oriented Programming in Python—Pydantic मॉडल्स को समझने की नींव बनाएँ
FAQs
क्या Pydantic वैलिडेशन मेरी एप्लिकेशन को धीमा कर देता है?
Pydantic V2 अंदरूनी तौर पर Rust से बना है, जिससे यह बहुत तेज़ है। अधिकांश एप्लिकेशनों के लिए, वैलिडेशन ओवरहेड उन बग्स की तुलना में न्यूनतम है जिन्हें यह रोकता है। जब प्रदर्शन महत्वपूर्ण हो और डेटा स्रोत विश्वसनीय हों, तो आप model_construct() का उपयोग करके वैलिडेशन को स्किप कर सकते हैं।
मुझे Python dataclasses के बजाय Pydantic कब उपयोग करना चाहिए?
जब आपको वैलिडेशन की ज़रूरत हो, बाहरी डेटा स्रोतों के साथ काम करना हो, या APIs बनानी हों, तब Pydantic का उपयोग करें। सरल आंतरिक डेटा स्ट्रक्चर्स के लिए, जहाँ आप इनपुट पर भरोसा करते हैं, dataclasses का उपयोग करें। जब डेटा उपयोगकर्ताओं, APIs, या कॉन्फ़िगरेशन फ़ाइलों से आता है, तो Pydantic उत्कृष्ट होता है।
प्रोडक्शन एप्लिकेशनों में Pydantic वैलिडेशन त्रुटियों को कैसे संभालें?
ValidationError अपवादों को पकड़ें और संरचित त्रुटि जानकारी पाने के लिए .errors() सूची निकालें। प्रत्येक त्रुटि में loc, msg, और type फ़ील्ड होते हैं, जो आपको उपयोगकर्ता-अनुकूल त्रुटि संदेश देने या विस्तृत डिबगिंग जानकारी लॉग करने में मदद करते हैं।
क्या मैं बिना सब कुछ तोड़े मौजूदा कोड में Pydantic जोड़ सकता/सकती हूँ?
हाँ! बाहरी डेटा एंट्री पॉइंट्स (API अनुरोध, फ़ाइल पार्सिंग) को Pydantic मॉडल्स से लपेटकर शुरू करें। आप धीरे-धीरे आंतरिक डेटा स्ट्रक्चर्स को बदल सकते हैं। Pydantic मौजूदा कोड के साथ काम करता है और आपको एक बार में पूरी कोडबेस बदलने की आवश्यकता नहीं होती।
Pydantic शुरू करते समय सबसे आम गलती क्या होती है?
टाइप coercion को न समझना। Pydantic डिफ़ॉल्ट रूप से संगत टाइप्स को कन्वर्ट कर देता है (जैसे string "123" को integer 123)। यदि आपको सख्त टाइप जाँच चाहिए, तो Field(strict=True) का उपयोग करें या अपने मॉडल कॉन्फ़िगरेशन में strict मोड सेट करें, ताकि स्वचालित कन्वर्ज़न रोके जा सकें।
मैं 2 से अधिक वर्षों के अनुभव वाला डेटा साइंस कंटेंट क्रिएटर हूँ और Medium पर सबसे बड़े फॉलोइंग्स में से एक रखता हूँ। मुझे एआई और एमएल पर विस्तार से लेख लिखना पसंद है, जिसमें हल्का-सा व्यंग्यात्मक अंदाज रहता है—क्योंकि कुछ तो करना पड़ता है ताकि वे कम उबाऊ लगें। मैंने 130 से अधिक लेख और एक DataCamp कोर्स तैयार किया है, और एक और बन रहा है। मेरा कंटेंट 50 लाख से अधिक लोगों ने देखा है, जिनमें से 20 हज़ार लोग Medium और LinkedIn पर फॉलोअर्स बन गए।
