سؤال

كما هو الحال في هذا السؤال, ، إلا أنني أريد أن أكون قادرًا على الحصول على مقاييس تُرجع مجموعة مختلطة من الأشياء:

>>> Product.objects.all()
[<SimpleProduct: ...>, <OtherProduct: ...>, <BlueProduct: ...>, ...]

لقد اكتشفت أنه لا يمكنني فقط تعيين Product.Meta.abstract إلى صواب أو خلاف ذلك عادل أو معا Querysets من الكائنات المختلفة. حسنًا ، ولكن هذه كلها فئات فرعية لفئة مشتركة ، لذلك إذا تركت فئة الفئة الفائقة على أنها غير مجترعة ، فيجب أن أكون سعيدًا ، طالما يمكنني الحصول على مديرها لإرجاع كائنات من الفئة المناسبة. يقوم رمز الاستعلام في Django بعمله ، ويقوم فقط بإجراء مكالمات إلى Product (). يبدو سهلاً بما فيه الكفاية ، إلا أنه ينفجر عندما أتجاوز Product.__new__, ، أنا أخمن بسبب __metaclass__ في النموذج ... إليك رمز غير دانغو الذي يتصرف إلى حد كبير كيف أريده:

class Top(object):
    _counter = 0
    def __init__(self, arg):
        Top._counter += 1
        print "Top#__init__(%s) called %d times" % (arg, Top._counter)
class A(Top):
    def __new__(cls, *args, **kwargs):
        if cls is A and len(args) > 0:
            if args[0] is B.fav:
                return B(*args, **kwargs)
            elif args[0] is C.fav:
                return C(*args, **kwargs)
            else:
                print "PRETENDING TO BE ABSTRACT"
                return None # or raise?
        else:
            return super(A).__new__(cls, *args, **kwargs)
class B(A):
    fav = 1
class C(A):
    fav = 2
A(0) # => None
A(1) # => <B object>
A(2) # => <C object>

لكن هذا يفشل إذا ورثت من django.db.models.Model بدلاً من object:

File "/home/martin/beehive/apps/hello_world/models.py", line 50, in <module>
    A(0)
TypeError: unbound method __new__() must be called with A instance as first argument (got ModelBase instance instead)

وهو خلف كربي بشكل ملحوظ. لا يمكنني الدخول إلى إطار بلدي __new__ رمز في مصحح الأخطاء ، أيضا. لقد حاولت بشكل مختلف super(A, cls), Top, super(A, A), وكل ما سبق بالاشتراك مع المرور cls في الحجة الأولى ل __new__, ، كل شيء دون جدوى. لماذا هذا يركلني بشدة؟ هل يجب علي معرفة metaclasses من Django لتتمكن من إصلاح هذا أم أن هناك طريقة أفضل لإنجاز نهايتي؟

هل كانت مفيدة؟

المحلول

في الأساس ما تحاول القيام به هو إعادة فصول الأطفال المختلفة ، مع الاستعلام عن فئة قاعدة مشتركة. هذا هو: تريد فصول الأوراق. تحقق من هذا المقتطف للحصول على حل: http://www.djangosnippets.org/snippets/1034/

تأكد أيضًا من مراجعة المستندات على إطار عمل ContentTypes من Django: http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ يمكن أن يكون الأمر مربكًا بعض الشيء في البداية ، لكن أنواع المحتوى ستحل مشكلات إضافية ربما تواجهها عند استخدام فئات قاعدة غير مجدية مع ORM Django.

نصائح أخرى

تريد واحدة من هذه:

http://code.google.com/p/django-polymorphic-models/
https://github.com/bconstantin/django_polymorphic

هناك سلبيات ، وهي استفسارات إضافية.

حسنًا ، هذا يعمل: https://gist.github.com/348872

كان هذا الشيء الصعب هذا.

class A(Top):
    pass

def newA(cls, *args, **kwargs):
    # [all that code you wrote for A.__new__]

A.__new__ = staticmethod(newA)

الآن ، هناك شيء حول كيفية ربط Python __new__ ربما لا أفهمها تمامًا ، لكن جوهر ذلك هو: Django's ModelBase Metaclass ينشئ كائن فئة جديد ، بدلاً من استخدام الكائن الذي تم نقله إليه __new__; ؛ نسمي ذلك A_prime. ثم تلتصق بكل السمات التي كانت لديك في تعريف الفصل A على A_prime, ، لكن __new__ لا تحصل على إعادة الربط بشكل صحيح.

ثم عند التقييم A(1), A هو في الواقع A_prime هنا ، ينادي بيثون <A.__new__>(A_prime, 1), ، والتي لا تتطابق ، وينفجر.

لذا فإن الحل هو تحديد الخاص بك __new__ بعد، بعدما A_prime تم تعريفه.

ربما هذا خطأ في django.db.models.base.ModelBase.add_to_class, ، ربما يكون هذا خطأ في بيثون ، لا أعرف.

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

ببساطة stickTaticMethod قبل __new__ طريقة.

@staticmethod
def __new__(cls, *args, **kwargs):
    print args, kwargs
    return super(License, cls).__new__(cls, *args, **kwargs)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top