راهنمای جامع وراثت مدل در جنگو، شامل کلاسهای پایه انتزاعی و وراثت چند-جدولی همراه با مثالهای عملی و ملاحظات طراحی پایگاه داده.
وراثت مدل در جنگو: مدلهای انتزاعی در مقابل وراثت چند-جدولی
نگاشتگر شیء-رابطهای (ORM) جنگو ویژگیهای قدرتمندی برای مدلسازی دادهها و تعامل با پایگاههای داده فراهم میکند. یکی از جنبههای کلیدی طراحی کارآمد پایگاه داده در جنگو، درک و استفاده از وراثت مدل است. این امکان به شما اجازه میدهد تا فیلدها و رفتارهای مشترک را در چندین مدل بازاستفاده کنید، که منجر به کاهش تکرار کد و بهبود قابلیت نگهداری میشود. جنگو دو نوع اصلی از وراثت مدل را ارائه میدهد: کلاسهای پایه انتزاعی (abstract base classes) و وراثت چند-جدولی (multi-table inheritance). هر رویکرد موارد استفاده و پیامدهای خاص خود را برای ساختار پایگاه داده و عملکرد کوئریها دارد. این مقاله به بررسی جامع هر دو روش میپردازد و شما را در مورد زمان استفاده از هر نوع و نحوه پیادهسازی مؤثر آنها راهنمایی میکند.
درک وراثت مدل
وراثت مدل یک مفهوم بنیادی در برنامهنویسی شیءگرا است که به شما امکان میدهد کلاسهای جدیدی (در جنگو، مدلها) را بر اساس کلاسهای موجود ایجاد کنید. کلاس جدید، ویژگیها و متدهای کلاس والد را به ارث میبرد و به شما این امکان را میدهد که رفتار والد را بدون بازنویسی کد، گسترش دهید یا تخصصی کنید. در جنگو، وراثت مدل برای به اشتراک گذاشتن فیلدها، متدها و گزینههای متا در چندین مدل استفاده میشود.
انتخاب نوع صحیح وراثت برای ساختن یک پایگاه داده با ساختار خوب و کارآمد بسیار مهم است. استفاده نادرست از وراثت میتواند منجر به مشکلات عملکردی و اسکیمای پیچیده پایگاه داده شود. بنابراین، درک تفاوتهای ظریف هر رویکرد ضروری است.
کلاسهای پایه انتزاعی
کلاسهای پایه انتزاعی چه هستند؟
کلاسهای پایه انتزاعی مدلهایی هستند که برای ارثبری طراحی شدهاند، اما قرار نیست مستقیماً نمونهسازی شوند. آنها به عنوان طرح اولیه برای مدلهای دیگر عمل میکنند و فیلدها و متدهای مشترکی را تعریف میکنند که باید در تمام مدلهای فرزند وجود داشته باشند. در جنگو، شما یک کلاس پایه انتزاعی را با تنظیم ویژگی abstract کلاس Meta مدل به True تعریف میکنید.
هنگامی که یک مدل از یک کلاس پایه انتزاعی ارث میبرد، جنگو تمام فیلدها و متدهای تعریف شده در کلاس پایه انتزاعی را در مدل فرزند کپی میکند. با این حال، خود کلاس پایه انتزاعی به عنوان یک جدول جداگانه در پایگاه داده ایجاد نمیشود. این یک تفاوت کلیدی با وراثت چند-جدولی است.
چه زمانی از کلاسهای پایه انتزاعی استفاده کنیم؟
کلاسهای پایه انتزاعی زمانی ایدهآل هستند که شما مجموعهای از فیلدهای مشترک دارید که میخواهید در چندین مدل অন্তর্ভুক্ত کنید، اما نیازی به کوئری زدن مستقیم به کلاس پایه انتزاعی ندارید. برخی از موارد استفاده رایج عبارتند از:
- مدلهای دارای مهر زمانی: افزودن فیلدهای
created_atوupdated_atبه چندین مدل. - مدلهای مرتبط با کاربر: افزودن فیلد
userبه مدلهایی که با یک کاربر خاص مرتبط هستند. - مدلهای فراداده (Metadata): افزودن فیلدهایی مانند
title،descriptionوkeywordsبرای اهداف سئو.
مثالی از کلاس پایه انتزاعی
بیایید یک مثال از یک کلاس پایه انتزاعی برای مدلهای دارای مهر زمانی ایجاد کنیم:
from django.db import models
class TimeStampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Article(TimeStampedModel):
title = models.CharField(max_length=200)
content = models.TextField()
def __str__(self):
return self.title
class Comment(TimeStampedModel):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.TextField()
def __str__(self):
return self.text
در این مثال، TimeStampedModel یک کلاس پایه انتزاعی با فیلدهای created_at و updated_at است. هر دو مدل Article و Comment از TimeStampedModel ارث میبرند و به طور خودکار این فیلدها را دریافت میکنند. هنگامی که شما دستور python manage.py migrate را اجرا میکنید، جنگو دو جدول Article و Comment ایجاد میکند که هر کدام دارای فیلدهای created_at و updated_at هستند. هیچ جدولی برای خود `TimeStampedModel` ایجاد نخواهد شد.
مزایای کلاسهای پایه انتزاعی
- قابلیت استفاده مجدد کد: از تکرار فیلدها و متدهای مشترک در چندین مدل جلوگیری میکند.
- اسکیمای سادهتر پایگاه داده: تعداد جداول در پایگاه داده را کاهش میدهد، زیرا خود کلاس پایه انتزاعی یک جدول نیست.
- قابلیت نگهداری بهبود یافته: تغییرات در کلاس پایه انتزاعی به طور خودکار در تمام مدلهای فرزند منعکس میشود.
معایب کلاسهای پایه انتزاعی
- عدم امکان کوئری مستقیم: شما نمیتوانید مستقیماً به کلاس پایه انتزاعی کوئری بزنید. شما فقط میتوانید به مدلهای فرزند کوئری بزنید.
- چندریختی محدود: اگر نیاز به دسترسی به فیلدهای مشترک تعریف شده در کلاس انتزاعی از طریق یک کوئری واحد داشته باشید، رفتار یکسان با نمونههای مدلهای فرزند مختلف دشوارتر است. شما باید به هر مدل فرزند به طور جداگانه کوئری بزنید.
وراثت چند-جدولی
وراثت چند-جدولی چیست؟
وراثت چند-جدولی نوعی از وراثت مدل است که در آن هر مدل در سلسله مراتب وراثت، جدول پایگاه داده مخصوص به خود را دارد. هنگامی که یک مدل با استفاده از وراثت چند-جدولی از مدل دیگری ارث میبرد، جنگو به طور خودکار یک رابطه یک-به-یک بین مدل فرزند و مدل والد ایجاد میکند. این به شما امکان میدهد تا از طریق یک نمونه از مدل فرزند، به فیلدهای هر دو مدل فرزند و والد دسترسی داشته باشید.
چه زمانی از وراثت چند-جدولی استفاده کنیم؟
وراثت چند-جدولی زمانی مناسب است که شما میخواهید مدلهای تخصصی ایجاد کنید که رابطه واضح "is-a" (یک نوعی از) با یک مدل عمومیتر دارند. برخی از موارد استفاده رایج عبارتند از:
- پروفایلهای کاربری: ایجاد پروفایلهای کاربری تخصصی برای انواع مختلف کاربران (مانند مشتریان، فروشندگان، مدیران).
- انواع محصول: ایجاد مدلهای محصول تخصصی برای انواع مختلف محصولات (مانند کتاب، لوازم الکترونیکی، پوشاک).
- انواع محتوا: ایجاد مدلهای محتوای تخصصی برای انواع مختلف محتوا (مانند مقالات، پستهای وبلاگ، اخبار).
مثالی از وراثت چند-جدولی
بیایید یک مثال از وراثت چند-جدولی برای پروفایلهای کاربری ایجاد کنیم:
from django.db import models
from django.contrib.auth.models import User
class Customer(User):
phone_number = models.CharField(max_length=20, blank=True)
address = models.CharField(max_length=200, blank=True)
def __str__(self):
return self.username
class Vendor(User):
company_name = models.CharField(max_length=100, blank=True)
payment_terms = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.username
در این مثال، هر دو مدل Customer و Vendor از مدل داخلی User ارث میبرند. جنگو سه جدول ایجاد میکند: auth_user (برای مدل User)، customer، و vendor. جدول customer یک رابطه یک-به-یک (به طور ضمنی یک ForeignKey) با جدول auth_user خواهد داشت. به طور مشابه، جدول vendor یک رابطه یک-به-یک با جدول auth_user خواهد داشت. این به شما امکان میدهد تا از طریق نمونههای مدلهای Customer و Vendor به فیلدهای استاندارد User (مانند username، email، password) دسترسی داشته باشید.
مزایای وراثت چند-جدولی
- رابطه واضح "is-a": یک رابطه سلسله مراتبی واضح بین مدلها را نشان میدهد.
- چندریختی (Polymorphism): به شما امکان میدهد تا با نمونههای مدلهای فرزند مختلف به عنوان نمونههایی از مدل والد رفتار کنید. شما میتوانید به تمام اشیاء `User` کوئری بزنید و نتایجی شامل نمونههای `Customer` و `Vendor` دریافت کنید.
- یکپارچگی دادهها: یکپارچگی ارجاعی بین جداول فرزند و والد را از طریق رابطه یک-به-یک تضمین میکند.
معایب وراثت چند-جدولی
- افزایش پیچیدگی پایگاه داده: جداول بیشتری در پایگاه داده ایجاد میکند که میتواند پیچیدگی را افزایش داده و به طور بالقوه سرعت کوئریها را کاهش دهد.
- سربار عملکرد: کوئری زدن به دادههایی که در چندین جدول پخش شدهاند میتواند کارایی کمتری نسبت به کوئری زدن به یک جدول واحد داشته باشد.
- پتانسیل دادههای تکراری: اگر دقت نکنید، ممکن است دادههای یکسانی را در چندین جدول ذخیره کنید.
مدلهای پراکسی (Proxy)
اگرچه مدلهای پراکسی دقیقاً مانند کلاسهای پایه انتزاعی و وراثت چند-جدولی یک نوع وراثت مدل نیستند، اما ذکر آنها در این زمینه ارزشمند است. یک مدل پراکسی به شما امکان میدهد رفتار یک مدل را بدون تغییر جدول پایگاه داده آن تغییر دهید. شما یک مدل پراکسی را با تنظیم proxy = True در کلاس Meta مدل تعریف میکنید.
چه زمانی از مدلهای پراکسی استفاده کنیم؟
مدلهای پراکسی زمانی مفید هستند که شما بخواهید:
- متدهای سفارشی به یک مدل اضافه کنید: بدون تغییر فیلدها یا روابط مدل.
- ترتیب پیشفرض یک مدل را تغییر دهید: برای نماها یا زمینههای خاص.
- یک مدل را با یک اپ جنگوی متفاوت مدیریت کنید: در حالی که جدول پایگاه داده زیربنایی در اپ اصلی باقی میماند.
مثالی از مدل پراکسی
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
def __str__(self):
return self.title
class PublishedArticle(Article):
class Meta:
proxy = True
ordering = ['-title']
def get_absolute_url(self):
return f'/articles/{self.pk}/'
در این مثال، PublishedArticle یک مدل پراکسی برای Article است. این مدل از همان جدول پایگاه داده Article استفاده میکند اما ترتیب پیشفرض متفاوتی دارد (ordering = ['-title']) و یک متد سفارشی (get_absolute_url) اضافه میکند. هیچ جدول جدیدی ایجاد نمیشود.
انتخاب نوع صحیح وراثت
جدول زیر تفاوتهای کلیدی بین کلاسهای پایه انتزاعی و وراثت چند-جدولی را خلاصه میکند:
| ویژگی | کلاسهای پایه انتزاعی | وراثت چند-جدولی |
|---|---|---|
| جدول پایگاه داده | بدون جدول جداگانه | جدول جداگانه |
| کوئری زدن | نمیتوان مستقیماً کوئری زد | میتوان از طریق مدل والد کوئری زد |
| رابطه | بدون رابطه صریح | رابطه یک-به-یک |
| موارد استفاده | به اشتراکگذاری فیلدها و متدهای مشترک | ایجاد مدلهای تخصصی با رابطه "is-a" |
| عملکرد | عموماً برای وراثت ساده سریعتر است | به دلیل joinها میتواند کندتر باشد |
در اینجا یک راهنمای تصمیمگیری برای کمک به شما در انتخاب نوع صحیح وراثت آورده شده است:
- آیا نیاز به کوئری زدن مستقیم به کلاس پایه دارید؟ اگر بله، از وراثت چند-جدولی استفاده کنید. اگر نه، کلاسهای پایه انتزاعی را در نظر بگیرید.
- آیا در حال ایجاد مدلهای تخصصی با رابطه واضح "is-a" هستید؟ اگر بله، از وراثت چند-جدولی استفاده کنید.
- آیا عمدتاً به اشتراکگذاری فیلدها و متدهای مشترک نیاز دارید؟ اگر بله، از کلاسهای پایه انتزاعی استفاده کنید.
- آیا نگران پیچیدگی پایگاه داده و سربار عملکرد هستید؟ اگر بله، کلاسهای پایه انتزاعی را ترجیح دهید.
بهترین شیوهها برای وراثت مدل
در اینجا چند رویه برتر برای دنبال کردن هنگام استفاده از وراثت مدل در جنگو آورده شده است:
- سلسله مراتب وراثت را کمعمق نگه دارید: سلسله مراتب وراثت عمیق میتواند درک و نگهداری را دشوار کند. تعداد سطوح در سلسله مراتب وراثت خود را محدود کنید.
- از نامهای معنادار استفاده کنید: نامهای توصیفی برای مدلها و فیلدهای خود انتخاب کنید تا خوانایی کد را بهبود بخشید.
- مدلهای خود را مستند کنید: برای توضیح هدف و رفتار مدلهای خود، docstring به آنها اضافه کنید.
- مدلهای خود را به طور کامل آزمایش کنید: تستهای واحد بنویسید تا اطمینان حاصل کنید که مدلهای شما همانطور که انتظار میرود رفتار میکنند.
- استفاده از میکسینها را در نظر بگیرید: میکسینها کلاسهایی هستند که عملکرد قابل استفاده مجدد را فراهم میکنند که میتوان به چندین مدل اضافه کرد. آنها میتوانند در برخی موارد جایگزین خوبی برای وراثت باشند. میکسین کلاسی است که عملکردی را برای به ارث بردن توسط کلاسهای دیگر فراهم میکند. این یک کلاس پایه نیست، بلکه یک ماژول است که رفتار خاصی را ارائه میدهد. برای مثال، میتوانید یک `LoggableMixin` برای ثبت خودکار تغییرات در یک مدل ایجاد کنید.
- به عملکرد پایگاه داده توجه داشته باشید: از ابزارهایی مانند Django Debug Toolbar برای تجزیه و تحلیل عملکرد کوئریها و شناسایی گلوگاههای احتمالی استفاده کنید.
- نرمالسازی پایگاه داده را در نظر بگیرید: از ذخیره دادههای یکسان در مکانهای مختلف خودداری کنید. نرمالسازی پایگاه داده تکنیکی است که برای کاهش افزونگی و بهبود یکپارچگی دادهها با سازماندهی دادهها در جداول به گونهای استفاده میشود که محدودیتهای یکپارچگی پایگاه داده به درستی وابستگیها را اعمال کنند.
مثالهای عملی از سراسر جهان
در اینجا چند نمونه جهانی برای نشان دادن استفاده از وراثت مدل در برنامههای مختلف آورده شده است:
- پلتفرم تجارت الکترونیک (جهانی):
- وراثت چند-جدولی میتواند برای مدلسازی انواع مختلف محصولات (مانند PhysicalProduct، DigitalProduct، Service) استفاده شود. هر نوع محصول میتواند ویژگیهای خاص خود را داشته باشد در حالی که ویژگیهای مشترکی مانند نام، توضیحات و قیمت را از یک مدل پایه Product به ارث میبرد. این به ویژه برای تجارت الکترونیک بینالمللی مفید است، جایی که تنوع محصولات به دلیل مقررات یا لجستیک نیاز به مدلهای متمایز دارد.
- کلاسهای پایه انتزاعی میتوانند برای افزودن فیلدهای مشترکی مانند 'shipping_weight' و 'dimensions' به تمام محصولات فیزیکی، یا 'download_link' و 'file_size' به تمام محصولات دیجیتال استفاده شوند.
- سیستم مدیریت املاک و مستغلات (بینالمللی):
- وراثت چند-جدولی میتواند انواع مختلف املاک (مانند ResidentialProperty، CommercialProperty، Land) را مدلسازی کند. هر نوع میتواند فیلدهای منحصر به فردی مانند 'number_of_bedrooms' برای املاک مسکونی یا 'floor_area_ratio' برای املاک تجاری داشته باشد، در حالی که فیلدهای مشترکی مانند 'address' و 'price' را از یک مدل پایه Property به ارث میبرد.
- کلاسهای پایه انتزاعی میتوانند فیلدهای مشترکی مانند 'listing_date' و 'available_date' را برای پیگیری در دسترس بودن ملک اضافه کنند.
- پلتفرم آموزشی (جهانی):
- وراثت چند-جدولی میتواند انواع مختلف دورهها (مانند OnlineCourse، InPersonCourse، Workshop) را نمایندگی کند. دورههای آنلاین ممکن است ویژگیهایی مانند 'video_url' و 'duration' داشته باشند، در حالی که دورههای حضوری ممکن است ویژگیهایی مانند 'location' و 'schedule' داشته باشند و ویژگیهای مشترکی مانند 'title' و 'description' را از یک مدل پایه Course به ارث ببرند. این در سیستمهای آموزشی متنوع در سطح جهان که روشهای ارائه متفاوتی دارند، مفید است.
- کلاسهای پایه انتزاعی میتوانند فیلدهای مشترکی مانند 'difficulty_level' و 'language' را برای اطمینان از سازگاری در تمام دورهها اضافه کنند.
نتیجهگیری
وراثت مدل در جنگو ابزاری قدرتمند برای ساخت اسکیمای پایگاه داده با ساختار خوب و قابل نگهداری است. با درک تفاوتهای بین کلاسهای پایه انتزاعی و وراثت چند-جدولی، میتوانید رویکرد مناسب برای مورد استفاده خاص خود را انتخاب کنید. به یاد داشته باشید که هنگام تصمیمگیری، مصالحههای بین قابلیت استفاده مجدد کد، پیچیدگی پایگاه داده و سربار عملکرد را در نظر بگیرید. پیروی از بهترین شیوههای ذکر شده در این مقاله به شما کمک میکند تا برنامههای جنگوی کارآمد و مقیاسپذیر ایجاد کنید.