带有空列的SQLAlchemy批量插入

时间:2015-10-29 10:32:06

标签: python postgresql sqlalchemy

我使用Session.bulk_insert_mappings()来插入多个实体,但是当实体有None个值时,我遇到了问题。

以下批量插入工作正常,单个插入语句用于插入所有实体:

session.bulk_insert_mappings(Document, [
    dict(document_id=1, version=1, colA=True, colB='a'),
    dict(document_id=2, version=1, colA=True, colB='b'),
    dict(document_id=3, version=1, colA=True, colB='c')
])

但是当其中一个字段为None时,SQLAlchemy会在多个语句中拆分插入内容:

session.bulk_insert_mappings(Document, [
    dict(document_id=1, version=1, colA=True, colB='a'),
    dict(document_id=2, version=1, colA=True, colB=None),
    dict(document_id=3, version=1, colA=True, colB='c')
])

日志:

INFO  [...] INSERT INTO api.documents (...) VALUES (...)
INFO  [...] {'colA': True, 'colB': 'a', 'version': 1, 'document_id': 1}
INFO  [...] INSERT INTO api.documents (...) VALUES (...)
INFO  [...] {'colA': True, 'version': 1, 'document_id': 2}
INFO  [...] INSERT INTO api.documents (...) VALUES (...)
INFO  [...] {'colA': True, 'colB': 'c', 'version': 1, 'document_id': 3}

我尝试将None替换为null(),但后来我收到以下错误"无法调整类型' Null'" :

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'Null' [SQL: 'INSERT INTO api.documents (...) VALUES (...)'] [parameters: ({'colB': 'a', 'colA': True, 'version': 1, 'document_id': 1}, {'colB': <sqlalchemy.sql.elements.Null object at 0x7f74679c0190>, 'colA': True, 'version': 1, 'document_id': 2}, {'colB': 'c', 'colA': True, 'version': 1, 'document_id': 3})]

即使某些实体的值为None,如何确保使用单个插入语句?

编辑:映射如下所示:

class Document(Base):
    __tablename__ = 'documents'

    document_id = Column(Integer, primary_key=True)
    version = Column(Integer, nullable=False, server_default='1')
    colA = Column(Boolean)
    colB = Column(Integer)

1 个答案:

答案 0 :(得分:2)

遵循SQLAlchemy文档http://docs.sqlalchemy.org/en/latest/orm/persistence_techniques.html

  

如果我们希望能够使用Python值而无法使用它   尽管存在列默认值,我们也可以保持为NULL   可以使用Core级修饰符为ORM配置此项   TypeEngine.evaluates_none(),表示ORM的类型   应该将值与任何其他值相同并传递它   通过,而不是将其省略为“缺失”值:

class MyObject(Base):
    __tablename__ = 'my_table'
    id = Column(Integer, primary_key=True)
    data = Column(
      String(50).evaluates_none(),  # indicate that None should always be passed
      nullable=True, server_default="default")

obj = MyObject(id=1, data=None)
session.add(obj)
session.commit()  # INSERT with the 'data' column explicitly set to None;
                  # the ORM uses this directly, bypassing all client-
                  # and server-side defaults, and the database will
                  # persist this as the NULL value

这可能解决了你的问题。