【发布时间】:2018-07-20 00:56:48
【问题描述】:
问题
在同一会话中,删除一个对象后,会话中包含或指向该已删除对象的其他对象的关系属性不会更新。简而言之:
sesion.add(a, b)
a.parent = b
print(a.parent) # b
session.delete(b)
print(a.parent) # b
完整的、可重现的示例如下。
材质
我已经详细阅读了 SQLA 文档,包括:
- 'deleting from collections' 上的误导部分。误导,因为它使您认为删除后缺少更新仅限于集合。下面的例子表明它不是。
- cascades 上的部分,尤其是“删除孤儿”。这不是我正在寻找的,因为我不希望所有删除关系来删除相关对象。
可能的解决方案
可以使用session.expire() 手动将单个对象甚至单个对象属性设置为重新加载。我认为 ORM 负责完成这项工作:-)
问题
- 我错过了一个简单的解决方案吗?
- 我是否错过了文档中明确编写和解释的地方? (我花了很长时间缩小问题范围)
- SQLAlchemy 不/不能标记更新关联到已删除对象的关系是否有原因?
代码示例
SQLA 设置
from sqlalchemy import create_engine, Table, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker
engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
模型定义
class Country(Base):
__tablename__ = 'countries'
id = Column(Integer(), primary_key=True)
name = Column(String(255))
def __repr__(self):
return '<Country {} [{}]>'.format(self.name, self.id)
class Capital(Base):
__tablename__ = 'capitals'
id = Column(Integer(), primary_key=True)
name = Column(String(255))
country_id = Column(Integer(), ForeignKey(Country.id), unique=True)
country = relationship('Country', backref=backref('capital', uselist=False))
def __repr__(self):
return '<Capital {} [{}]>'.format(self.name, self.id)
Base.metadata.create_all(engine)
测试
# Creating both objects
us = Country(name="USA")
ny = Capital(name="NYC")
session.add(us)
session.add(ny)
session.commit()
print("\n### 1. Creating the relation:")
# Loading relations:
print("## us.capital: ", us.capital)
print("## ny.country: ", ny.country)
# Creating the relation:
us.capital = ny
# Checking that it's upated on the other side:
print("## ny.country (after rel creation): ", ny.country)
# Saving
session.commit()
print("\n### 2. Deleting relation:")
# Loading relations:
print("## us.capital: ", us.capital)
print("## ny.country: ", ny.country)
# Deleting one object of the relation:
us.capital = None
# The relation from the other side are updated accordingly
print("## ny.country (after rel deletion): ", ny.country)
# Rolling back
session.rollback()
print("\n### 3. Deleting one object:")
# Loading relations:
print("## us.capital: ", us.capital)
print("## ny.country: ", ny.country)
# Deleting one object of the relation:
session.delete(us)
# The relations are not updated!
print("## ny.country (after deletion of us): ", ny.country)
# Flushing doesn't change anything (undersantably so)
session.flush()
print("## ny.country (+ flush): ", ny.country)
# Expiring manually
session.expire(ny, ['country'])
# Looks okay
print("## ny.country (+ expire): ", ny.country)
# Rolling back
session.rollback()
print("\n### 4. Deleting the other object:")
# Loading relations:
print("## us.capital: ", us.capital)
print("## ny.country: ", ny.country)
# Deleting one object of the relation:
session.delete(ny)
# The relations are not updated!
print("## us.capital (after deletion of ny): ", us.capital)
# Flushing doesn't change anything (undersantably so)
session.flush()
print("## us.capital (+ flush): ", us.capital)
# Expiring manually
session.expire(us, ['capital'])
# Looks okay
print("## us.capital (+ expire): ", us.capital)
# Rolling back
session.rollback()
结果
### 1. Creating the relation:
## us.capital: None
## ny.country: None
## ny.country (after rel creation): <Country USA [1]>
### 2. Deleting relation:
## us.capital: <Capital NYC [1]>
## ny.country: <Country USA [1]>
## ny.country (after rel deletion): None
### 3. Deleting one object:
## us.capital: <Capital NYC [1]>
## ny.country: <Country USA [1]>
## ny.country (after deletion of us): <Country USA [1]>
## ny.country (+ flush): <Country USA [1]>
## ny.country (+ expire): None
### 4. Deleting the other object:
## us.capital: <Capital NYC [1]>
## ny.country: <Country USA [1]>
## us.capital (after deletion of ny): <Capital NYC [1]>
## us.capital (+ flush): <Capital NYC [1]>
## us.capital (+ expire): None
【问题讨论】:
标签: python orm sqlalchemy