7

この質問のように、オブジェクトの混合体を返すクエリセットを使用できるようにしたいことを除いて:

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

Product.Meta.abstracttrue に設定することも、異なるオブジェクトのクエリセットを単に OR することもできないことがわかりました。わかりましたが、これらはすべて共通クラスのサブクラスであるため、スーパークラスを非抽象として残しても、そのマネージャーに適切なクラスのオブジェクトを返させることができる限り、満足するはずです。django のクエリ コードはその役割を果たし、Product() を呼び出すだけです。をオーバーライドすると爆発することを除いて、十分に簡単に聞こえますが、モデルProduct.__new__のせいだと推測してい__metaclass__ます...これは、私が望むようにほとんど動作する非djangoコードです。

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)渡すことと組み合わせてさまざまに試しましたが、すべて役に立ちませんでした。なぜこれが私をそんなに激しく蹴っているのですか?これを修正するには、djangoのメタクラスを理解する必要がありますか?それとも、目的を達成するためのより良い方法がありますか?cls__new__

4

5 に答える 5

4

基本的に、あなたがやろうとしているのは、共有基本クラスにクエリを実行しながら、さまざまな子クラスを返すことです。つまり、リーフクラスが必要です。解決策については、このスニペットを確認してください:http ://www.djangosnippets.org/snippets/1034/

また、DjangoのContenttypesフレームワークのドキュメントも確認してください。http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/最初は少し混乱するかもしれませんが、Contenttypesは追加の問題を解決します。 DjangoのORMで非抽象基本クラスを使用するときに直面する可能性があります。

于 2010-03-30T09:48:25.540 に答える
2

次のいずれかが必要です。

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

欠点、つまり余分なクエリがあります。

于 2012-02-08T17:29:30.010 に答える
1

さて、これは動作します: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のModelBaseメタクラスは、渡されたオブジェクトを使用するのではなく、新しいクラスオブジェクトを作成し__new__ます。それを呼び出しますA_prime。次に、クラス定義にあるすべての属性をに固定しますが、正しく再バインドAされません。A_prime__new__

次に、を評価するA(1)と、A実際にはA_primeここにありますが、Pythonは<A.__new__>(A_prime, 1)、一致しないを呼び出し、爆発します。

したがって、解決策は、定義された__new__ A_primeを定義することです。

多分これはのバグdjango.db.models.base.ModelBase.add_to_classかもしれません、多分それはPythonのバグかもしれません、私は知りません。

さて、先ほど「これは機能する」と言ったとき、これは現在のSVNバージョンのDjangoの最小オブジェクト構築テストケースとは別に機能することを意味しました。それが実際にモデルとして機能するのか、それともQuerySetで役立つのかはわかりません。これを本番コードで実際に使用する場合は、pdxpythonについて公開ライトニングトークを行い、グルテンフリーのピザをすべて購入するまでモックアップしてもらいます。

于 2010-03-30T08:50:52.650 に答える
1

最近見つけた別のアプローチ: http://jeffelmore.org/2010/11/11/automatic-downcasting-of-inherited-models-in-django/

于 2013-04-04T18:51:57.063 に答える
1

メソッドの前に @staticmethod を付けるだけ__new__です。

@staticmethod
def __new__(cls, *args, **kwargs):
    print args, kwargs
    return super(License, cls).__new__(cls, *args, **kwargs)
于 2012-02-08T13:45:34.820 に答える