SQLAlchemy 将值插入到反射表中会导致所有的 NULL 条目
Posted
技术标签:
【中文标题】SQLAlchemy 将值插入到反射表中会导致所有的 NULL 条目【英文标题】:SQLAlchemy insert values into reflected table results in NULL entries all across 【发布时间】:2021-06-12 04:28:52 【问题描述】:以下代码在每次尝试中都会跨行生成 None ()。下面的query.values()
代码只是一个缩短的行,以使事情不那么复杂。此外,我在地址字段中插入 dict 作为 JSON 时遇到问题,但这是另一个问题。
CREATE TABLE public.customers (
id SERIAL,
email character varying(255) NULL,
name character varying(255) NULL,
phone character varying(16) NULL,
address jsonb NULL,
shipping jsonb NULL,
currency character varying(3) NULL,
metadata jsonb[] NULL,
created bigint NULL,
uuid uuid DEFAULT uuid_generate_v4() NOT NULL,
PRIMARY KEY (uuid)
);
from sqlalchemy import *
from sqlalchemy.orm import Session
# Create engine, metadata, & session
engine = create_engine('postgresql://postgres:password@database/db', future=True)
metadata = MetaData(bind=engine)
session = Session(engine)
# Create Table
customers = Table('customers', metadata, autoload_with=engine)
query = customers.insert()
query.values(email="test@test.com", \
name="testy testarosa", \
phone="+12125551212", \
address='"city": "Cities", "street": "123 Main St", \
"state": "CA", "zip": "10001"')
session.execute(query)
session.commit()
session.close()
# Now to see results
stmt = text("SELECT * FROM customers")
response = session.execute(stmt)
for result in response:
print(result)
# Results in None in the fields I explicitly attempted
(1, None, None, None, None, None, None, None, 1, None, None, None, None, UUID('9112a420-aa36-4498-bb56-d4129682681c'))
【问题讨论】:
【参考方案1】:调用query.values()
会返回一个新的insert 实例,而不是就地修改现有实例。这个返回值必须赋给变量,否则无效。
您可以迭代地构建插入
query = customers.insert()
query = query.values(...)
session.execute(query)
或链接调用Karolus K.在他们的answer中建议。
query = customers.insert().values(...)
关于 address
列,您正在插入一个已经序列化为 JSON 的字典。这个值在插入过程中再次被序列化,所以数据库中的值最终看起来像这样:
test# select address from customers;
address
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
"\"city\": \"Cities\", \"street\": \"123 Main St\", \"state\": \"CA\", \"zip\": \"10001\""
(1 row)
并且不适合作为 JSON 对象进行查询(因为它是 JSON 化的 字符串)
test# select address->'state' AS state from customers;
state
═══════
¤
(1 row)
您可能会发现传递原始 dict 会更好,从而将该值存储在数据库中:
test# select address from customers;
address
════════════════════════════════════════════════════════════════════════════
"zip": "10001", "city": "Cities", "state": "CA", "street": "123 Main St"
(1 row)
可以作为 JSON 对象进行查询:
test# select address->'state' AS state from customers;
state
═══════
"CA"
(1 row)
【讨论】:
你知道我试过了,但只是在session.add(query)
之后导致Class 'sqlalchemy.sql.dml.Insert' is not mapped
- 没有意识到跳过session.add()
使其工作。那么我该如何session.add_all(queries)
并避免...Insert is not mapped
错误呢? (批量/多次插入)
session.add(query)
-> 这是没有意义的,session.add
需要一个 ORM 模型实例,但是您将核心查询的结果传递给它。【参考方案2】:
我不知道你是什么意思
下面的 query.values() 代码只是缩短了一行,以便保持 事情不那么复杂。
所以也许我没有正确理解这个问题。
无论如何,这里的问题是您分别执行insert()
和values()
,而它的本意是“链式”。
做类似的事情:
query = customers.insert().values(email="test@test.com", name="testy testarosa", phone="+12125551212", address='"city": "Cities", "street": "123 Main St", "state": "CA", "zip": "10001"')
会起作用的。
文档:https://docs.sqlalchemy.org/en/14/core/selectable.html#sqlalchemy.sql.expression.TableClause.insert
PS:我也没有遇到 JSON 字段的任何问题。也许是 PG 版的?
【讨论】:
我的意思是我没有插入所有值(货币、创建等),而只是插入了“电子邮件”、“姓名”、“电话”和“地址”。以上是关于SQLAlchemy 将值插入到反射表中会导致所有的 NULL 条目的主要内容,如果未能解决你的问题,请参考以下文章