SQLAlchemy 的更新和表继承问题

qua*_*ben 6 python sql sqlite inheritance sqlalchemy

我正在构建一个如下所示的继承表架构:

规格代码

class Person(Base):
    __tablename__ = 'people'
    id = Column(Integer, primary_key=True)
    discriminator = Column('type', String(50))
    updated = Column(DateTime, server_default=func.now(), onupdate=func.now())
    name = Column(String(50))
    __mapper_args__ = {'polymorphic_on': discriminator}

class Engineer(Person):
    __mapper_args__ = {'polymorphic_identity': 'engineer'}
    start_date = Column(DateTime)

class Manager(Person):
    __mapper_args__ = {'polymorphic_identity': 'manager'}
    start_date = Column(DateTime)
Run Code Online (Sandbox Code Playgroud)

更新(工作)代码

import os
import sys

from sqlalchemy import Column, create_engine, ForeignKey, Integer, String, DateTime

from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base


try:
   os.remove('test.db')
except FileNotFoundError:
   pass 

engine = create_engine('sqlite:///test.db', echo=True)
Session = sessionmaker(engine)

Base = declarative_base()


class People(Base):
    __tablename__ = 'people'
    discriminator = Column('type', String(50))
    __mapper_args__ = {'polymorphic_on': discriminator}

    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    updated = Column(DateTime, server_default=func.now(), onupdate=func.now())

class Engineer(People):
    __tablename__ = 'engineer'
    __mapper_args__ = {'polymorphic_identity': 'engineer'}
    id = Column(Integer, ForeignKey('people.id'), primary_key=True)
    kind = Column(String(100), nullable=True)

Base.metadata.create_all(engine)

session = Session()

e = Engineer()
e.name = 'Mike'
session.add(e)
session.flush()
session.commit()

# works when updating the object
e.name = "Doug"
session.add(e)
session.commit()


# works using the base class for the query
count = session.query(People).filter(
                           People.name.is_('Doug')).update({People.name: 'James'})

# fails when using the derived class
count = session.query(Engineer).filter(
                           Engineer.name.is_('James')).update({Engineer.name: 'Mary'})

session.commit()
print("Count: {}".format(count))
Run Code Online (Sandbox Code Playgroud)

注意:这是来自sql docs 的稍微修改的示例

如果我尝试更新name工程师的两件事情应该发生。

  1. 列上 People 表的更新语句 name
  2. 自动触发更新updatedPeople 表上的列

现在,我想专注于数字 1。像下面的示例(也记录在完整代码示例中)之类的事情将导致无效的 SQL

session.query(Engineer).filter(
                           Engineer.name.is_('James')).update({Engineer.name: 'Mary'})
Run Code Online (Sandbox Code Playgroud)

我相信上面会产生以下内容:

更新工程师 SET name=?, updated=CURRENT_TIMESTAMP FROM people WHERE people.name IS ?

再次,这是无效的。该语句试图更新不正​​确表中的行。 name位于基表中。

我有点不清楚继承表应该如何工作,但似乎更新应该与派生对象透明地工作。意思是,当我更新Engineer.nameEngineerSQLAlchemy 应该知道更新People表的对象的查询时。更复杂的是,如果我尝试更新两个表中存在的列会发生什么

session.query(Engineer).filter(
                           Engineer.name.is_('James')).update({Engineer.name: 'Mary', Engineer.start_date: '1997-01-01'})
Run Code Online (Sandbox Code Playgroud)

我怀疑 SQLAlchemy 不会发出两个更新语句。