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 条目的主要内容,如果未能解决你的问题,请参考以下文章

如何将值插入到python中的嵌套表中?

将值插入到存在于多个数据库中的表中

将值插入到从父表引用的子表中

我可以在存储过程中使用 if 语句将值插入到表中吗?

在 Oracle 中,我可以执行“将值插入或更新到表中”吗

mysql将值插入表中?