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




many-to-many (7)

في 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 ، ولكنها تعمل على خدعة ويمكن استخدامها أثناء الطيران إذا لزم الأمر.


في Python ، مع منح فئة ("نمط جديد") X ، يمكنك الحصول على الفئات الفرعية (المباشرة) الخاصة بها مع X.__subclasses__() ، والتي تقوم بإرجاع قائمة كائنات الفئة. (إذا كنت تريد "أحفاد أخرى" ، __subclasses__ عليك أيضًا الاتصال بـ __subclasses__ على كل فئة من الفئات الفرعية المباشرة ، إلخ ... - إذا كنت بحاجة إلى مساعدة حول كيفية القيام بذلك بشكل فعال في Python ، اسأل فقط!).

بمجرد تحديد فئة اهتمام الطفل (ربما جميعهم ، إذا كنت تريد حالات من كل الفئات الفرعية الفرعية ، إلخ) ، يجب أن يساعد getattr(parentclass,'%s_set' % childclass.__name__) (إذا كان اسم فئة الطفل هو 'foo' ، هذا مثل الوصول إلى parentclass.foo_set - لا أكثر ولا أقل). مرة أخرى ، إذا كنت بحاجة إلى توضيح أو أمثلة ، يرجى السؤال!


هنا هو الحل الخاص بي ، مرة أخرى يستخدم _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-polymorphic لذلك.

يسمح باستبدال الطبقات المشتقة تلقائيًا بنوعها الفعلي. كما أنه يوفر دعم مشرف Django ، ومعالجة استعلام SQL أكثر كفاءة ، ونموذج الوكيل ، والخطوط الداخلية ودعم formset.

يبدو أن المبدأ الأساسي يتم إعادة اختراعه عدة مرات (بما في ذلك Wagtail. .specific ، أو الأمثلة المبينة في هذا المنصب). ومع ذلك ، يتطلب الأمر المزيد من الجهد ، للتأكد من أنه لا يؤدي إلى مشكلة في طلب N ، أو أن يتكامل بشكل جيد مع المشرف ، formsets / inlines أو تطبيقات الطرف الثالث.






many-to-many