如何通过SQLalchemy的声明式方法描述关联对象

2 投票
2 回答
638 浏览
提问于 2025-04-15 19:49

我想找一种方法,用声明式的方式来描述一个关联对象。除了在关联表中存储外键之外,我还需要存储一些信息,比如关联的创建日期。

现在,我的模型是这样的:

# Define the User class
class User(Base):
    __tablename__ = 'users'

    # Define User fields
    id = schema.Column(types.Integer(unsigned=True),
        schema.Sequence('users_seq_id', optional=True), primary_key=True)
    password = schema.Column(types.Unicode(64), nullable=False)

# Define the UserSubset class
class UserSubset(Base):
    __tablename__ = 'subsets'

    # Define UserSubset fields
    id = schema.Column(types.Integer(unsigned=True),
        schema.Sequence('subsets_seq_id', optional=True), primary_key=True)
    some_short_description = schema.Column(types.Unicode(50), nullable=False)

# Define the subset memberships table
subset_memberships = schema.Table('group_memberships', Base.metadata,
    schema.Column('user_id', types.Integer(unsigned=True), ForeignKey('users.id')),
    schema.Column('subset_id', types.Integer(unsigned=True), ForeignKey('subsets.id')),
    schema.Column('created', types.DateTime(), default=now, nullable=False),
)

我可以把所有东西都连接到一个关联对象上吗?还是说我应该放弃使用声明式的方法?

2 个回答

0

手册中可以看到,设置一对多的关系其实非常简单:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    addresses = relation("Address", backref="user")

class Address(Base):
    __tablename__ = 'addresses'

    id = Column(Integer, primary_key=True)
    email = Column(String(50))
    user_id = Column(Integer, ForeignKey('users.id'))

多对多的关系也不难:

使用声明式(declarative)来处理多对多关系没有什么特别的。relation()函数的第二个参数仍然需要一个表对象,而不是一个声明式类。这个表应该和声明式基础使用的MetaData对象是同一个:

 keywords = Table('keywords', Base.metadata,
                     Column('author_id', Integer, ForeignKey('authors.id')),
                     Column('keyword_id', Integer, ForeignKey('keywords.id'))
             )
             
 class Author(Base):
     __tablename__ = 'authors'
     id = Column(Integer, primary_key=True)
     keywords = relation("Keyword", secondary=keywords)

一般来说,在多对多关系中,你不应该同时映射一个类和指定它的表,因为这样可能会导致ORM发出重复的插入和删除语句。

总之,你现在的做法可能更适合使用继承。当然,有些复杂的表关系可能会让声明式的方式变得很麻烦,但看起来这并不是其中之一。

还有一点,代码注释应该说明接下来的代码做了什么以及为什么,而不是怎么做。比如说,写一个 # 定义用户类 的注释,几乎就像在代码里写 a = 1 # 将值1赋给变量"a" 一样。

1

你现在使用的只是一个多对多的关系。关于如何使用关联对象的详细信息,可以在文档中找到。

还有一个叫做associationproxy的扩展,它可以简化这种关系。

撰写回答