使用SQLAlchemy的动态列属性

5 投票
1 回答
3542 浏览
提问于 2025-04-16 14:28

我有一些SA模型,现在需要一些技巧:

class Entry(Base):
    __tablename__ = 'entry'
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(255))
    author_id = Column(Integer, ForeignKey('user.id'))
    date = Column(DateTime)
    content = Column(Text)
    author = relationship('User', backref='entries')

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(Unicode(255))
    ...

如你所见,这个模型很常见,用户会写一些记录……我需要展示一些关于这些记录的统计信息(比如每周或每月的记录数量……)

为了计算记录数量,我在用户模型中添加了一个column_property,像这样:

class User(Base):
    ...
    entries_count = column_property(select([func.count(Entry.id)]).\
                                            where(Entry.author_id==id))

这样我就能显示用户写了多少条记录。但是为了根据日期范围生成一些统计数据,我需要动态调整entries_count,以便添加日期的条件。

所以问题是:你会怎么处理日期条件呢?使用column_property是否是满足这种需求的最佳方案呢?

提前谢谢你。

1 个回答

8

添加属性是一种获取与对象相关的数据库状态的好方法。但是,如果有外部的条件参数,那么这个计数就不仅仅是一个状态,而是一个函数。把这样的数据表示为对象的属性就不太合适了。所以,最好直接查询额外的数据(在下面的所有例子中,都是计算比start_date更新的条目数量):

session.query(User, func.count(Entry.id))\
    .outerjoin((Entry, (Entry.author_id==User.id) & (Entry.date>start_date)))\
    .group_by(User.id)

或者在User类中定义一个辅助方法(而不是属性!)来简化使用:

class User(Base):
    # ...
    @classmethod
    def entries_count(cls, cond):
        return select([func.count(Entry.id)])\
                .where((Entry.author_id==cls.id) & cond)\
                .as_scalar()

session.query(User, User.entries_count(Entry.date>start_date))

撰写回答