SQLAlchemy:在声明式类定义中避免重复

12

我正在使用SQLAlchemy,而我的许多对象模型中都有相同的两个属性:id(整数和主键)和name(字符串)。我试图避免在每个类中像这样声明它们:

class C1(declarative_base()):
    id = Column(Integer, primary_key = True)
    name = Column(String)
    #...

class C2(declarative_base()):
    id = Column(Integer, primary_key = True)
    name = Column(String)
    #...

有什么好的方法可以做到这一点吗?我尝试使用元类,但还没有成功。

3个回答

14

你可以将常用属性提取到一个混合类中,然后在declarative_base()的基础上进行多继承:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

class IdNameMixin(object):
    id = Column(Integer, primary_key=True)
    name = Column(String)

class C1(declarative_base(), IdNameMixin):
    __tablename__ = 'C1'

class C2(declarative_base(), IdNameMixin):
    __tablename__ = 'C2'

print C1.__dict__['id'] is C2.__dict__['id']
print C1.__dict__['name'] is C2.__dict__['name']

编辑:你可能会认为这会导致C1C2共享相同的Column对象,但正如在SQLAlchemy文档中所述,当来自Mixin类时,Column对象会被复制。我已更新代码示例以演示此行为。


很遗憾,这样做行不通,因为id属性将在IdNameMixin的所有子类之间共享。在SQLAlchemy中,每个类必须有自己的id(一个新创建的Column类对象)。 - max
啊,非常酷!谢谢你。现在如果我能做些关于__tablename__的事情就好了,它肯定必须是唯一的 :) 但我喜欢你使用混合类的方法比我使用元类修改的方法更好。 - max

2

你也可以使用Column的复制方法吗?这样,字段可以独立于表定义,并且那些被重用的字段只需要复制field即可。

id = Column(Integer, primary_key = True)
name = Column(String)

class C1(declarative_base()):
    id = id.copy()
    name = name.copy()
    #...

class C2(declarative_base()):
    id = id.copy()
    name = name.copy()
    #...

1
有人知道如何更改不同表类中这些列的属性吗?也就是说,如果在C1中id不是主键,但在C2中是主键,如何做出区分而避免重复呢? - jkmacc

1

我想我已经让它工作了。

我创建了一个从DeclarativeMeta派生的元类,并将其设置为C1和C2的元类。在这个新的元类中,我只是简单地说

def __new__(mcs, name, base, attr):
  attr['__tablename__'] = name.lower()
  attr['id'] = Column(Integer, primary_key = True)
  attr['name'] = Column(String)
  return super().__new__(mcs, name, base, attr)

看起来运行良好。


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