> On 24 Apr 2016, at 13:50, Jimmy Thrasibule <thrasibule.ji...@gmail.com> wrote:
> 
> I'm working on a SQLAlchemy defining a bunch of mixin classes that 
> applications should be able to import and extend their model.
> 
> When looking at the documentation,  mixin classes are create knowing the 
> final table name however, in the case of a generic library, the final table 
> name that will be used by the application is not known.
> 
> Take the following mixin classes:
> 
> import sqlalchemy as sa
> 
> class UserMixin(object):
>     id = sa.Column(sa.Integer(), primary_key=True)
>     first_name = sa.Column(sa.Unicode(255))
>     last_name  = sa.Column(sa.Unicode(255))
> 
> class ItemMixin(object):
>     id = sa.Column(sa.Integer(), primary_key=True)
>     name = sa.Column(sa.Unicode(255))
>     short_description = sa.Column(sa.Unicode(255))
> 
> class OrdersMixin(object):
>     id = sa.Column(sa.Integer(), primary_key=True)
>     user_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
>     item_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
> 
> Then an application defining its models:
> 
> import sqlalchemy as sa
> from sqlalchemy.ext.declarative import declarative_base
>     
> Base = declarative_base()
> 
> class MyUser(UserMixin, Base):
>     __tablename__ = 'myuser'
> 
> class MyItem(ItemMixin, Base):
>     __tablename__ = 'myitem'
>     total = sa.Column(sa.Integer())
> 
> class MyOrders(OrdersMixin, Base):
>     __tablename__ = 'myorders'
> 
> I have two issues with this model:
> 
>       • Except from redefining the relationship columns in the extending 
> models, how can the mixin class build the relationship on its own.
>       • Type of the foreign key is assumed by the mixin class, but the `id` 
> of the table may come from the application itself or from another mixin class.
> Is the model I'm trying to implement correct? What would be the right way to 
> tackle this problem?

I don’t know about the *right* way, but one way would be to write a function 
that generates new OrdersMixin classes for a given User and Item 
implementation. For example:

##########################
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base, declared_attr

class UserMixin(object):
    id = sa.Column(sa.Integer(), primary_key=True)
    first_name = sa.Column(sa.Unicode(255))
    last_name  = sa.Column(sa.Unicode(255))

class ItemMixin(object):
    id = sa.Column(sa.Integer(), primary_key=True)
    name = sa.Column(sa.Unicode(255))
    short_description = sa.Column(sa.Unicode(255))

def make_orders_mixin(userpkcol, itempkcol):
    class OrdersMixin(object):
        id = sa.Column(sa.Integer(), primary_key=True)
        @declared_attr
        def user_id(self):
            return sa.Column(sa.ForeignKey(userpkcol))

        @declared_attr
        def item_id(self):
            return sa.Column(sa.ForeignKey(itempkcol))

    return OrdersMixin

    
Base = declarative_base()

class MyUser(UserMixin, Base):
    __tablename__ = 'myuser'

class MyItem(ItemMixin, Base):
    __tablename__ = 'myitem'
    total = sa.Column(sa.Integer())

OrdersMixin = make_orders_mixin(MyUser.id, MyItem.id)

class MyOrders(OrdersMixin, Base):
    __tablename__ = 'myorders'

if __name__ == '__main__':
    engine = sa.create_engine('sqlite://', echo='debug')
    Base.metadata.create_all(bind=engine)
##########################

This is using a nice feature of SQLAlchemy where, if you define a column as a 
foreign key, and you don’t give it an explicit type, it will use the same type 
as the referenced column.

As for alternative approaches, perhaps some of the “Generic Associations” 
examples might give you some ideas:

http://docs.sqlalchemy.org/en/latest/orm/examples.html#module-examples.generic_associations

Hope that helps,

Simon

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to