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

12 投票
3 回答
2123 浏览
提问于 2025-04-16 03:37

我在使用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 个回答

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)

看起来一切都正常。

2

你也可以使用列的复制方法吗?这样的话,字段就可以独立于表格来定义,而那些被重复使用的字段只需要用field.copy()来复制就可以了。

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()
    #...
14

你可以把一些共同的属性提取到一个叫做混合类(mixin class)的地方,然后和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的文档所提到的,来自混合类的Column对象是会被复制的。我已经更新了代码示例来展示这个行为。

撰写回答