【问题标题】:How to get original value of SQLAlchemy custom type?如何获取 SQLAlchemy 自定义类型的原始值?
【发布时间】:2017-08-12 06:28:38
【问题描述】:

简而言之我的问题:是否可以在 SQLAlchemy 中访问自定义类型的原始值?

我对自定义类型的实现:

class JSONDocument(TypeDecorator):
    # override field
    impl = JSON

    # Write
    def process_bind_param(self, value, dialect):
        if value is not None:
            req = requests.post(url, data=json.dumps({'data': value}))
            uri = req.json()['uri']
            value = uri
        return value

    # Read
    def process_result_value(self, value, dialect):
        if value is not None:
            uri = value
            req = requests.get(uri)
            value = req.json()['data']
        return value

我的桌子模型:

class SomeTable(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    # The column with large json data
    json_data = db.Column(JSONDocument)

每当我尝试更新或插入一行,结果将写入json_data 列时,SQLAlchemy 将调用JSONDocumentprocess_bind_param。然后它会执行一个 POST API 调用,在我的 NoSQL 表中创建一个新的数据条目,并将我的 SQL 表中的 json_data 列更新为返回的 URI。

每当我尝试访问 json_data 列时,它都会对存储在我的 SQL 表中的 URI 执行 GET API 调用,并返回存储在我的 NoSQL 表中的实际 JSON 数据。

我的问题:如何获取存储在JSONDocument 覆盖的SQL 表中的URI?每当我更新 json_data 时,我都想对旧 URI 执行 DELETE API 调用。

我已经尝试使用 SQLAlchemy 的 Mapping 事件回调,但我仍然无法获取自定义类型背后的 URI。

如果我的问题问得不够清楚,请告诉我。任何建议或想法表示赞赏。

我正在尝试做的任务的总结:

我有一个包含以下列的 Postgresql 数据库 (RDS) 表:id(int)、json_data(string)、other_columns...

由于json_data 列占用了太多存储空间,我正在努力将该列中的数据移动到其他 NoSQL 数据库 (DynamoDB)。我实现了一个 RESTful API 服务器,用于在我的 NoSQL 表中更新、插入和软删除数据。

我想实现一个 SQLAlchemy 自定义类型,当我的应用尝试访问其他 Python 代码中的 json_data 列时,它会自动调用我的 API 方法。

【问题讨论】:

  • 你的意思是在读取过程中沿着值返回uri吗?
  • 不完全,我只想要常规读取期间的值。通过常规阅读,我的意思是result = SomeTable.query.first().json_data。我在问是否有result.raw_value之类的东西,以便我可以获取自定义类型后面的URI。
  • 有多种方法可以解决这个问题,但没有“内置”解决方案,因为流程绑定和流程结果都是由您编写的。第一 - 你可以使用“self.uri = value”代替“uri = value”,而不是“req = requests.get(uri)”使用“req = requests.get(self.uri)”。这样 uri 应该可以通过“result.uri”访问。第二种选择是通过 session.execute() 使用纯 SQL。或者你甚至可以创建另一个继承自 JSONDocument 的类,然后再次覆盖 process_result_value :)
  • @PeterMajko 非常感谢您的建议!我实际上确实尝试了第一种方法,但似乎每个自定义类型实例共享相同的JSONDocument 实例,因为当我更新一行json_data 的“self.uri”时,其他行的“self.uri” ' json_data 也将更新为相同的内容。你能详细说明你提到的最后一种方法吗?或者是否有任何文件或文章我可以查看它是如何工作的?谢谢!
  • 当我写我之前的评论时,我无法尝试。现在我到了电脑,不幸的是我的“想法”是错误的。对不起。因为当您访问 SameTable.json_data 时,它已经提供了数据类型实例而不是 TypeDecorator 一个。你可以使用类似“返回值,uri”的东西,然后当你访问 some_table_instance.json_data[0] 你得到你的 JSON 和 some_table_instance.json_data[1] 你得到 uri。这样合适吗?

标签: python sqlalchemy


【解决方案1】:

您是否考虑过摆脱自定义 TypeDecorator 并将您的逻辑移动到类似于使用属性的 SomeTable?

class SomeTable(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    # The column with large json data
    _uri = db.Column(db.JSON)

    @property
    def json_data(self):
        if self._uri is not None:
            req = requests.get(self._uri)
            return req.json()['data']
        else:
            return None

    @json_data.setter
    def json_data(self, value):
        req = requests.post(url, data=json.dumps({'data': value}))
        self._uri = req.json()['uri']

    @property
    def uri(self):
        return self._uri

【讨论】:

  • 哇。使用属性效果很好!令人惊讶的是,我们用来读写属性和列的代码完全相同(如果这不是真的,请告诉我)。我将不得不进行一些单元测试以确保一切正常。非常感谢您的建议! :)
猜你喜欢
  • 2019-05-17
  • 2015-08-26
  • 2011-02-22
  • 2014-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多