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

环境

  • 蟒蛇3.7

  • SqlAlchemy 1.3.10(我也在 1.2.16 上测试过,结果相同)

  • PostgreSQL 11


TL,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 annotations


import unittest

from unittest import TestCase


import sqlalchemy as sa

from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

from sqlalchemy.orm import relationship, backref, sessionmaker, object_session


create_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.metadata



class 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()



明月笑刀无情
浏览 155回答 1
1回答

慕神8447489

更新的答案:对于 SQLAlchemy 1.3.10(我在此示例中使用的版本)及以下版本,修复方法是设置cascade与None或非持久性相关级联选项之一("expunge"或"refresh-expire"两者)的关系。False(默认)不起作用,因为它意味着"save-update, merge".总结一下:answer: Answer = relationship(&nbsp; &nbsp; 'Answer',&nbsp; &nbsp; ...,&nbsp; &nbsp; viewonly=True,&nbsp; &nbsp; cascade=None&nbsp; # or "expunge" or "refresh-expire" or "expunge,refresh-expire")这确实是 1.3 及以下版本的错误,已在 1.3.11 和 1.4.22 之间的某个地方得到纠正。我所知道的是,没有指定的原始示例cascade在 1.4.22 中就像一个魅力。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python