SQLAlchemy: multiple inheritance with dynamic function "association_proxy"

I am currently trying to create the following database schema with SQLAlchemy (using ext.declarative):

I have a base class MyBaseClassthat provides some common functions for all my public classes, a mixin class MetadataMixinthat provides the functionality for requesting metadata from imdb and saving. Each class that has subclasses MetadataMixinhas a field personsthat provides an M: N relation to class instances Personand a field persons_rolesthat provides a 1: N ratio to an object (one for each subclass) in which a roleparticular person is stored plays in an instance of the subclass.

This is an abridged version of what my code currently looks like:

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

What I'm trying to do is create a generic creatorfunction for association_proxythat creates a PersonMovieRole or PersonShowRole object, depending on the class of the particular instance to which it is added Person. At the moment, I'm stuck in the fact that I don’t know how to pass the calling class to the creator function. Is this possible, or maybe even an easier way for what I'm trying to accomplish?

+5
source share
1 answer

, 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).

+3

All Articles