Подклассные модели django со встроенными наборами запросов
Как и в этом вопросе, за исключением того, что я хочу иметь наборы запросов, которые возвращают смешанное тело объектов:
>>> Product.objects.all()
[<SimpleProduct: ...>, <OtherProduct: ...>, <BlueProduct: ...>, ...]
Я понял, что я не могу просто установить Product.Meta.abstract
в true или иначе просто ИЛИ вместе наборы запросов различных объектов. Хорошо, но это все подклассы общего класса, поэтому, если я оставлю их суперкласс как неабстрактный, я буду счастлив, пока я смогу заставить его менеджера возвращать объекты соответствующего класса. Код запроса в 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)
и все вышеперечисленное в сочетании с прохождением cls
в качестве первого аргумента __new__
все безрезультатно. Почему это так сильно пинает меня? Нужно ли выяснять метаклассы django, чтобы это исправить, или есть лучший способ достичь моих целей?
5 ответов
По сути, вы пытаетесь вернуть разные дочерние классы, запрашивая общий базовый класс. То есть: вы хотите листовые классы. Проверьте этот фрагмент для решения: http://www.djangosnippets.org/snippets/1034/
Также обязательно ознакомьтесь с документацией по инфраструктуре Contenttypes Django: http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ Поначалу это может немного запутать, но Contenttypes решит дополнительные проблемы, которые вы '' Я, вероятно, столкнусь при использовании неабстрактных базовых классов с ORM Джанго.
Вы хотите один из них:
http://code.google.com/p/django-polymorphic-models/
https://github.com/bconstantin/django_polymorphic
Есть минусы, а именно дополнительные запросы.
Просто вставьте @staticmethod перед __new__
метод.
@staticmethod
def __new__(cls, *args, **kwargs):
print args, kwargs
return super(License, cls).__new__(cls, *args, **kwargs)
Другой подход, который я недавно нашел: http://jeffelmore.org/2010/11/11/automatic-downcasting-of-inherited-models-in-django/
Хорошо, это работает: 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
здесь Python вызывает <A.__new__>(A_prime, 1)
, который не совпадает, и он взрывается.
Таким образом, решение состоит в том, чтобы определить ваш __new__
после A_prime
был определен.
Может быть, это ошибка в django.db.models.base.ModelBase.add_to_class
возможно это ошибка в Python, я не знаю.
Теперь, когда я сказал "это работает" ранее, я имел в виду, что это работает изолированно с минимальным тестовым примером построения объекта в текущей версии Django для SVN. Я не знаю, действительно ли он работает в качестве модели или полезен в QuerySet. Если вы на самом деле используете это в рабочем коде, я сделаю публичный доклад об этом для pdxpython и заставлю их издеваться над вами, пока вы не купите нам пиццу без глютена.