sqlalchemy将mixin列移到末尾

2024-10-01 13:34:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个sqlalchemy模型,其中所有的表/对象都有一个notes字段。所以为了遵循干燥原则,我把场地搬到了一个混合班。在

class NotesMixin(object):
    notes = sa.Column(sa.String(4000) , nullable=False, default='')

class Service(Base, NotesMixin):
    __tablename__ =  "service"
    service_id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String(255), nullable=False, index=True, unique=True)


class Datacenter(Base, NotesMixin):
    __tablename__ =  "datacenter"
    datacenter_id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String(255), nullable=False, index=True, unique=True)


class Network(Base, NotesMixin, StatusMixin):
    __tablename__ =  "network"
    network_id = sa.Column(sa.Integer, primary_key=True)

etc...

现在notes列是model/db中的第一列。我知道这不会影响我的应用程序的功能,但是看到id前的注释会让我有点恼火,等等。有什么办法可以把它移到最后?在


Tags: keyidfalsetruebasestringsacolumn
2条回答

找到了更干净的解决方案:

在sqlalchemy 0.6.5中使用sqlalchemy.ext.declarative.declared_attr修饰符(sqlalchemy.util.classproperty在sqlalchemy<;=0.6.4中)

class NotesMixin(object):
    @declared_attr
    def notes(cls):
        return sa.Column(sa.String(4000) , nullable=False, default='')

根据文档,这是“对于具有外键的列,以及各种需要目标显式上下文的映射器级构造”。虽然严格说来不是这样,但它是通过在构造子类时调用方法(并创建列)来实现的,从而避免了复制的需要。这意味着mixin列将在最后出现。可能是比黑客攻击更好的解决方案。。。在

简单的答案是:只需自己创建数据库表,而不是让sqlalchemy用metadata.create_all()来完成。在

如果您不认为这是可以接受的,恐怕这需要对sqlalchemy.ext.declarative本身做一个(小的)更改,或者您必须创建自己的元类并用metaclass关键字参数将其传递给declarative_base()。然后将使用该类代替默认的DeclarativeMeta。在

说明:sqlalchemy使用列属性的创建顺序,它将其存储在“private”属性._creation_order(在调用column()时生成)中。声明性扩展通过从mixin类创建column对象的副本并将其添加到类中来实现列的混合。此副本的._creation_order设置为与mixin类的原始属性相同的值。由于mixin类当然是先创建的,所以它的列属性的创建顺序将低于子类。在

因此,为了使您的请求成为可能,在制作副本时应该分配一个新的创建顺序,而不是使用原始的。您可以尝试根据这个解释创建自己的元类,并使用它。但您也可以尝试询问sqlalchemy开发人员。也许他们愿意将此作为bug/feature请求接受?至少,它看起来像是一个小的(一行)改变,除了你要求的改变(可以说是更好的)之外,不会有任何效果。在

相关问题 更多 >