在SQLAlchemy中将__table_args__与mixin类中的约束条件相结合

9
在SQLAlchemy中,我已经了解到如何在声明一个声明性类时合并来自不同Mixin的__table_args__。
我有一个问题,示例展示了如何在MRO的最后一个类中完成这一操作,但如果我有这些Mixin,并希望它发生在MyClientMixin或Base类中,以避免为其他类型的Mixin重复此代码,该怎么办?
参考链接:Combining Table/Mapper Arguments from Multiple Mixins
class LaneCarrierCommitmentSummaryMixin(object):
    """ Lane Carrier Commitment Summary.

    A base class for LCCS to mixin with a client specific class.
    """

    __tablename__ = 'lane_carrier_commitment_summary'
    __table_args__ = ((UniqueConstraint(['hashmap_key', 'bow'],
                                        name='uq_lane_carrier_commitment_summary_hashmap_key_bow')),)

class MyClientMixin(object):
    """ MyClient Mixin class for providing the ETL schema. """

    __table_args__ = {'schema': 'myclient_etl'}

class MyClientLaneCarrierCommitmentSummary(LaneCarrierCommitmentSummaryMixin, DateTrackedMixin, MyClientMixin, Base):
    pass

我对这个概念感到有些困惑。

1个回答

13

这个基础类会搜索所有的Mixin以查找要添加的__table_args__,然后检查当前类中是否存在__local_table_args__需要添加。这样,__local_table_args__就不会与已声明的属性冲突。基类(cls.mro())按照相反顺序进行检查,这样链条下面的Mixin将被高级Mixin覆盖。

def _process_args(cls, attr, out_args, out_kwargs):
    try:
        args = getattr(cls, attr)
    except AttributeError:
        return

    if isinstance(args, Mapping):  # it's a dictionary
        out_kwargs.update(args)
    else:  # it's a list
        if isinstance(args[-1], Mapping):  # it has a dictionary at the end
            out_kwargs.update(args.pop())

        out_args.extend(args)

class Base():
    @declared_attr
    def __mapper_args__(cls):
        args = []
        kwargs = {}

        for mixin in reversed(cls.mro()):
            _process_args(mixin, '__mapper_args__', args, kwargs)

        _process_args(mixin, '__local_mapper_args__', args, kwargs)

        return kwargs  # mapper only takes dict

    @declared_attr
    def __table_args__(cls):
        args = []
        kwargs = {}

        for mixin in reversed(cls.mro()):
            _process_args(mixin, '__table_args__', args, kwargs)

        _process_args(cls, '__local_table_args__', args, kwargs)

        args.append(kwargs)  # [item, item, ...,  kwargs]
        return tuple(args)

所有的mixin都应该按照正常方式定义__table_args__,但是从Base继承的“真实”类应该定义__local_table_args__


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接