~2 دقیقه مطالعه • بروزرسانی ۱۹ اسفند ۱۴۰۴
۱. تعریف رابطهٔ چندبهیک در Django
برای تعریف رابطهٔ many‑to‑one از ForeignKey استفاده میکنیم.
در مثال زیر، یک Reporter میتواند چندین Article داشته باشد، اما هر Article فقط یک Reporter دارد.
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
۲. ایجاد دادهها
ایجاد Reporter:
r = Reporter(first_name="John", last_name="Smith", email="[email protected]")
r.save()
r2 = Reporter(first_name="Paul", last_name="Jones", email="[email protected]")
r2.save()
ایجاد Article:
from datetime import date
a = Article(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
a.save()
دسترسی به Reporter مرتبط:
a.reporter
a.reporter.id
ForeignKey نیاز به آبجکت ذخیرهشده دارد
اگر Reporter ذخیره نشده باشد، خطا میدهد:
r3 = Reporter(first_name="John", last_name="Smith", email="[email protected]")
Article.objects.create(..., reporter=r3) # ValueError
۳. دسترسی معکوس: Reporter → Article
Django بهصورت خودکار یک مدیر معکوس به نام article_set ایجاد میکند:
r.article_set.all()
ایجاد Article از سمت Reporter:
new_article = r.article_set.create(
headline="John's second story",
pub_date=date(2005, 7, 29)
)
۴. جابهجایی Article بین Reporterها
میتوان Article را به Reporter دیگر منتقل کرد:
r2.article_set.add(new_article2)
new_article2.reporter # اکنون Paul Jones
افزودن نوع اشتباه خطا میدهد:
r.article_set.add(r2) # TypeError
۵. کوئریزدن روی رابطهٔ ForeignKey
فیلتر روی فیلدهای Reporter:
Article.objects.filter(reporter__first_name="John")
Article.objects.filter(reporter__first_name="John", reporter__last_name="Smith")
فیلتر با pk یا آبجکت:
Article.objects.filter(reporter__pk=1)
Article.objects.filter(reporter=1)
Article.objects.filter(reporter=r)
استفاده از لیست یا queryset:
Article.objects.filter(reporter__in=[r, r2]).distinct()
Article.objects.filter(
reporter__in=Reporter.objects.filter(first_name="John")
).distinct()
۶. کوئری از سمت معکوس (Article → Reporter)
Reporter.objects.filter(article__pk=1)
Reporter.objects.filter(article=a)
Reporter.objects.filter(article__headline__startswith="This").distinct()
count با distinct:
Reporter.objects.filter(article__headline__startswith="This").count()
Reporter.objects.filter(article__headline__startswith="This").distinct().count()
۷. کوئریهای حلقهای (Circular Queries)
میتوان lookupها را بینهایت زنجیره کرد:
Reporter.objects.filter(article__reporter__first_name__startswith="John").distinct()
۸. رفتار حذف (CASCADE)
چون on_delete=models.CASCADE استفاده شده، حذف Reporter باعث حذف Articleهای او میشود:
r2.delete()
Article.objects.all() # مقالات مربوط به r2 حذف شدهاند
حذف با JOIN:
Reporter.objects.filter(article__headline__startswith="This").delete()
Reporter.objects.all() # خالی
Article.objects.all() # خالی
جمعبندی
رابطهٔ چندبهیک در Django ساده اما بسیار قدرتمند است.
با استفاده از ForeignKey میتوان بهراحتی بین آبجکتهای مرتبط حرکت کرد، از هر دو سمت رابطه داده ایجاد کرد، رابطهها را جابهجا کرد، و کوئریهای پیچیده نوشت.
Django با ایجاد مدیرهای معکوس و lookupهای قابلگسترش، کار با دادههای رابطهای را بسیار روان و کارآمد میکند.
نوشته و پژوهش شده توسط دکتر شاهین صیامی