如何为Sqlalchemy中的各种模型编写一个通用的get_by_id()方法?

Posted

技术标签:

【中文标题】如何为Sqlalchemy中的各种模型编写一个通用的get_by_id()方法?【英文标题】:How to write a common get_by_id() method for all kinds of models in Sqlalchemy? 【发布时间】:2011-04-07 23:24:47 【问题描述】:

我正在使用带有 sqlalchemy 的 pylons。我有几个模型,发现自己一次又一次地写这样的代码:

question = Session.query(Question).filter_by(id=question_id).one()
answer = Session.query(Answer).fileter_by(id=answer_id).one()
...
user = Session.query(User).filter_by(id=user_id).one()

既然模型都是扩展类Base,有没有办法定义一个通用的get_by_id()方法呢?

所以我可以把它用作:

quesiton = Question.get_by_id(question_id)
answer = Answer.get_by_id(answer_id)
...
user = User.get_by_id(user_id)

【问题讨论】:

【参考方案1】:

如果id 是您的主键列,您只需:

session.query(Foo).get(id)

如果该实例已经在会话中,它的优点是不查询数据库。

【讨论】:

【参考方案2】:

不幸的是,SQLAlchemy 不允许您在没有相应表声明的情况下继承 Base。您可以将 mixin class 和 get_by_id 定义为类方法,但是您需要为每个类指定它。

一个更快更脏的解决方案是将其猴子修补到Base

def get_by_id(cls, id, session=session):
    return session.query(cls).filter_by(id=id).one()

Base.get_by_id = classmethod(get_by_id)

这假设您在定义时有一个可用的 session 对象,否则您每次都需要将其作为参数传递。

【讨论】:

只有当你使用愚蠢的declarative 东西时,这才是正确的。最简单的解决方法是不使用declarative 这个答案帮助我解决了我遇到的一个相关问题。谢谢。【参考方案3】:
class Base(object):
    @classmethod
    def get_by_id(cls, session, id):
        q = session.query(cls).filter_by(id=id)
        return q.one()

Question.get_by_id(Session, question_id)

【讨论】:

我相信Freewind所指的Base是调用declarative_base的结果,所以它的定义不能通过这种方式直接修改。 @dhaffey,所以,正如我已经说过的,不要使用declarative。呜呜呜。 @Freewind, declarative 将数据库模式、关系和映射对象全部混合为一个可怕的组合。这会导致不同程度的 hacky 变通方法出现许多问题,更不用说在不必要的地方使用大量多余的魔法了。

以上是关于如何为Sqlalchemy中的各种模型编写一个通用的get_by_id()方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何为通用数字编写函数?

如何为没有已知列的 PostgreSQL 视图编写通用更新触发器?

SQLAlchemy + Tornado:如何为SQLAlchemy的ScopedSession创建scopefunc?

如何为使用 Firestore 文档快照的模型编写测试

如何为客户特定数据使用通用变量

如何为本地通知界面编写适当的测试?