Python 在SQLAlchemy中从集合中删除对象

Python 在SQLAlchemy中从集合中删除对象,python,mysql,sqlalchemy,Python,Mysql,Sqlalchemy,我正在MySQL数据库中存储大量专利数据,并通过SQLAlchemy与之交互。我在专利类中有一个集合,代表受让人列表(被转让专利的公司): 我正在处理数据库中存储的一些对象,对于专利对象,我想从p的受让人列表中删除一些受让人a(公司对象)。基于,调用s.delete(a)实际上会删除公司对象a。我只是想从p的受让人列表中删除受让人a(即删除专利公司表中的一行),而不是实际删除公司对象,因为a可能在另一个专利对象的受让人列表中 我尝试创建一个新的列表new_assignees,其中除了a之外,还只

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

我正在处理数据库中存储的一些对象,对于专利对象,我想从
p
的受让人列表中删除一些受让人
a
(公司对象)。基于,调用
s.delete(a)
实际上会删除公司对象
a
。我只是想从
p
的受让人列表中删除受让人
a
(即删除专利公司表中的一行),而不是实际删除公司对象,因为
a
可能在另一个专利对象的受让人列表中

我尝试创建一个新的列表
new_assignees
,其中除了
a
之外,还只包括
p
中的assignees,然后调用:

p.assignees = new_assignees
s.add(p)
不幸的是,这实际上并没有将
p
标记为dirty,因此我认为这不会影响数据库

对于如何从集合中删除对象,删除patent_company_表中的行,而不是从company表中删除对象,您有什么建议吗

多谢各位

更新 以下是代码片段:

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)

在循环浏览所有专利之后,
添加了\u patent\u count=983672
,但是
会话中没有对象。dirty()
。修改后是否需要通过
append
remove
手动添加到会话?

SQLAlchemy集合支持列表,如append/remove操作

p.assignees.remove(c)

这应该删除
c
表单
p.受让人
,而不从数据库中删除
c

一个工作示例脚本意味着,我们可以完全运行它。下面是根据您提供的代码片段生成的脚本。有一点很有帮助,那就是将“assignees”作为一个列表进行评估,因为您正在从列表中删除,所以很可能您没有正确地进行迭代

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])

谢谢你的建议,但这并不能解决问题。我在上面包含了一个代码片段。这是正确的。s.dirty的长度为0,但s.commit()仍对assignees关系进行必要的更改。非常感谢。此外,如果您已将cascade设置为all、delete、delete orphan等,这将从数据库中删除对象。您是否能够提取并发布此问题的工作示例脚本(模型定义、示例副本dict等)?还想知道您使用的是哪种类型的
PrimaryKey
标识符吗?谢谢您写这篇文章。这很好地说明了这种关系。我感谢你的帮助。
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])