簡體   English   中英

使用 `sqlalchemy` `insert` 批量插入相關對象

[英]Using `sqlalchemy` `insert` to bulk insert related objects

我正在使用 sqlalchemy 將數據插入表中。 我關心的事情:

  • 我希望插入大量數據,因此希望最大限度地減少數據庫執行次數。
  • 會有重復的條目,這是意料之中的,所以我將使用on_conflict_do_nothing (我正在使用 postgres)。

作為一個最小的例子,假設我有兩個表:

from sqlalchemy import Column, Integer, ForeignKey, String

Base = declarative_base()


class Address(Base):
    __tablename__ = "addresses"
    id = Column(Integer, primary_key=True)
    street = Column(String)
    number = Column(Integer)

class Person(Base)
    __tablename__ = "people"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    address_id = Column(Integer, ForeignKey("addresses.id")
    address = relationship("Address")

我可以通過以下方式輕松地批量處理所有Address插入:

from sqlalchemy.dialects.postgresql import insert
values = [{"street": "main", "number": 1}, {"street": "main", "number": 2}]
statement = insert(Address).values(values).on_conflict_do_nothing()
session.execute(statement)

問題是我如何對People做同樣的事情? 我正在為"address"提供什么而苦苦掙扎,例如

values = [{"name": "John", "address": ????}]
statement = insert(Person).values(values).on_conflict_do_nothing()
session.execute(statement)

我假設我需要Address object 但是我不知道 go 從那里到哪里?

不要使用address ,因為它不是 SQL 字段。 您可以使用INSERT...RETURNING來獲取您剛剛插入的地址的 ID,然后在此基礎上設置values[0]['address_id'] 像這樣的東西應該工作:

from sqlalchemy.dialects.postgresql import insert
values = [{"street": "main", "number": 1}, {"street": "main", "number": 2}]
statement = insert(Address)\
    .values(values)\
    .returning(Address.id)\
    .on_conflict_do_nothing()
address_ids = [address_id for address_id, in session.execute(statement)]

values = [{"name": "John", "address_id": address_ids[0]}]
statement = insert(Person).values(values).on_conflict_do_nothing()
session.execute(statement)

解釋

使用insert().on_conflict_do_nothing ,與 SQLAlchemy 的添加層相比,您將相對接近 PostgreSQL 的裸機。 這不是一件壞事,當然是你控制最多、提速最大的地方,但這確實意味着你需要仔細考慮SQLAlchemy添加了哪些字段,哪些字段直接反映在ZD233B99A3CCB7F38A032466289B6D227數據庫。

在您的情況下,只有idnameaddress_id是實際的數據庫列。 如果您執行SELECT * FROM people ,它們是唯一應該顯示的列。 相反, address是由 SQLAlchemy 添加的,以便為您提供指向 ID 為address_idAddress實例的直接鏈接,但在水下,如果需要,將對數據庫執行不同的調用以獲取它。

如果你有一個 id 為 1 的Address ,那么設置john.address = 1不起作用,因為 1 不是地址,它是一個數字。 但是,設置john.address_id = 1確實有效,因為您直接設置了一個字段。 如果您使用完整的 ORM(您不是),SQLAlchemy 不鼓勵這樣做,因為您在他們的生態系統之外執行此操作。 如果運行john.address = Address.query.get(1) ,則將整個地址 object 分配給地址,並且 SQLAlchemy 在內部將address_id更新為 1。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM