هنگامی که شما در حال ساختن چیزی در جنگو هستید-خواه این یک وبلاگ باشد ، یک برنامه انجام یا حتی چیزی پیچیده تر-در بعضی مواقع ، می خواهید داده های مختلفی را به هم وصل کنید.

این جایی است که ForeignKey وارد می شود. این به پیوند یک مدل به مدل دیگر کمک می کند ، مانند اتصال یک نظر به یک پست یا سفارش به مشتری.

این یکی از این موارد در جنگو است که در ابتدا می تواند گیج کننده به نظر برسد ، اما پس از کلیک ، تعجب خواهید کرد که چگونه برنامه های خود را بدون آن ساخته اید.

بنابراین بیایید همه آن را خراب کنیم. من شما را از طریق همه چیز از آنچه که یک فرد خارجی است ، تا روش استفاده از آن در پروژه Django خود قدم می زنم.

این چیزی است که ما پوشش خواهیم داد:

  • این چیزی است که ما پوشش خواهیم داد:

  • کلید خارجی در جنگو چیست؟

  • چرا به جای ذخیره سازی شناسه به صورت دستی ، از یک کلید خارجی استفاده می کنید؟

  • مثال در دنیای واقعی: پست ها و نظرات وبلاگ

  • on_delete چیست و چرا اهمیت دارد؟

  • روش دسترسی به اشیاء مرتبط در جنگو

  • روش ایجاد روابط کلیدی خارجی در مدیر Django

    • در پایگاه داده چه اتفاقی می افتد؟
  • روش پرس و جو با Freetkey

    • همه نظرات را برای یک پست با ID = 1 دریافت کنید:

    • تمام پست هایی را که حداقل یک نظر توسط یک کاربر خاص دارند دریافت کنید:

  • متداول

    • آیا یک کلید خارجی می تواند اختیاری باشد؟

    • آیا یک کلید خارجی می تواند به همان مدل (خود) اشاره کند؟

    • آیا یک مدل می تواند بیش از یک کلید خارجی داشته باشد؟

  • افکار نهایی

    • منابع بیشتر

کلید خارجی در جنگو چیست؟

به ساده ترین اصطلاح ، یک کلید خارجی در جنگو بین دو مدل رابطه ای به یک ایجاد می کند. این بدان معناست که بسیاری از ردیف ها در یک جدول می توانند مربوط به یک ردیف واحد در دیگری باشند.

به عنوان مثال:

  • یک پست وبلاگ می تواند داشته باشد بسیاری از نظرات

  • یک مشتری می تواند داشته باشد بسیاری از سفارشات

  • یک نویسنده می تواند بنویسد کتابهای زیادی

اگر از پس زمینه صفحه گسترده می آیید ، مانند پیوند دو صفحه با استفاده از یک ستون مشترک ، به آن فکر کنید. در جنگو ، این کار را در تعاریف مدل خود انجام می دهید.

چرا به جای ذخیره سازی شناسه به صورت دستی ، از یک کلید خارجی استفاده می کنید؟

ممکن است تعجب کنید ، “چرا فقط شناسه شیء مرتبط را در یک قسمت عدد صحیح ساده ذخیره نکنید؟”

خوب ، شما می توانستید – اما شما یک تن قدرت از دست می دهید. بدون کلید خارجی:

  • شما اعتبار سنجی خودکار دریافت نمی کنید که شیء مربوطه وجود دارد.

  • شما نمی توانید به راحتی در نمایش داده ها روابط را دنبال کنید (به عنوان مثال ، post.comments.all() امکان پذیر نخواهد بود)

  • مدیر Django نمی تواند کشویی یا فرم های درون خطی را برای داده های مرتبط ارائه دهد.

  • شما از دست می دهید روی ویژگی های مفید مانند on_delete رفتار و نامگذاری شیء مرتبط.

زمینه های خارجی این روابط را به صورت خودکار و اجرای آن انجام می دهند و باعث می شوند کد شما تمیزتر ، ایمن تر و حفظ آن آسان تر شود.

مثال در دنیای واقعی: پست ها و نظرات وبلاگ

بیایید بگوییم که در حال ساختن یک وبلاگ هستید. احتمالاً شما Post مدل و الف Comment مدل. هر نظر باید با یک پست خاص مرتبط باشد.

در اینجا چگونه به نظر می رسد در کد:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    published_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    author = models.CharField(max_length=100)
    text = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'Comment by {self.author}'

بگذارید هر قسمت از آن را توضیح دهم:

  • models.ForeignKey(Post, on_delete=models.CASCADE): این خط اتصال را ایجاد می کند. این بدان معناست که هر نظر به یک پست مرتبط است. در on_delete=models.CASCADE در صورت حذف یک پست ، قسمت به Django می گوید که تمام نظرات مرتبط را حذف کند.

  • __str__ روشها فقط خواندن چیزها را در سرپرست یا پوسته آسانتر می کند.

چیست on_delete و چرا مهم است؟

هنگامی که شما یک کلید خارجی را در جنگو ایجاد می کنید ، باید شامل یک on_delete بحث اگر ردیف والدین (مانند پست وبلاگ) حذف شود ، این اتفاق برای ردیف کودک (مانند نظرات) می افتد.

در اینجا گزینه های مشترک وجود دارد:

  • models.CASCADE: ردیف های کودک را نیز حذف کنید (مانند حذف همه نظرات هنگام حذف یک پست).

  • models.PROTECT: در صورت وجود اشیاء مرتبط ، از حذف جلوگیری کنید.

  • models.SET_NULL: reperialkey را روی آن قرار دهید NULL به جای حذف

  • models.SET_DEFAULT: یک مقدار پیش فرض را تنظیم کنید.

  • models.DO_NOTHING: هیچ کاری انجام ندهید (توصیه نمی شود مگر اینکه واقعاً بدانید چه کاری انجام می دهید).

من معمولاً با CASCADE برای برنامه های ساده ، اما ارزش آن را دارد که از طریق آن فکر کنید روی وضعیت

پس از راه اندازی FreatireKey ، Django چند ابزار خوب برای کار با داده های مرتبط به شما می دهد.

به عنوان مثال ، بیایید بگوییم که شما یک شیء پست دارید:

post = Post.objects.get(id=1)

می توانید مانند این همه نظرات را برای آن پست دریافت کنید:

comments = post.comment_set.all()

در comment_set به طور خودکار توسط Django ایجاد می شود ، و می توانید نام را با آن سفارشی کنید related_name:

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')

اکنون می توانید انجام دهید:

post.comments.all()

خیلی تمیزتر ، درست است؟

روش ایجاد روابط کلیدی خارجی در مدیر Django

مدیر Django به خوبی از افراد خارجی برخورد می کند. اگر هر دو را دارید Post وت Comment مدلهای ثبت شده در admin.pyبرای انتخاب پستی که متعلق به آن است ، در فرم نظر یک کشویی دریافت خواهید کرد.

همچنین می توانید فرم های درون خطی بسازید ، بنابراین می توانید هنگام ویرایش یک پست ، نظرات را اضافه کنید. در اینجا یک مثال سریع وجود دارد:

from django.contrib import admin
from .models import Post, Comment

class CommentInline(admin.TabularInline):
    model = Comment
    extra = 1

class PostAdmin(admin.ModelAdmin):
    inlines = [CommentInline]

admin.site.register(Post, PostAdmin)
admin.site.register(Comment)

اکنون وقتی در حال ویرایش یک پست هستید ، می توانید نظرات را در آنجا اضافه یا ویرایش کنید روی یکسان pageبشر

در پایگاه داده چه اتفاقی می افتد؟

Django از یک پایگاه داده رابطه ای (مانند PostgresQL ، MySQL یا SQLite) استفاده می کند و ExternateKey ستونی را در جدول پایگاه داده ایجاد می کند که دارای شناسه شیء مرتبط است.

اگر دویدید python manage.py makemigrations و بعد python manage.py migrate، Django جداول پایگاه داده واقعی را با روابط مناسب در پشت صحنه ایجاد می کند.

روش پرس و جو با Freetkey

همچنین می توانید مبتنی بر فیلتر یا جستجو کنید روی روابط خارجی:

همه نظرات را برای یک پست با ID = 1 دریافت کنید:

Comment.objects.filter(post_id=1)

یا با استفاده از شیء پست:

post = Post.objects.get(id=1)
comments = Comment.objects.filter(post=post)

تمام پست هایی را که حداقل یک نظر توسط یک کاربر خاص دارند دریافت کنید:

Post.objects.filter(comments__author='John')

این که comments__author قسمت به لطف related_name="comments" من زودتر اضافه کردم

متداول

آیا یک کلید خارجی می تواند اختیاری باشد؟

بله ، فقط اضافه کنید null=True, blank=True مثل این:

post = models.ForeignKey(Post, on_delete=models.SET_NULL, null=True, blank=True)

اگر همیشه شیء مرتبط لازم نباشد ، ممکن است این را بخواهید. به عنوان مثال ، الف Comment قدرت در صورت اختیاری متعلق به یک Post، یا الف Task ممکن است به صورت اختیاری دارای یک مرتبط باشد Projectبشر هنگام ساختن پیش نویس ، حذف نرم یا رسیدگی به داده های میراث مفید است.

آیا یک کلید خارجی می تواند به همان مدل (خود) اشاره کند؟

کاملا به آن یک کلید خارجی خود ارجاعی گفته می شود ، که اغلب برای مواردی مانند نظرات یا دسته بندی های موضوعی استفاده می شود.

class Category(models.Model):
    name = models.CharField(max_length=100)
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL)

آیا یک مدل می تواند بیش از یک کلید خارجی داشته باشد؟

کاملا. به عنوان مثال ، یک مدل سفارش می تواند یک کلید خارجی را برای مشتری و دیگری به حمل و نقل ارسال کند.

افکار نهایی

اگر در جنگو در حال ساختن هر چیزی هستید که بیش از یک مدل را سروکار دارد ، درک UneferneyKey ضروری است. این برنامه شما را ساختار یافته تر ، پرس و جو تر و قدرتمندتر می کند.

در ابتدا ، ممکن است احساس زیادی کند ، اما پس از ایجاد یک یا دو رابطه و دیدن همه آن در مدیر و نماهای خود ، کلیک می کند.

و اگر چیزی هنوز مشخص نیست ، طبیعی است. من قبل از شروع احساس طبیعی مجبور شدم چند مینی پروژه بسازم.

منابع بیشتر

  • اسناد Django روی شخص خارجی

  • مرجع میدانی مدل Django

  • نوشتن مدل ها در جنگو

  • اسناد مدیر Django