Разделенные на подклассы django модели с интегрированным querysets

Как в этом вопросе, кроме я хочу смочь иметь querysets, которые возвращают смешанное тело объектов:

>>> Product.objects.all()
[, , , ...]

Я выяснил, что не могу просто установить Product.Meta.abstract к истинному или иначе просто ИЛИ вместе querysets отличающихся объектов. Прекрасный, но это все подклассы общего класса, поэтому если я оставляю их суперкласс как некраткий обзор, я должен быть счастливым, пока я могу получить его менеджера к эхо-сигналам надлежащего класса. Код запроса в django делает свою вещь и просто выполняет вызовы к продукту (). Звучит достаточно легким, кроме него аварийные завершения, когда я переопределяю Product.__new__, Я предполагаю из-за __metaclass__ в Модели... Вот код non-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) # => 
A(2) # => 

Но это перестало работать, если я наследовался django.db.models.Model вместо object:

File "/home/martin/beehive/apps/hello_world/models.py", line 50, in 
    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, чтобы смочь зафиксировать это или есть ли лучший способ выполнить мои концы?

7
задан Community 23 May 2017 в 11:46
поделиться

2 ответа

По сути, вы пытаетесь вернуть различные дочерние классы, запрашивая общий базовый класс. То есть: вам нужны классы листа. Посмотрите этот фрагмент для решения: http://www.djangosnippets.org/snippets/1034/

Также обязательно ознакомьтесь с документацией по фреймворку Contenttypes в Django: http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ Поначалу это может быть немного запутанно, но Contenttypes решает дополнительные проблемы, с которыми вы, вероятно, столкнетесь при использовании неабстрактных базовых классов с ORM Django.

4
ответ дан 7 December 2019 в 03:13
поделиться

Хорошо, это работает: 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_prime, 1), что не совпадает, и он взрывается.

Так что решение состоит в том, чтобы определять __new__ после того, как A_prime уже определен.

Возможно, это ошибка в django.db.models.base.ModelBase.add_to_class, возможно, это ошибка в Python, я не знаю.

Теперь, когда я сказал "это работает" ранее, я имел в виду это работает в изоляции с тестовым примером построения минимального объекта в текущей SVN версии Django. Я не знаю, работает ли это на самом деле как Модель или полезно в QuerySet. Если вы действительно используете это в производственном коде, я сделаю из этого публичный lightning talk для pdxpython, и пусть они издеваются над вами, пока вы не купите нам всем пиццу без глютена.

1
ответ дан 7 December 2019 в 03:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: