SQLAlchemy:将表数据与外键合并 [英] SQLAlchemy: Merging table data with foreign keys

查看:32
本文介绍了SQLAlchemy:将表数据与外键合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在尝试更新使用外键作为主键一部分的行时遇到问题.这是一个简化的案例:

I'm running into issues when trying to update rows that use a foreign key as part of their primary key. Here's a simplified case:

class Foo(Base):
    __tablename__ = 'foo_table'
    foo_id = Column(Integer, primary_key=True)
    bar_id = Column(Integer, ForeignKey('bar_table.bar_id'), primary_key=True)
    foo_data = Column(String(255))

    bar = relationship('Bar', backref='foos', foreign_keys=[bar_id])

class Bar(Base):
    __tablename__ = 'bar_table'
    bar_id = Column(Integer, primary_key=True)

首先,我将为 foo_table 创建一个条目:

First I'll create an entry for the foo_table:

f = Foo()
f.foo_id = 1
f.foo_data = 'Foo Data'

现在我将在 bar_table 中创建一行并将两者关联起来:

Now I'll create a row in the bar_table and associate the two:

b = Bar()
f.bar = b

太好了!我们将 f 添加到我们的会话中并提交:

Great! We'll add f to our session and commit:

session.add(f)
session.commit()

现在假设我们遇到了另一个具有相同 foo_id 并与相同 Bar 相关的 Foo 实例,但有一些新数据:

Now pretend we run into another instance of Foo with the same foo_id and related to the same Bar, but with some new data:

f = Foo()
f.foo_id = 1
f.foo_data = 'NEW Foo Data'
f.bar = b

没关系!这种情况经常发生,对吧?我将使用 session.merge() 而不是 session.add() 来更新 foo_table 中的信息:

That's fine! This happens all the time, right? I'll just update the information in the foo_table using session.merge() instead of session.add():

session.merge(f)

但这不行!代码中断,我得到了回溯:

But this is not fine! The code breaks and I get the traceback:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 1689, in merge
    self._autoflush()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 1282, in _autoflush
    self.flush()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2004, in flush
    self._flush(objects)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2122, in _flush
    transaction.rollback(_capture_exception=True)
  File "/Library/Python/2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2086, in _flush
    flush_context.execute()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
    rec.execute(self)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
    uow
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/persistence.py", line 149, in save_obj
    base_mapper, states, uowtransaction
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/persistence.py", line 301, in _organize_states_for_save
    state_str(existing)))
sqlalchemy.orm.exc.FlushError: New instance <Foo at 0x10a804590> with identity key (<class 'test.Foo'>, (1, 1)) conflicts with persistent instance <Foo at 0x1097a30d0>

有谁知道这次更新失败的原因吗?

Does anyone know why this update fails?

推荐答案

我不确定是否有一个很好的答案...我最终查询以确定我是否正在使用 new数据.

I'm not sure if there's a really good answer for this... I've ended up querying to determine whether or not I'm working with new data.

所以每当我创建 Foo 的新实例时:

So any time I create a new instance of Foo:

old_foo = session.query(Foo).filter(Foo.id == id).all()
if old_foo:
    foo = old_foo[0]
else:
    foo = Foo()

这似乎并不理想,但我还没有找到另一种有效的解决方案.

This doesn't seem ideal, but I've yet to find another solution that works.

这篇关于SQLAlchemy:将表数据与外键合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆