Search code examples
pythonpython-3.xsqlalchemyflask-sqlalchemy

Flask-SQLAlchemy: SAWarning: Identity map already had an identity for (object), replacing it with newly flushed object


So I've made a personal web server to scrape some sites and display the data on a web page. But when I try to commit the results to the database I got a warning for each Video that I commit. I'd like to know if this warning can be fixed or at least hidden ?

Here's my code:

from web_scraper import db
from web_scraper.models import Video

old_db = Video.query.all() # existing database to compare with the new one
db_queue = list() # scraping results ready to be added to the database

### web scraping occurs here to fill db_queue

db.drop_all() # reset db
db.create_all() # recreate a new one
for vid in db_queue:
    db.session.add(vid) # adding all pending results
db.session.commit() # error thrown here

And here's the complete warning output:

C:\DevApps\Python38\lib\site-packages\sqlalchemy\orm\session.py:1948: SAWarning: Identity map already had
an identity for (<class 'web_scraper.models.Video'>, (2133,), None), replacing it with newly flushed object.
Are there load operations occurring inside of an event handler within the flush?

Solution

  • This warning is issued because:

    • A session is created
    • Existing objects are fetched into the session
    • The database tables are dropped and re-created
    • New objects are added to the same session
    • The new objects have the same ids as objects added to the original session, so SQLAlchemy warns that the original objects in the session are being overwritten with the new objects

    The objects in old_db are still the original objects, so you could choose to ignore the warning, but it's usually best to deal with warnings before they lead to errors (that's why they're warnings).

    You could take one or all of these steps:

    • close* the original session and open a new one before adding the new objects
    • expunge the objects from the session
    • instead of dropping and recreating the tables, delete the objects that they contain

    * or remove if it's a scoped_session.