رابطه‌ی Many-to-Many


در مدل‌های رابطه‌ای داده‌ها، رابطه چند به چند (Many-to-Many) زمانی استفاده می‌شود که هر رکورد از جدول A بتواند با چندین رکورد از جدول B مرتبط باشد و برعکس. این نوع رابطه در جنگو با استفاده از فیلد ManyToManyField پیاده‌سازی می‌شود.

یکی از رایج‌ترین سناریوهای استفاده از ManyToManyField در پروژه‌های جنگو، برچسب‌گذاری (tagging) است. در مدلی که تعریف نمودیم، هر پروژه می‌تواند دارای چندین برچسب باشد (مانند «Django»، «JavaScript»، «Python») و هر برچسب نیز می‌تواند به چندین پروژه تعلق داشته باشد. در این حالت، رابطه بین مدل Project و مدل Tag به‌وضوح از نوع چند به چند است.

class Project(models.Model):
    ...
    tags = models.ManyToManyField(Tag, related_name='projects')
    ...

این رابطه کاملا منطقی و کاربردی خواهد بود چرا که یک در یک پروژه می‌تواند هم «Django» استفاده گردد و هم «JavaScript»، و در عین حال، برچسب «Python» می‌تواند به ده‌ها پروژه دیگر نیز اختصاص داده شود.

رابطه چند به چند در جنگو، امکان مدل‌سازی انعطاف‌پذیر و واقع‌گرایانه‌ای را فراهم می‌کند. با استفاده از ManyToManyField، می‌توان به‌راحتی ارتباطات پیچیده بین موجودیت‌ها را مدیریت کرد و از قابلیت‌های پیشرفته ORM جنگو — از جمله دسترسی معکوس، فیلتر کردن بر اساس روابط، و افزودن/حذف برچسب‌ها — بهره برد، بدون نیاز به مدیریت دستی جدول واسط (junction table).


✺✳ دسترسی معکوس (Reverse Access) ✳✺ 

⮜ دسترسی به پروژه‌های دارای یک برچسب


tag = Tag.objects.get(name="ِDjango")

# Method 1: If related_name is not set (Django default)
projects = tag.project_set.all()

# Method 2: When related_name is set to "projects" (recommended)
projects = tag.projects.all()

⚠️ اگر در تعریف ManyToManyField از پارامتر related_name استفاده نموده باشیم، نباید از نام پیش‌فرض (modelname_set) — جنگو به‌صورت پیش‌فرض، از نام مدل به صورت کوچک‌شده بهره می‌برد — استفاده کنیم. در غیر این صورت با خطای AttributeError مواجه خواهیم شد.

 

⮜ دریافت تمام برچسب‌های مرتبط با یک پروژه خاص


project = Project.objects.get(id="ac260bde-5f13-4744-9f23-9052420573a7")
tags = project.tags.all()

 

✺✳ فیلتر کردن بر اساس روابط (Lookups across relationships) ✳✺ 

جنگو اجازه می‌دهد تا با استفاده از دو زیرخط  (__)، داده‌ها را بر اساس فیلدهای مدل‌های مرتبط جستجو نمود.

 

⮜ فیلتر کردن پروژه‌ها بر اساس برچسب 


projects = Project.objects.filter(tags__name="Python")
projects = Project.objects.filter(tags__name__icontains="java")

— دریافت تمام پروژه‌هایی که دارای یک برچسب خاص هستند

⮜ فیلتر کردن برچسب‌ها بر اساس پروژه


tags = Tag.objects.filter(projects__area="Sport")
tags = Tag.objects.filter(projects__title__icontains="AI").distinct()

 — پیدا کردن تمام برچسب‌هایی که به پروژه‌های خاصی مرتبط هستند

⚠️این کوئری ممکن است برچسب‌ها را تکراری نشان دهد اگر به چند پروژه مرتبط باشند. برای جلوگیری از تکرار، می‌بایست از .distinct() استفاده کنیم

 

📌 اضافه/حذف کردن رابطه: