Я использую SQLAlchemy с Flask -SQLAlchemy и пытаюсь настроить пару событий после создания новых элементов. Я хочу, чтобы это работало, когда люди взаимодействуют с моделями без необходимости понимать логику c. Он должен просто работать, когда они создают новые объекты.
В настоящее время он выглядит примерно так:
class A(db.Model):
id = db.Column(db.Integer, primary_key=True)
b_id = db.Column(db.Integer, db.ForeignKey('b.id'), nullable=True)
generated_from_id = db.Column(db.String)
@event.listens_for(A, 'after_insert')
def generate_something(mapper, connection, target):
id = target.id
a_table = target.__table__
generated_thing = <do some operation on id>
connection.execute(
a_table.update().where(a_table.columns.id==target.id).values(generated_from_id=generated_thing)
)
class B(db.Model):
id = db.Column(db.Integer, primary_key=True)
some_attribute = db.Column(db.String)
@event.listens_for(B, 'after_insert')
def create_or_update_class_a(mapper, connection, target):
if target.some_attribute == 'whatever':
# we need to create a new A
# this creates a new A, but the event listener on A does not catch the insert
connection.execute(A.__table__.insert().values(b_id=target.id))
# this creates a new A and the event listener on A does catch the insert, but it shows warning:
# sqlalchemy/orm/session.py:2488: SAWarning: Usage of the 'Session.add()' operation is not currently supported within the execution stage of the flush process. Results may not be consistent.
new_a = A()
db.session.add(new_a)
else:
# we need to update an existing A
target_a = <some logic to find which A to update>
# this does update the existing A, but it seems that sometimes the b_id is stale and I need to do something like db.session.refresh(some_a)
connection.execute(A.__table__.update().where(A.__table__.columns.id==target_a.id).values(b_id=target.id))
Так что всякий раз, когда я создаю новые B, такие как:
new_b = B(some_attribute='whatever')
db.session.add(new_b)
db.session.commit()
Я ожидаю что мой новый B создан и создан соответствующий A. Когда я делаю что-то вроде:
new_b = B(some_attribute='something-else')
db.session.add(new_b)
db.session.commit()
Я ожидаю, что мой существующий A будет обновляться, в идеале, без каких-либо устаревших данных при запросе As для B.
Как отмечено в комментариях выше:
- Использование
db.session.add()
в событии after_insert для B показывает предупреждение SA, но в остальном кажется в основном нормальным. Использование .update()
в событии after_insert для B обновляет db для единственного значения на A, но не вызывает обработчик события A для generate_something()
. Есть ли лучший подход? - Использование
.update()
в другом случае в create_or_update_class_a
приводит к некоторым устаревшим данным. Это кажется не совсем идеальным, так как я не буду знать, когда мне нужно обновить sh моих объектов. Как мне узнать, когда нужно обновить sh мой объект? Есть ли лучший способ сделать это?