python - SQLAlchemy - 如何映射只读(或计算)属性

标签 python properties sqlalchemy readonly

我正在尝试弄清楚如何映射到一个简单的只读属性,并在我保存到数据库时触发该属性。

一个人为的例子应该可以更清楚地说明这一点。首先,一个简单的表格:

meta = MetaData()
foo_table = Table('foo', meta,
    Column('id', String(3), primary_key=True),
    Column('description', String(64), nullable=False),
    Column('calculated_value', Integer, nullable=False),
    )

我想做的是设置一个具有只读属性的类,当我调用 session.commit() 时,它将为我插入到 calculated_value 列中...

import datetime
def Foo(object):  
    def __init__(self, id, description):
        self.id = id
        self.description = description

    @property
    def calculated_value(self):
        self._calculated_value = datetime.datetime.now().second + 10
        return self._calculated_value

根据 sqlalchemy 文档,我认为我应该这样映射:

mapper(Foo, foo_table, properties = {
    'calculated_value' : synonym('_calculated_value', map_column=True)
    })

问题在于,在您访问 calculated_value 属性之前,_calculated_value 为 None。看起来 SQLAlchemy 没有在插入数据库时​​调用该属性,所以我得到的是 None 值。正确的映射方法是什么,以便将“calculated_value”属性的结果插入到 foo 表的“calculated_value”列中?

好的 - 我正在编辑这篇文章以防其他人有同样的问题。我最终做的是使用 MapperExtension。让我给你一个更好的例子以及扩展的用法:

class UpdatePropertiesExtension(MapperExtension):
    def __init__(self, properties):
        self.properties = properties

    def _update_properties(self, instance):
        # We simply need to access our read only property one time before it gets
        # inserted into the database.
        for property in self.properties:
            getattr(instance, property)

    def before_insert(self, mapper, connection, instance):
        self._update_properties(instance)

    def before_update(self, mapper, connection, instance):
        self._update_properties(instance)

这就是您使用它的方式。假设您有一个具有多个只读属性的类,这些属性必须在插入数据库之前触发。我在这里假设对于这些只读属性中的每一个,您在数据库中都有一个相应的列,您希望用该属性的值填充该列。您仍然要为每个属性设置同义词,但是在映射对象时使用上面的映射器扩展:

class Foo(object):
    def __init__(self, id, description):
        self.id = id
        self.description = description
        self.items = []
        self.some_other_items = []

    @property
    def item_sum(self):
        self._item_sum = 0
        for item in self.items:
            self._item_sum += item.some_value
        return self._item_sum

    @property
    def some_other_property(self):
        self._some_other_property = 0
        .... code to generate _some_other_property on the fly....
        return self._some_other_property

mapper(Foo, metadata,
    extension = UpdatePropertiesExtension(['item_sum', 'some_other_property']),
    properties = {
        'item_sum' : synonym('_item_sum', map_column=True),
        'some_other_property' : synonym('_some_other_property', map_column = True)
    })

最佳答案

感谢您编辑您的回答,Jeff。我遇到了完全相同的问题并使用您的代码解决了它,对于那些使用声明性基础的人来说,这是类似的事情。查找如何指定映射器参数和同义词可能会节省您几分钟的时间:

from sqlalchemy.ext.declarative import declarative_base

class Users(Base):
  __tablename__ = 'users'

  id = Column(Integer, primary_key=True)
  name = Column(String)
  _calculated_value = Column('calculated_value', String)

  __mapper_args__ = {'extension': UpdatePropertiesExtension(['calculated_value'])}

  def __init__(self, name):
    self.name = name

  @property
  def calculated_value(self):
    self._calculated_value = "foobar"
    return self._calculated_value

  calculated_value = synonym('_calculated_value', descriptor=calculated_value)

关于python - SQLAlchemy - 如何映射只读(或计算)属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3020394/

相关文章:

用于 FTP 上传/下载的 Python 库?

c# - 更改继承的 .net 控件上属性的默认值

file - 执行上传时未定义的文件属性

java - 构建期间 Gradle NPE?

python - 如何将 Perl Map 函数转换为 Python?

python - Selenium 未加载 TikTok 页面

python - if comment.name == user 无法正常工作

python - OperationalError "unable to open database file"使用 SQLAlchemy 和 SQLite3 处理查询结果

python - Python 和 Google SQL Cloud 之间的接口(interface)问题

python - 如何在 SQLAlchemy 中的 python 中回滚 dataframe.to_sql?