使用SQLAlchemy多态关系删除整个层次结构

3

我想在 sqlalchemy 中删除一些具有多态关系的表中的元素。下面是模型:

class Employee(Base):
  __tablename__ = 'employee'
  id = Column(Integer, primary_key=True)
  name = Column(String(50))
  type = Column(String(50))

  __mapper_args__ = {
    'polymorphic_identity':'employee',
    'polymorphic_on':type
  }

class Engineer(Employee):
  __tablename__ = 'engineer'
  id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
  engineer_name = Column(String(30))

  __mapper_args__ = {
    'polymorphic_identity':'engineer',
  }

以下是我如何删除它的步骤:

e = Engineer();
e.name = "John";
e.engineer_name = "Doe";
DBSession.add(e);

q = session.query(Engineer).filter(Employee.name == "John")

q.delete(False)

我得到了以下错误,这是一个bug还是我的方法有问题?
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such
column: employee.name [SQL: u'DELETE FROM engineer WHERE employee.name
= ?'] [parameters: ('John',)]

我希望SQLAlchemy能够删除engineer和employee表中的条目。

应该是 q = session.query(Engineer).filter(Engineer.name == "John") 吗?(而不是 Employee.name - undefined
2个回答

5

首先,您应该定义此关系的删除行为:

id = Column(Integer, ForeignKey('employee.id', ondelete='CASCADE'), primary_key=True)

然后,使用ORM,您可以通过循环删除所有名为“John”的工程师:

eng_list = session.query(Engineer).filter(Employee.name == "John").all()

for eng in eng_list:
   session.delete(eng)
session.commit()

这将从EmployeeEngineer两个表中删除记录。 更新: 对错误信息进行评论:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such 
column: employee.name [SQL: u'DELETE FROM engineer WHERE employee.name
= ?'] [parameters: ('John',)]

你的尝试是从工程师表中通过与雇员表的连接(以访问Employee.name字段)进行删除。但是,这个连接在sqlalchemy发出的查询中丢失了。
我认为SQLite不支持使用连接进行删除。也许您可以尝试在不同的后端上运行`session.query(Engineer).filter(Employee.name == "John").delete()`,并且sqlalchemy可能能够发出正确的SQL语句。不过,我没有尝试过。
更新2:对于遵循外键约束的后端(并且已将onupdate约束设置为级联),仅删除父行中的行即可自动删除子链接行。
我已经尝试了MySQL和Postgresql后端,并且以下查询从两个表(employee和engineer)中都删除了行:
session.query(Employee).filter(Employee.name=='John').delete()

由于某些原因,在Sqlite上,这仅会从employee中删除记录。

0

因为直接不支持执行联合DELETE操作,我找到了一个简单的解决方法,就是使用普通的联合查询来选择要删除的id,然后将这些id传递给一个单独的DELETE查询。

一个小麻烦是,由于返回的id是整数,如果你尝试直接将这些id(实际上是一个元组数组)传递给DELETE查询,很可能会遇到这个错误,就像我遇到的一样。简单地将其转换为字符串即可解决这个问题。

所以总结起来:

ids_to_delete = session.query(Engineer.id). \
    filter(Employee.name == "John"). \
    all()

# Convert the resulting int tuples to simple strings:
id_strings = [str(id_[0]) for id_ in ids_to_delete]

session.query(Engineer). \
    filter(Engineer.id.in_(id_strings)). \
    delete(synchronize_session=False)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接