【问题标题】:set non-ORM object fields while querying查询时设置非 ORM 对象字段
【发布时间】:2017-10-27 14:35:41
【问题描述】:

假设我有一个班级Interaction。我的程序处理interactions,每次交互都会更新一个分数表。 Interaction 被声明为数据库表的精确映射,但我也希望它能够引用ScoreTable 的相关实例。 ScoreTable是一个保存分数的类,控制业务逻辑更新分数:

class Interaction(Base):
    __tablename__ = 'interactions'
    #Mirror the table's structure
    anomaly_id = Column(Integer, ForeignKey('anomalies.id'), primary_key=True)
    user_id = Column(Integer, primary_key=True) # ForeignKey('users.id'),
    feedback_score = Column(Integer)

    #scoreUpdater is another (non-ORM) object I want this instance to be aware of
    myScoreUpdater=  ...

query() 获取的所有Interaction 实例都将共享相同的ScoreUpdater。所以当我运行query() 来获取我的所有Interactions 实例时,我可以以某种方式告诉query()scoreUpdater 设置为某个值,在同一进程中?否则,如果Interaction 克隆并填充ORM 数据,我可以给query() 一个半构建的模板实例吗? 我读到我可以修改标准构造函数来执行某些任务,但不知道如何通过 query() 将额外的参数(例如 ScoreUpdater 的实例)传递给构造函数

我猜另一种方法是先运行query并让它填充与ORM相关的字段,然后在第二步中遍历查询结果以设置非OM字段(即正确的实例scoreUpdater)?

我是 SQLalchemy 的新手......并从 java 转换为 python。因此,如果您认为我的方法从根本上是错误的,请告诉我!

【问题讨论】:

  • 我想我理解您的ScoreUpdater 想法(尽管我会将业务逻辑与模型对象分开),但ScoreTable 到底是什么?它是另一个映射类吗?

标签: python python-3.x sqlalchemy


【解决方案1】:

相关documentation on constructing objects说:

从数据库行重新创建对象时,SQLAlchemy ORM 不会调用 __init__。 ORM 的流程有点类似于 Python 标准库的 pickle 模块,调用底层的 __new__ 方法,然后直接在实例上悄悄恢复属性,而不是调用 __init__

如果您需要在数据库加载实例准备好使用之前对其进行一些设置,有一个称为InstanceEvents.load() 的事件挂钩可以实现此目的;它也可以通过名为orm.reconstructor() 的特定于类的装饰器获得。当使用orm.reconstructor() 时,映射器将在每次加载或重构类的实例时调用不带参数的修饰方法。这对于重新创建通常在 __init__ 中分配的瞬态属性很有用

因此,如果我对您的理解正确,您可以为填充非 ORM 字段的Interaction 定义一个重构器:

from sqlalchemy.orm import reconstructor

class Interaction(Base):

    __tablename__ = 'interactions'

    # Mirror the table's structure
    anomaly_id = Column(Integer, ForeignKey('anomalies.id'), primary_key=True)
    user_id = Column(Integer, primary_key=True) # ForeignKey('users.id'),
    feedback_score = Column(Integer)

    # myScoreUpdater is another (non-ORM) object I want this instance to be aware of
    @reconstructor
    def init_on_load(self):
        # Do what you must to populate score updater
        self.myScoreUpdater =  ...

请注意,您可能希望在重构器和__init__ 之间共享逻辑,所以要么将__init__ 装饰为重构器,如果它可以在没有参数的情况下调用,或者将分数更新器的初始化移动到一个方法.

最后,如果您的 ScoperUpdater 实际上不需要知道它绑定到哪个实例,您可以将其作为所有实例之间共享的类属性——就像 Java 中的静态属性一样。

【讨论】:

  • 谢谢伊利亚。我认为阻止我的部分是“(调用装饰方法)没有参数”。我需要一个支持这种签名的重构器:init_on_load(self, myScoreUpdater)
  • 我认为您的评论和答案的最后一句话可能是最好的建议:我应该尝试重新考虑我的整体架构
猜你喜欢
  • 2018-07-08
  • 2015-12-08
  • 1970-01-01
  • 2011-10-30
  • 2019-06-20
  • 2013-08-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多