SQLAlchemy: joining table data using foreign keys

I am having problems 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)

      

First, I'll create an entry for foo_table

:

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

      

Now I will create a line in bar_table

and link the two:

b = Bar()
f.bar = b

      

Fine! We'll add f

to our session and commit:

session.add(f)
session.commit()

      

Now, let's pretend we are facing another instance Foo

with the same foo_id

and associated with the same Bar

, but with some new data:

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

      

It's fine! It happens all the time, right? I just update the information in foo_table

using session.merge()

instead session.add()

:

session.merge(f)

      

But that's not okay! The code breaks down and I get a 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?

+1


source to share


1 answer


I'm not sure if there is a really good answer for this ... I finished a survey to determine if I am working with new data.

So anytime I create a new instance Foo

:



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

      

It doesn't seem perfect, but I have yet to find another solution that works.

+1


source







All Articles