- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当字段设置为不可为 nullable 时,我尝试使用 session.merge(object)
更新记录,并且使用 sqlalchemy 和服务器默认设置。当它尝试更新现有记录时,会抛出一个错误,表明违反了非空约束。我能够通过从表初始化中的记录中删除空值来解决这个问题,但这看起来很奇怪。这是预料之中的,还是我不明白服务器默认值或 session.merge
是如何工作的?
Python 版本:3.6.8
sqlalchemy 版本:1.3.4
示例代码:
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class TestTable(Base):
__tablename__ = 'test_table'
id = sa.Column(sa.Integer, primary_key=True)
field = sa.Column(sa.String, default='Unknown', server_default=sa.text("'Unknown'"), nullable=False)
field2 = sa.Column(sa.Integer)
engine = sa.create_engine('postgresql://postgres@localhost/test')
Base.metadata.create_all(bind=engine)
session = sa.orm.sessionmaker(engine)()
record = {'id': 1, 'field': None, 'field2': 3}
session.merge(TestTable(**record))
session.commit()
session.merge(TestTable(**record))
session.commit()
抛出的错误:
IntegrityError: (psycopg2.errors.NotNullViolation) null value in column "field" violates not-null constraint
DETAIL: Failing row contains (1, null, 3).
[SQL: UPDATE test_table SET field=%(field)s WHERE test_table.id = %(test_table_id)s]
[parameters: {'field': None, 'test_table_id': 1}]
(Background on this error at: http://sqlalche.me/e/gkpj)
最佳答案
在第一次合并时,该行不存在,因此创建它:
record = {'id': 1, 'field': None, 'field2': 3}
session.merge(TestTable(**record))
...发出:
INSERT INTO test_table (id, field, field2) VALUES (%(id)s, %(field)s, %(field2)s)
{'id': 1, 'field': 'Unknown', 'field2': 3}
根据 the documentation ,Column
的 default
参数应用于 insert,这就是为什么您可以看到 None
已被替换的原因与插入语句一起发送的参数集中的 'Unknown'
。文档状态:
A scalar, Python callable, or
ColumnElement
expression representing the default value for this column, which will be invoked upon insert if this column is otherwise not specified in the VALUES clause of the insert.
...所以在这种情况下,“未指定”似乎应该解释为“不是无
”,因为您显然已经“指定”了记录<中的值
字典。与此相关的是,当您在不为任何属性提供任何值的情况下实例化一个实例时,这些属性已经隐式地持有 None
的值:
print(TestTable().field is None) # True
如果从列定义中删除 default=...
kwarg,即使您向 TestTable
构造函数提供了 field=None
,删除默认值后,该参数的值根本不会发送到数据库:
INSERT INTO test_table (id, field2) VALUES (%(id)s, %(field2)s)
{'id': 1, 'field2': 3}
在这种情况下,将触发服务器端默认值。因此,在刷新插入语句之前,SQLAlchemy 会将客户端默认为指定值的列的任何 None
值交换。
在第二次合并时,该行已存在于数据库中,因此合并实例的值将填充到代表数据库中已存在的行的实例上。在合并期间,该实例的 field
列的值从 'Unknown'
更改为 None
。此值更改意味着该字段的新值将作为 更新 查询的一部分发送到数据库。请注意,客户端或服务器端的默认值均不适用于更新语句。
UPDATE test_table SET field=%(field)s WHERE test_table.id = %(test_table_id)s
{'field': None, 'test_table_id': 1}
当我们尝试将 NOT NULL
列显式设置为 NULL
时,引发了 IntegrityError
。
关于python - 为什么 session.merge 在设置默认值和 server_default 时行包含 null 时抛出 IntegrityError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58549937/
我有两个管理员和角色表,通过第三个表 assignments(多对多关系)与字段 role_id、administrator_id 和一些额外的字段 created_at 和 updated_at,我
使用 default 时是否有性能优势(或劣势)而不是 server_default用于在将 SQLAlchemy 与 PostgreSQL 一起使用时映射表列默认值? 我的理解是 default 呈
我想使用 alembic 运行从 sqlalchemy 模型到另一个模型的迁移。初始模型如下所示: from sqlalchemy.dialects.postgresql import JSONB f
这是我希望 SQLAlchemy 做的事情: blesk_dev=# alter table address add column reg_at timestamp without time zone
我有一个 MySQL 集列,我使用 sqlalchemy.dialects.mysql.SET 来描述我想设置 server_default arg 到包含两个值的集合。我正在寻找这样的东西: fro
当字段设置为不可为 nullable 时,我尝试使用 session.merge(object) 更新记录,并且使用 sqlalchemy 和服务器默认设置。当它尝试更新现有记录时,会抛出一个错误,表
我的模型(之前)包含客户端默认值: created_ts = db.Column(db.DateTime(timezone=True), default=dt.datetime.now) 我的模型(之
我是一名优秀的程序员,十分优秀!