jba*_*ter 5 python sqlalchemy multiple-inheritance
我目前正在尝试使用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
Run Code Online (Sandbox Code Playgroud)
我要做的是创建一个泛型creator函数association_proxy,创建PersonMovieRole或PersonShowRole对象,具体取决于Person添加到的具体实例的类.我现在坚持的是,我不知道如何将调用类传递给创建者函数.这是可能的,或者甚至可能更容易实现我想要完成的工作?
当你的persons字段被定义时,你无法真正知道它最终会进入哪个类。Python 使用类成员的现成字典并从中创建类(通过type.__new__),但当它发生时,这些成员已经完全定义了。
因此,您需要直接向 mixin 提供所需的信息,并容忍它在代码中创建的少量重复。我会选择与此类似的界面:
class Movie(Base, MyBaseClass, MetadataMixin('Movie')):
pass
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为我们要查找的内容Base._decl_class_registry(从声明性基派生的所有类的注册表)不是最终类(例如Movie),而是关联对象(例如PersonMovieRole)。
| 归档时间: |
|
| 查看次数: |
1188 次 |
| 最近记录: |