【问题标题】:Deleting an Object from Collection in SQLAlchemy从 SQLAlchemy 中的集合中删除对象
【发布时间】:2012-04-30 04:22:05
【问题描述】:

我将一堆专利数据存储在 MySQL 数据库中,并通过 SQLAlchemy 与之交互。我在 Patent 类中有一个集合,代表受让人(被分配专利的公司)列表:

assignees = relationship('Company', secondary=patent_company_table, backref='patents')

我正在处理存储在数据库中的一些对象,对于专利对象p,我想从p 的受让人列表中删除一些受让人a(公司对象)。基于http://docs.sqlalchemy.org/en/latest/orm/session.html#deleting-from-collections,调用s.delete(a) 似乎实际上会删除公司对象a。我只是想从p 的受让人列表中删除受让人a(即删除patent_company_table 中的一行),而不是实际删除公司对象,因为a 可能在另一个专利对象的受让人列表中。

我尝试创建一个新列表new_assignees,其中仅包括来自p 的受让人除了a,然后调用:

p.assignees = new_assignees
s.add(p)

不幸的是,这实际上并没有将p 标记为脏,所以我认为它不会影响数据库。

您对如何从集合中删除对象有什么建议吗?删除patent_company_table 中的行而不是从Company 表中删除对象?

谢谢。

更新

这是一个sn-p的代码:

assignees = patent.assignees
for assignee in assignees:
    if assignee in duplicate_company_to_default:
        patent.assignees.remove(assignee)
        default_company = duplicate_company_to_default[assignee]
        if default_company not in assignees:
            added_patent_count += 1
            patent.assignees.append(default_company)

遍历所有专利后,added_patent_count = 983672session.dirty() 中没有对象。通过appendremove修改后是否需要手动添加到会话中?

【问题讨论】:

  • 您能否提取并发布此问题的工作示例脚本(模型定义、示例重复字典等)?还想知道您使用的是什么类型的 PrimaryKey 标识符?

标签: python mysql sqlalchemy


【解决方案1】:

SQLAlchemy 集合支持类似列表的追加/删除操作。

p.assignees.remove(c)

这应该从p.assignees 中删除c 而不会从数据库中删除c

【讨论】:

  • 感谢您的建议,但这并不能解决问题。我在上面包含了一个代码 sn-p。
  • 这工作正常。 s.dirty 的长度为 0,但 s.commit() 仍然对受让人关系进行必要的更改。非常感谢。
  • 此外,如果您将级联设置为 all、delete、delete-orphan 等,这从数据库中删除对象。
【解决方案2】:

一个工作示例脚本意味着,我们可以完全运行它。这是从您提供的 sn-ps 生成的脚本。有帮助的一件事是将“受让人”评估为一个列表,因为您要从中删除,很可能您没有正确迭代。

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base= declarative_base()

patent_company_table = Table('pct', Base.metadata,
    Column('patent_id', Integer, ForeignKey('patent.id')),
    Column('company_id', Integer, ForeignKey('company.id'))
)

class Patent(Base):
    __tablename__ = "patent"
    id = Column(Integer, primary_key=True)

    assignees = relationship('Company', secondary=patent_company_table, backref='patents')

class Company(Base):
    __tablename__ = "company"
    id = Column(Integer, primary_key=True)

e = create_engine("sqlite://")
Base.metadata.create_all(e)

s = Session(e)
p = Patent()
c1, c2, c3, c4, c5 = Company(), Company(), Company(), Company(), Company()
d1, d2 = Company(), Company()
duplicate_company_to_default = {c1:d1, c2:d2, c3:d1, c4:d2}

new_assignees = [c1, c2, c3, c4, c5]
p.assignees = new_assignees
s.add(p)
s.commit()

patent = s.query(Patent).first()
assignees = patent.assignees
added_patent_count = 0
for assignee in list(assignees):
    if assignee in duplicate_company_to_default:
        patent.assignees.remove(assignee)
        default_company = duplicate_company_to_default[assignee]
        if default_company not in assignees:
            added_patent_count += 1
            patent.assignees.append(default_company)

assert p in s.dirty

s.commit()

assert set(p.assignees) == set([d1, d2, c5])

【讨论】:

  • 感谢 zzzeek 写这篇文章。它很好地说明了这种关系。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
相关资源
最近更新 更多