python - كيف يمكنني الوصول إلى الفصول الفرعية من كائن في django دون معرفة اسم فئة الطفل؟




many-to-many (6)

في Django ، عندما يكون لديك فئة رئيسية وفئات فرعية متعددة ترث منها ، فإنك عادة ما تصل إلى طفل عبر parentclass.childclass1_set أو parentclass.childclass2_set ، ولكن ماذا لو لم أكن أعرف اسم فئة الطفل المحددة التي أريدها؟

هل هناك طريقة للحصول على الأشياء ذات الصلة في الأصل-> اتجاه الطفل دون معرفة اسم فئة الطفل؟



حل كارل هو حل جيد ، وإليك طريقة واحدة لإجراء ذلك يدويًا إذا كانت هناك فصول فرعية ذات صلة متعددة:

def get_children(self):
    rel_objs = self._meta.get_all_related_objects()
    return [getattr(self, x.get_accessor_name()) for x in rel_objs if x.model != type(self)]

ويستخدم وظيفة خارج نطاق _meta ، والتي لا يمكن ضمان استقرارها مع تطور django ، ولكنها تعمل على خدعة ويمكن استخدامها أثناء الطيران إذا لزم الأمر.


هنا هو الحل الخاص بي ، مرة أخرى يستخدم _meta لذلك لا يضمن أن تكون مستقرة.

class Animal(models.model):
    name = models.CharField()
    number_legs = models.IntegerField()
    ...

    def get_child_animal(self):
        child_animal = None
        for r in self._meta.get_all_related_objects():
            if r.field.name == 'animal_ptr':
                child_animal = getattr(self, r.get_accessor_name())
        if not child_animal:
            raise Exception("No subclass, you shouldn't create Animals directly")
        return child_animal

class Dog(Animal):
    ...

for a in Animal.objects.all():
    a.get_child_animal() # returns the dog (or whatever) instance

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


يمكنك تحقيق هذا البحث عن كافة الحقول الموجودة في الأصل التي تمثل مثال django.db.models.fields.related.RelatedManager. من المثال الخاص بك يبدو أن الفئات الفرعية التي تتحدث عنها ليست فئات فرعية. حق؟


( تحديث : بالنسبة لـ Django 1.2 والإصدارات الأحدث ، والتي يمكن أن تتبع استعلامات Select_related عبر علاقات OneToOneField العكسي (وبالتالي أسفل التسلسل الهرمي للوراثة) ، هناك تقنية أفضل متوفرة والتي لا تتطلب حقل real_type على النموذج الأصلي. إنها متوفرة في InheritanceManager في مشروع django-model-utils .)

الطريقة المعتادة للقيام بذلك هي إضافة ForeignKey إلى ContentType في نموذج الأصل الذي يقوم بتخزين نوع محتوى فئة "leaf" المناسبة. بدون هذا ، قد تضطر إلى إجراء عدد كبير من الاستعلامات على الجداول التابعة للعثور على المثيل ، اعتماداً على حجم شجرة التوريث الخاص بك. إليك كيف قمت بذلك في مشروع واحد:

from django.contrib.contenttypes.models import ContentType
from django.db import models

class InheritanceCastModel(models.Model):
    """
    An abstract base class that provides a ``real_type`` FK to ContentType.

    For use in trees of inherited models, to be able to downcast
    parent instances to their child types.

    """
    real_type = models.ForeignKey(ContentType, editable=False)

    def save(self, *args, **kwargs):
        if not self._state.adding:
            self.real_type = self._get_real_type()
        super(InheritanceCastModel, self).save(*args, **kwargs)

    def _get_real_type(self):
        return ContentType.objects.get_for_model(type(self))

    def cast(self):
        return self.real_type.get_object_for_this_type(pk=self.pk)

    class Meta:
        abstract = True

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

لن يعمل هذا الحل إذا لم تكن قادرًا على تعديل النموذج الأصلي. في هذه الحالة أنت عالق تمامًا في التحقق من جميع الفئات الفرعية يدويًا.





many-to-many