【问题标题】:SQLAlchemy: Multiple Inheritance with dynamic 'association_proxy' creator functionSQLAlchemy:具有动态“association_proxy”创建者函数的多重继承
【发布时间】:2011-04-23 13:34:38
【问题描述】:

我目前正在尝试使用 SQLAlchemy(使用 ext.declarative)创建以下数据库架构:

我有一个基类 MyBaseClass,它为我的所有可公开访问的类提供了一些通用功能,一个 mixin 类 MetadataMixin 提供了从 imdb 查询元数据并存储它的功能。 子类MetadataMixin 的每个类都有一个字段persons,它提供与Person 类实例的M:N 关系,以及一个字段persons_roles,它提供与一个对象的1:N 关系(每个子类一个) 存储role 一个具体的人在子类的实例中播放。

这是我的代码目前的缩略版本:

from sqlalchemy import Column, Integer, Enum, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class MyBaseClass(object):
    """Base class for all publicly accessible classes"""
    id = Column(Integer, primary_key=True)


class Person(MyBaseClass):
    """A Person"""

    name = Column(Unicode)
    movies = association_proxy('movie_roles', 'movie',
                               creator=lambda m: _PersonMovieRole(movie=m))
    shows = association_proxy('show_roles', 'show',
                              creator=lambda s: _PersonShowRole(show=s=))


class _PersonMovieRole(Base):
    """Role for a Person in a Movie"""
    __tablename__ = 'persons_movies'

    id = Column(Integer, primary_key=True)
    role = Column(Enum('none', 'actor', 'writer', 'director', 'producer'),
                  default='none')
    person_id = Column(Integer, ForeignKey('persons.id'))
    person = relationship('Person', backref='movie_roles')
    movie_id = Column(Integer, ForeignKey('movies.id'))
    movie = relationship('Movie', backref='persons_roles')


class _PersonShowRole(Base):
    """Role for a Person in a Show"""
    __tablename__ = 'persons_shows'

    id = Column(Integer, primary_key=True)
    role = Column(Enum('none', 'actor', 'writer', 'director', 'producer'),
                  default='none')
    person_id = Column(Integer, ForeignKey('persons.id'))
    person = relationship('Person', backref='show_roles')
    show_id = Column(Integer, ForeignKey('shows.id'))
    show = relationship('Episode', backref='persons_roles')


class MetadataMixin(object):
    """Mixin class that provides metadata-fields and methods"""

    # ...
    persons = association_proxy('persons_roles', 'person',
                                creator= #...???...#)


class Movie(Base, MyBaseClass, MetadataMixin):
    #....
    pass

我要做的是为association_proxy 创建一个通用的creator 函数,该函数创建一个PersonMovieRole 或PersonShowRole 对象,具体取决于添加Person 的具体实例的类。我现在坚持的是我不知道如何将调用类传递给创建者函数。 这可能吗,或者是否有更简单的方法来完成我想要完成的事情?

【问题讨论】:

    标签: python sqlalchemy multiple-inheritance


    【解决方案1】:

    当你的 persons 字段被定义时,你无法真正知道它最终会在哪个类中。Python 会占用类成员的现成字典并从中创建类(通过 type.__new__),但是当它发生时,这些成员已经完全定义了。

    因此,您需要直接向 mixin 提供所需的信息,并容忍它将在您的代码中创建的少量重复。我会选择类似这样的界面:

    class Movie(Base, MyBaseClass, MetadataMixin('Movie')):
        pass
    

    (您也不能拥有MetadataMixin(Movie),原因完全相同:Movie 要求在创建类时完全定义其基类。

    要实现这样的“参数化类”,只需使用一个函数:

    def MetadataMixin(cls_name):
        """Mixin class that provides metadata-fields and methods"""
        person_role_cls_name = 'Person%sRole' % cls_name
        person_role_cls = Base._decl_class_registry[person_role_cls_name]
    
        class Mixin(object):
            # ...
            persons = association_proxy('persons_roles', 'person',
                                        creator=person_role_cls)
        return Mixin
    

    这是可行的,因为我们在 Base._decl_class_registry 中查找的内容 - 从声明性基础降级的所有类的注册表 - 不是最终类(例如 Movie),而是关联对象(例如 PersonMovieRole) .

    【讨论】:

      猜你喜欢
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 2012-03-25
      相关资源
      最近更新 更多