簡體   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