محتويات الدورة

Django / سير تطبيق موثوق / الدرس 7

استعلامات ORM وتحميل العلاقات

ابن استعلامات محدودة وافهم التقييم الكسول واختر تحميل العلاقات بحسب الرد الفعلي.

وقت القراءة التقريبي: 3 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • تصف QuerySet العمل قبل تقييمه
  • تحميل العلاقة المفردة بـselect_related
  • فصل صحة الاستعلام عن سهولته

تصف QuerySet العمل قبل تقييمه

تصف QuerySet استعلاما قابلا للتركيب ولا يجلب كل ربط فورا. يحدث التقييم بالتكرار أو التحويل وقد تخزن النسخة نتائجها وفق القواعد، ولا تشارك إعادة البناء مخزنها. حدد حاجتك للكائن والقيمة والوجود والعدد. قد تزيد exists ثم التكرار العمل إن كنت تحتاج الكائنات أصلا. وقد يكون فحص الوجود مفيدا إذا لم تحتج إلى الكائنات، لكنه قد يضيف استعلاما غير لازم إن كنت ستجلب المجموعة كاملة بعده مباشرة.

تحمل العلاقة التعدد وسياسة الحذف

تشير ForeignKey من الكثير للواحد وتختلف كلفة المتعدد والعكسي. حدد الاختيار والحذف؛ لا يعوض on_delete مراجعة القيود. استخدم AUTH_USER_MODEL للمستخدم المهيأ. تستعمل العينة Instructor صغيرا لعزل ORM دون المصادقة، ولا تقترح به هوية أو إذنا حقيقيين. كما أن اسم العلاقة لا يقرر سياسة الوصول أو معنى الحذف في المجال، ولا ينبغي استخدام علاقة تدريبية صغيرة بديلا عن هوية المستخدم الحقيقية.

تحميل العلاقة المفردة بـselect_related

ينشئ المثال جدولين في الذاكرة ومدربا ومقررين ويحمل العلاقة بالضم لتجنب بحث مستقل لكل مدرب. يثبت الترتيب الناتج ولا يدعي عددا عالميا مع كل مدير وعمل إضافي. احفظ مفاتيح المطابقة عند تقليل الأعمدة وافحص الاستعلام إذا قرأ القالب العلاقات؛ فقد يخفي الناتج الصغير عملا متكررا. وعند تقليل الأعمدة، يجب أن تبقى مفاتيح المطابقة التي يحتاجها الربط؛ وإلا فقد تتغير كلفة الوصول أو يفشل تكوين العلاقة المقصودة.

python مثال تنفيذي معزول
from django.conf import settings
settings.configure(
    SECRET_KEY="synthetic-course-key",
    USE_I18N=False, USE_TZ=True,
    INSTALLED_APPS=[],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    DEFAULT_AUTO_FIELD="django.db.models.AutoField",
    ALLOWED_HOSTS=["testserver"],
)
import django
django.setup()

from django.db import connection, models

class Instructor(models.Model):
    name = models.CharField(max_length=60)
    class Meta:
        app_label = "lab"

class Course(models.Model):
    title = models.CharField(max_length=100)
    instructor = models.ForeignKey(Instructor, on_delete=models.PROTECT)
    class Meta:
        app_label = "lab"

with connection.schema_editor() as editor:
    editor.create_model(Instructor)
    editor.create_model(Course)
mira = Instructor.objects.create(name="Mira")
Course.objects.create(title="Django", instructor=mira)
Course.objects.create(title="Python", instructor=mira)
rows = Course.objects.select_related("instructor").order_by("title")
print([(row.title, row.instructor.name) for row in rows])
الناتج المتوقع
[('Django', 'Mira'), ('Python', 'Mira')]

تستخدم العينة ضم علاقة مفردة ولا تنشئ جداول تطبيق معد.

التصفية والاختيار قبل الجلب

تختار العينة المنشور فقط قبل الجلب. قد تعطي تصفية قائمة Python الشكل نفسه بكلفة زائدة. طبق نطاق الرؤية ثم فوض العملية. يناسب select_related المفرد وتنفذ prefetch_related جلبا منفصلا وتجميعا للمجموعات، وقد يستنفد الإفراط الذاكرة. حد الجذر وحمّل الرسم المطلوب فقط. ويجب ألا يستبدل الإفراط في التحميل مشكلة الاستعلام لكل صف بتحميل عدد غير محدود من الكائنات المرتبطة التي لن تظهر في الرد.

python مثال تنفيذي معزول
from django.conf import settings
settings.configure(
    SECRET_KEY="synthetic-course-key",
    USE_I18N=False, USE_TZ=True,
    INSTALLED_APPS=[],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    DEFAULT_AUTO_FIELD="django.db.models.AutoField",
    ALLOWED_HOSTS=["testserver"],
)
import django
django.setup()

from django.db import connection, models

class Course(models.Model):
    title = models.CharField(max_length=100)
    published = models.BooleanField(default=False)
    class Meta:
        app_label = "lab"

with connection.schema_editor() as editor:
    editor.create_model(Course)
Course.objects.create(title="Django", published=True)
Course.objects.create(title="Draft", published=False)
print(list(Course.objects.filter(published=True).order_by("title", "pk").values_list("title", flat=True)))
الناتج المتوقع
['Django']

تستبعد القاعدة المسودة قبل تحويل النتائج لقائمة وتختار العناوين فقط.

فصل صحة الاستعلام عن سهولته

استخدم معاملات القيم وحدد أسماء الترتيب المسموحة. اجمع Q حتى لا تهرب OR من الوصول. قد يكرر الربط الصفوف والمجاميع فحدد وحدة التقرير قبل distinct. اختبر الفراغ والغياب والتكرار وعدة جذور وافحص الدليل. تقلل ORM التكرار ولا تضمن النطاق أو SQL الخام أو الخطة لكل توزيع ومحرك. كما أن ضم مجموعتين متعددتي العناصر قد يكرر صف الجذر، ولذلك يجب فهم وحدة النتيجة قبل إضافة distinct أو جمع عددي يبدو صحيحا لعينة بسيطة.

الأخطاء الشائعة وإصلاحها

ينفذ القالب استعلاما لكل مدرب

لماذا يحدث؟
تتكرر قراءة علاقة كسولة.
كيف تصلحه؟
حمّلها بـselect_related المناسب.
كيف تتجنب تكراره؟
اختبر عدة صفوف بالدليل.

تتجاوز OR النطاق

لماذا يحدث؟
لا يحفظ التجميع القيد.
كيف تصلحه؟
اجمع البدائل تحت الثابت.
كيف تتجنب تكراره؟
اختبر سجلات مستبعدة.

يزيد التحميل الذاكرة

لماذا يحدث؟
الجذور والعلاقات بلا حد.
كيف تصلحه؟
حدها وحمّل المطلوب.
كيف تتجنب تكراره؟
قس الصفوف والعدد معا.

اختبر فهمك

1. تحتاج القائمة اسم المدرب وعدد التسجيلات فقط؛ ماذا تحمل؟

اعرض الحل المشروح

حمّل علاقة المدرب واجمع عدد التسجيلات بدل كل كائن، وحد النطاق والجذور وافحص الاستعلام والعد مع التكرار والربط.

2. لماذا قد يسرب استعلام بمعاملات بيانات غيره؟

اعرض الحل المشروح

تحمي المعاملات بناء القيم لا قاعدة الوصول. قد يجلب بحث معرف غير مقيد موردا ممنوعا؛ قيد وفوض واختبر السالب.

أهم ما تعلمته

  • اعرف وقت تقييم الاستعلام.
  • اختر التحميل بشكل العلاقة والحاجة.
  • لا تعوض ORM التفويض والمراجعة.

المراجع الرسمية