为了账号安全,请及时绑定邮箱和手机立即绑定

如何防止sqlalchemy中的相关对象持久化?

如何防止sqlalchemy中的相关对象持久化?

明月笑刀无情 2022-06-22 18:18:10
环境:蟒蛇3.7SqlAlchemy 1.3.10(我也在 1.2.16 上测试过,结果相同)PostgreSQL 11TL,DR:我有一个表和一个 1-1“相关”物化视图(没有 fk,关系在 sql 端是隐式的)。在 SQLAlchemy 中,这种关系被声明为viewonly=True. 但是,如果我分配给它,会话无论如何都会尝试插入分配的 mat view 对象(显然,它失败了,因为它是一个物化视图)。是我误解了他们的目的viewonly还是没有正确建立关系?完整的可重现测试用例:使用 SQLalchemy 1.3.10 设置 python 3.7 venv创建一个新的(空的)postgresql 数据库将此代码示例保存在文件中并将 DB_URI 值更改为您刚刚创建的值python <path-to-script>在 env ( )中执行文件from __future__ import annotationsimport unittestfrom unittest import TestCaseimport sqlalchemy as safrom sqlalchemy.ext.declarative import declarative_base, DeclarativeMetafrom sqlalchemy.orm import relationship, backref, sessionmaker, object_sessioncreate_sql = """CREATE TABLE universe (   id SERIAL PRIMARY KEY,   name VARCHAR NOT NULL,   is_perfect BOOLEAN NULL DEFAULT 'f');CREATE MATERIALIZED VIEW answer AS (    SELECT        id,        trunc(random() * 100)::INT AS computed    FROM universe)"""Base: DeclarativeMeta = declarative_base()metadata = Base.metadataclass Universe(Base):    __tablename__ = 'universe'    id = sa.Column(sa.Integer, primary_key=True)    name = sa.Column(sa.String, nullable=False)    is_perfect = sa.Column(sa.Boolean, nullable=False, server_default='f')    answer: Answer = relationship('Answer',                                  backref=backref('universe', uselist=False),                                  innerjoin=False,                                  lazy='select',                                  uselist=False,                                  viewonly=True)    def set_perfect(self):        self.is_perfect = (self.answer.computed == 42)        session = object_session(self)        if session:            session.commit()
查看完整描述

1 回答

?
慕神8447489

TA贡献1780条经验 获得超1个赞

更新的答案:


对于 SQLAlchemy 1.3.10(我在此示例中使用的版本)及以下版本,修复方法是设置cascade与None或非持久性相关级联选项之一("expunge"或"refresh-expire"两者)的关系。False(默认)不起作用,因为它意味着"save-update, merge".


总结一下:


answer: Answer = relationship(

    'Answer',

    ...,

    viewonly=True,

    cascade=None  # or "expunge" or "refresh-expire" or "expunge,refresh-expire"

)

这确实是 1.3 及以下版本的错误,已在 1.3.11 和 1.4.22 之间的某个地方得到纠正。我所知道的是,没有指定的原始示例cascade在 1.4.22 中就像一个魅力。


查看完整回答
反对 回复 2022-06-22
  • 1 回答
  • 0 关注
  • 120 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信