Улучшить синтаксис SQLAlchemy для полиморфной идентичности - PullRequest
5 голосов
/ 16 декабря 2010

У меня есть декларативный базовый класс Entity, который определяет столбец name как полиморфный, например,

class Entity(DeclarativeBase):
    name = Column('name', String(40))
    __mapper_args__ = {'polymorphic_on':name}

В подклассах я теперь могу сказать

class Experiment(Entity):
    __mapper_args__ = {'polymorphic_identity': "experiment"}

и будет сделано. Тем не менее, я хотел бы упростить создание подклассов для пользователей моей библиотеки и поэтому сделать возможным следующее:

  • Имейте лучший синтаксис для него, который не так сложен, как синтаксис по умолчанию. Это может быть простое присваивание poly_id = "exp" внутри класса или, возможно, декоратор класса.
  • Если не указано polymorphic_identity, извлеките имя из имени подкласса.

Я попытался сделать это с помощью метаклассов (только вторая часть):

from sqlalchemy.ext.declarative import DeclarativeMeta

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        dict_["__mapper_args__"] = {'polymorphic_identity': classname}
        return super(Meta, cls).__init__(classname, bases, dict_)

class CombinedMeta(Meta, DeclarativeMeta):
    pass

class Experiment(Entity):
    __metaclass__ = CombinedMeta

так что, на мой взгляд, мой Meta должен установить имя перед вызовом DeclarativeMeta, но, похоже, он не работает. Так что либо DeclarativeMeta, который предположительно устанавливает полиморфное имя, никогда не увидит изменения, потому что я испортил MRO, или то, что я делаю, в любом случае совершенно неправильно. Что мне нужно изменить или в SQLAlchemy уже есть что-то подобное?

Ответы [ 2 ]

7 голосов
/ 16 декабря 2010

Позор мне, но проблему легко решить, не используя dict_, а установив атрибут непосредственно на cls.

class Meta(DeclarativeMeta):
    def __init__(cls, *args, **kw):
        if getattr(cls, '_decl_class_registry', None) is None:
            return # they use this in the docs, so maybe its not a bad idea
        cls.__mapper_args__ = {'polymorphic_identity': cls.__name__}
        return super(Meta, cls).__init__(*args, **kw)

class Experiment(Entity):
    __metaclass__ = Meta
1 голос
/ 16 декабря 2010

Последние документы sqlalchemy показывают способы использования классов mixin для таких целей (я не уверен, работает ли он только в версиях> = 0.6 или лучше документирован сейчас)

http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative/mixins.html

...