روابط مدل‌ها


در دنیای پایگاه‌داده‌ها و مدل‌سازی داده، یکی از مهم‌ترین اصول طراحی، جلوگیری از تکرار غیرضروری داده‌ها و ایجاد روابط معنادار بین موجودیت‌ها است — و دقیقاً همین جاست که روابط بین مدل‌ها (Relationships) به کمک فیلدهای رابطه‌ای در جنگو نقش حیاتی ایفا می‌کنند. این فیلدها — شامل ForeignKey، OneToOneField و ManyToManyField — اجازه می‌دهند تا مدل‌های مختلف را به یکدیگر متصل نمود و ساختاری منطقی، پایدار و مقیاس‌پذیر ساخت. در پس‌زمینه، جنگو این روابط را با استفاده از کلیدهای خارجی (Foreign Key) در دیتابیس پیاده‌سازی می‌کند — یعنی در مدل فرزند، ستونی ایجاد می‌شود که به id رکورد مرتبط در مدل والد اشاره می‌کند — یا در موارد رابطه چند-به-چند، یک جدول واسط (Intermediate Table) به‌صورت خودکار ساخته می‌شود که جفت‌های مرتبط را نگه می‌دارد. هدف نهایی این است که داده‌ها فقط در یک مکان ذخیره شوند و هر جا به آن‌ها نیاز بود، از طریق رابطه به آن‌ها دسترسی پیدا کرد — نه با کپی‌کردن و تکرار. این رویکرد نه‌تنها حجم دیتابیس را کاهش می‌دهد، بلکه یکپارچگی داده‌ها (Data Integrity) را تضمین می‌کند. بعنوان مثال، اگر نام یک نویسنده تغییر کند، به‌جای ویرایش صدها مقاله، فقط یک رکورد در جدول نویسندگان به‌روز می‌شود و تمام مقالات مرتبط به‌طور خودکار این تغییر را منعکس می‌کنند. بدون این روابط، مجبور خواهیم بود اطلاعات را در چندین جا تکرار کنیم — که علاوه بر هدر رفت فضا، خطاهای انسانی، ناسازگاری داده‌ها و سختی در نگهداری سیستم نیز ایجاد می‌شد. بنابراین، فیلدهای رابطه‌ای تنها یک ابزار فنی نیستند، بلکه پایه‌ای اساسی برای طراحی هوشمندانه و حرفه‌ای سیستم‌های نرم‌افزاری هستند که کمک می‌کنند داده‌ها را به‌صورت ساختاریافته، منعطف و بدون افزونگی مدیریت نمود.

رابطه یک به چند - ForeignKey


در این نوع رابطه، یک رکورد از مدل اول می‌تواند با چندین رکورد در مدل دوم مرتبط باشد اما هر رکورد در مدل دوم تنها می‌تواند به یک رکورد در مدل اول مرتبط باشد.. برای مثال یک پروژه در داخل وب‌سایت می‌تواند شامل چندین نظر و بازخورد باشد، ولی هر نظر و یا بازخورد تنها می‌تواند در خصوص یک پروژه باشد. در این صورت، رابطه یک به چند یا OneToMany مطرح خواهد بود. باید توجه داشت که به این رابطه چند به یک یا ManyToOne نیز گفته می‌شود و بستگی به این خواهد داشت که از کدام مدل برای مرجع قرار دادن استفاده کنیم.

در واقع فرآیندی که در سمت پایگاه داده اتفاق می­افتد به این صورت می­باشد که یک فیلد parent_id در زمان تعریف مدل شامل فیلد OneToMany بصورت خودکار به مدل اضافه می‌شود.


برای درک بهتر این موضوع، با این فرض پیش می‌رویم که یک مدل project شامل اطلاعات پروژه­ها و یک مدل review شامل بازخورد و نظرات، در خصوص پروژه‌ها خواهیم داشت که کاربران به بیان نظرات خود در خصوص پروژه­ها اقدام نموده­اند. به بیان دیگر، هر رکورد - One - از مدل project می‌تواند چندین رکورد - Many - از نظرات کاربران در مدل review را داشته باشد.

 

برای استفاده از رابطه OneToMany باید از فیلد ForeignKey استفاده گردد این فیلد در مدل review بصورت رابطه چند به یک (ManyToOne) خواهد ساخت!


نکته: در جنگو، related_name یک ویژگی (attribute) است که می‌توان هنگام تعریف یک ارتباط ForeignKey (یا دیگر انواع روابط) برای تعیین نام دسترسی از سمت مدل مرتبط استفاده نمود و امکان ساده‌تر شدن دسترسی به داده‌های مرتبط، جلوگیری از تداخل نام‌ها و افزایش خوانایی کد را فراهم می‌آورد.


نکته: جنگو برای اعمال تغییرات و یا ایجاد مدل‌های جدید مطابق با فیلدهای تعریف شده در پایگاه داده، نیاز به اجرای دستورات makemigrations و سپس migrate خواهد داشت.

نکته: برای نمایش هر مدل جدید تعربف شده در اینترفیس ادمین می­بایست آن را در فایل admin.py ثبت کنیم.

رابطه یک به یک - OneToOne


در این نوع رابطه یک رکورد از یک مدل می‌تواند فقط با یک رکورد از مدل دیگر مرتبط باشد. برای مثال یک کاربر فقط می‌تواند یک پروفایل داشته باشد و همینطور یک ‌پروفایل نیز فقط متعلق به یک کاربر است.

برای استفاده از رابطه one-to-one در مدل‌های جنگو باید از گزینه OneToOneField برای فیلد استفاده نمود تا بدین صورت رابطه یک به یک(one-to-one) را تعریف کرد. برای درک بهتر، مدلی را فرض می‌گیریم که نام شرکت­های خودرو سازی را یدک می­کشد و همچنین مدل دیگری که مدیرعامل شرکت­ها را شامل می‌شود. این دو مدل مفهوم فیلد OneToOne را ایجاد خواهند کرد چرا که:

- یک شرکت خودروسازی تنها می‌تواند یک مدیرعامل داشته باشد.


- یک نفر می‌تواند تنها در یک شرکت خودروسازی به عنوان میدعامل مشغول به کار شود.

فیلد company در مدل ceo بصورت OneToOne به مدل company مرتبط شده است. بدین صورت از طریق فیلد company به تمامی اطلاعات مدل company دسترسی خواهد داشت. همچنین در مدل company، از طریق مدل ceo به تمامی فیلدهای آن دسترسی خواهیم داشت.

حال با فرض داشتن داده­های دو مدل به­صورت ذیل، می‌توان جستجوی رکوردها کوئری - را انجام داد


با کوئری از سمت مدل company:


و با کوئری از سمت مدل ceo:

رابطه چند به چند - ManyToMany



در این نوع رابطه چند رکورد از یک مدل می‌تواند با چندین رکورد از مدل دیگر مرتبط باشند. برای مثال یک پروژه در وب‌سایت بر مبنای بستر پیاده‌سازی آن پروژه، می‌تواند چندین برچسب یا تگ از جمله Python، React و ... داشته باشد و همینطور یک برچسب نیز می‌تواند متعلق به چندین پروژه باشد.


در واقع برای این نوع رابطه، در سمت پایگاه داده، فرآیندی که اتفاق می­افتد به این صورت می­باشد که یک جدول میانی توسط جنگو هنگام تعریف گزینه ManyToMany به­صورت خودکار ایجاد شده و هربار که یک تگ به یک پروژه اختصاص می­یابد، جنگو یک رکورد به جدول میانی از رابطه ایجاد شده اضافه می‌کند.

برای استفاده از رابطه ManyToMany در مدل‌های جنگو باید از فیلد ManyToManyField استفاده کرد و این فیلد رابطه چند به چند را خواهد ساخت، چون خصوصیت تگ در مدل پروژه وجود دارد، ما این فیلد را در مدل projects قرار خواهیم داد.


پس از ایجاد مدل tag، حال می­بایست نسبت به تعریف فیلد ManyToMany در مدل projects اقدام کنیم

نکته: ذکر این نکته حائز اهمیت می­باشد که بعد از ایجاد و یا انجام هر تغییری در ساختار مدل­ها، می­بایست دستورات makemigrations و سپس migrate را اجرا کنیم تا تغییرات در پایگاه داده نیز اعمال شوند؛ و همچنین بعد از ایجاد هر مدل، می­بایست نسبت به ثبت آن در اینترفیس ادمین از مسیر فایل admin.py از داخل دایرکتوری اپ اقدام کرد:


coreapp/admin.py

حال که تمامی مراحل فرایند ایجاد، تغییر و ثبت مدل­ها را طی کردیم، نگاهی به نحوه عملکرد فیلد ManyToMany تعریف شده در مدل projects خواهیم انداخت. قبل از انجام آن می­بایست چند آیتم در جدول tag اضافه کنیم تا درک بهتری از نحوه عملکرد داشته باشیم.

در اینجا لیستی از تگ­ها به جدول tag اضافه کردیم. حال اگر به سراغ آیتم­های مدل projects برویم، فیلد tags ایجاد شده به این صورت خواهد بود.