How do I cascade objects using flask-sqlalchemy?

problem description

for example, I want to create a Wallet object after the User object is successfully session.commit (), and I may need to create another object after the Wallet object is successfully created. I don"t want to use functions to encapsulate the code that creates multiple objects, because User objects may not be explicitly created in the code, but sometimes through load fixtures (I have a load fixtures feature similar to django).

methods that have been tried

I try to use the models_committed signal of flask-sqlalchemy to trigger, such as this:

    @models_committed.connect_via(app)
    def on_models_committed(sender, changes):
        for obj, change in changes:
            if change == "insert" and hasattr(obj, "__commit_insert__"):
                obj.__commit_insert__()
            elif change == "update" and hasattr(obj, "__commit_update__"):
                obj.__commit_update__()
            elif change == "delete" and hasattr(obj, "__commit_delete__"):
                obj.__commit_delete__()

then add the commit_insert method to User model, where you create a Wallet object, such as this:

def __commit_insert__(self):
    wallet = Wallet(name="my_wallet")
    db.session.add(wallet)
    db.session.commit()
What is the error message that

actually sees?

however, when creating the Wallet object commit, an error was reported:

This session is in "committed" state; no further SQL can be emitted within this transaction.

be reasonable. Temporarily working on flask has not yet poured out the kung fu source code to see how flask-sqlalchemy is logical, so first ask everyone to see if you have encountered this kind of situation, and whether there is any general way to handle similar scenarios in flask?

in addition,
I went to stack-overflow to have a look at it first. As a result, this answer makes sense very embarrassing.


try SQLAlchemy's event ( http://docs.sqlalchemy.org/en.)
a simple usage example

import sqlalchemy
from sqlalchemy import event
from models import Wallet

class User(db.Model):
  name = sqlalchemy.column(s.String)

  @staticmethod
  def after_create(mapper, connection, target):
    wallet = Wallet()
    db.session.add(wallet)
    db.session.commit()
    
event.listen(User, 'after_insert', User.after_create)

this problem can be solved by directly executing the sql statement

import sqlalchemy
from sqlalchemy import event
from models import Wallet

class User(db.Model):
  name = sqlalchemy.column(s.String)

  @staticmethod
  def after_create(mapper, connection, target):
    wallet_table = Wallet.__table__
    connection.execute(
        wallet_table.insert().values(name='my wallet')
        )
    
event.listen(User, 'after_insert', User.after_create)

referred to the answer given by @ silently . Although he may report errors, his sqlalchemy event writing method is very convenient to get connection objects. In the Flask Signaling way I wrote in my original question, if I want to get connection, I need to write like this:

with db.engine.connect() as connection:
    ...

there is another problem to note, that is, if you need to execute multiple sql statements, pay attention to using transactions, for example:

trans = connection.begin()
try:
    ...
except exc.SQLAlchemyError:
    trans.rollback()
        raise
    else:
        trans.commit()

reference link

Menu