繁体   English   中英

SQLAlchemy:具有动态'association_proxy'创建函数的多重继承

[英]SQLAlchemy: Multiple Inheritance with dynamic 'association_proxy' creator function

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

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

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

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的具体实例的类。 我现在坚持的是,我不知道如何将调用类传递给创建者函数。 这是可能的,或者甚至可能更容易实现我想要完成的工作?

当你的persons字段被定义时,你不可能真正知道它最终会成为什么类.Python占用类成员的现成字典并type.__new__创建类(通过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查找的Base._decl_class_registry - 从声明性基础下降的所有类的注册表 - 不是最终类(例如Movie ),而是关联对象(例如PersonMovieRole )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM