【问题标题】:How to insert a nil_uuid in Postgres, using SQLAlchemy?如何使用 SQLAlchemy 在 Postgres 中插入 nil_uuid?
【发布时间】:2021-03-07 14:33:26
【问题描述】:

使用 Python 和 SQLAlchemy,是否可以在链接到主键的 Postgresql 外键列中插入 None / NIL_UUID / NULL 值,两者都存储为 UUID?

  • None 返回column none does not exist
statement = "INSERT INTO tb_person (pk_person, first_name, last_name, fk_person_parent) VALUES ('9ce131...985
fea06', 'John', 'Doe', None)"
parameters = {}, context = <sqlalchemy.dialects.postgresql.psycopg2.PGExecutionContext_psycopg2 object at 0x7fbff5ea2730>

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       psycopg2.errors.UndefinedColumn: column "none" does not exist
E       LINE 1: '9ce131...985','John', 'Doe', None)
E                                             ^
E       HINT:  Perhaps you meant to reference the column "tb_person.last_name".

../../.local/share/virtualenvs/project/lib/python3.8/site-packages/sqlalchemy/engine/default.py:593: UndefinedColumn
  • NIL_UUID(即用 0 组成的有效 UUID)返回 psycopg2.errors.ForeignKeyViolation
E       psycopg2.errors.ForeignKeyViolation: insert or update on table "tb_person" violates foreign key constrain
t "tb_person_fk_person_parent_fkey"
E       DETAIL:  Key (fk_person_parent)=(00000000-0000-0000-0000-000000000000) is not present in table "tb_person
".

更多详情

我使用 SQLAlchemy 经典映射(SQLAlchemy Core),我的表是这样定义的:

tb_person = Table(
    "tb_person",
    metadata,
    Column(
        "pk_person",
        UUID(as_uuid=True), 
        default=uuid.uuid4,
        unique=True,
        nullable=False
    ),
    Column("first_name", String(255)),
    Column("last_name", String(255)),
    Column(
        "fk_person_parent", UUID(as_uuid=True),
        ForeignKey("tb_person.pk_person"),
        nullable=True
    )
)

映射器是这样定义的:

    client_mapper = mapper(
        domain.model.Person,
        tb_person,
        properties={
            "child": relationship(domain.model.Person),
        },
    )

在 pk_person 字段中插入数据库中已存在的 UUID 时,单元测试运行良好。

【问题讨论】:

  • 可以在FOREIGN KEY 字段中设置INSERT NULL 值。您的NIL_UUID 值不是NULL,因此它需要在引用表的PRIMARY KEY 中输入一个条目。
  • @AdrianKlaver 谢谢,你用我所做的较短的术语提出了我的问题。当 None 和 NIL_UUID 都不起作用时,如何在 UUID 字段中插入 NULL?
  • 您实际上并没有传入None,而是传入了被视为列名的“None”。如果fk_person_parent 允许NULL 则不要在INSERT 中包含该字段,并且将为该值设置NULL。您确实应该使用参数来传递值,然后None 将正确适应INSERT 上的NULL
  • 从 psycopg2 回溯中,该语句显示为“INSERT INTO tb_person (pk_person, first_name, last_name, fk_person_parent) VALUES ('9ce131...985fea06', 'John', 'Doe', None)" -它在查询中被插入为 None (而不是“None”),但谢谢我会使用参数再试一次。
  • 是的,但是错误 psycopg2.errors.UndefinedColumn: column "none" does not exist 显示,因为它在一个字符串中,所以它被双引号引起来,并被误认为是一个标识符(在这种情况下是一列)。这也是它被装箱的原因。

标签: python postgresql sqlalchemy


【解决方案1】:

我使用的是原始 SQL,正如 @AdrianKlaver 所建议的,最好使用参数 - 它可以解决问题。

# In the context of this unit test,
# we have to handle UUID generation here
uuid_1 = uuid.uuid4()
uuid_2 = uuid.uuid4()
uuid_3 = uuid.uuid4()

session.execute(
"""
INSERT INTO tb_person
(pk_person, first_name, last_name, fk_parent_person) 
VALUES
(:uuid_1, 'John', 'Doe', :uuid_none),
(:uuid_2, 'Jean', 'Dupont', :uuid_none)
(:uuid_3, 'Baby', 'Doe', :uuid_1)
""",
 {"uuid_1": uuid_1, "uuid_2", "uuid_3": uuid_3, ":uuid_none": None}
)

它在查询中有效地转换为 NULL。

【讨论】:

    猜你喜欢
    • 2019-11-24
    • 2017-11-15
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 2021-08-11
    • 2023-03-26
    • 1970-01-01
    • 2021-12-17
    相关资源
    最近更新 更多