Egal, welche Option Sie unten gewählt haben, kommt SQLAlchemy mit a big warning about the after_commit
event (das ist, wenn beide Möglichkeiten, um das Signal zu senden).
die Sitzung nicht in einer aktiven Transaktion, wenn das after_commit()
Ereignis aufgerufen wird, und kann daher nicht emittieren SQL.
Wenn Ihr Rückruf Abfragen oder Commit für die Datenbank ausführen muss, können unerwartete Probleme auftreten. In diesem Fall könnten Sie eine Aufgabenwarteschlange wie Celery verwenden, um dies in einem Hintergrundthread (mit einer separaten Sitzung) auszuführen. Dies ist wahrscheinlich der richtige Weg, da das Senden von E-Mails sehr lange dauert und Sie nicht möchten, dass Ihre Ansicht wartet, um zurückzukehren, während sie stattfindet.
Flask-SQLAlchemy provides a signal Sie das hören sendet alle insert/update/delete ops. Allerdings, the patch, dass dies tatsächlich funktioniert, ist nicht in der veröffentlichten Version noch, müssten Sie die dev-Version von git installieren (das Signal existiert in der aktuellen Version (2.0), funktioniert aber nicht richtig). Wenn Sie mit dem ok sind, installieren Sie es dann mit:
pip install https://github.com/mitsuhiko/flask-sqlalchemy/tarball/master
Dann für das Signal hören:
from flask_sqlalchemy import models_committed
def notify_subscribers(app, changes):
new_posts = [target for target, op in changes if isinstance(target, Post) and op in ('insert', 'update')]
# notify about the new and updated posts
models_committed.connect(notify_subscribers, app)
Sie auch diese selbst (vor allem durch Kopieren Sie den Code aus Flask implementieren -SQLAlchemy). Es ist ein wenig schwierig, weil Modelländerungen auftreten Flush, nicht auf Commit, so müssen Sie alle Änderungen als Flushes aufzeichnen, dann verwenden Sie sie nach dem Festschreiben.
from sqlalchemy import event
class ModelChangeEvent(object):
def __init__(self, session, *callbacks):
self.model_changes = {}
self.callbacks = callbacks
event.listen(session, 'before_flush', self.record_ops)
event.listen(session, 'before_commit', self.record_ops)
event.listen(session, 'after_commit', self.after_commit)
event.listen(session, 'after_rollback', self.after_rollback)
def record_ops(self, session, flush_context=None, instances=None):
for targets, operation in ((session.new, 'insert'), (session.dirty, 'update'), (session.deleted, 'delete')):
for target in targets:
state = inspect(target)
key = state.identity_key if state.has_identity else id(target)
self.model_changes[key] = (target, operation)
def after_commit(self, session):
if self._model_changes:
changes = list(self.model_changes.values())
for callback in self.callbacks:
callback(changes=changes)
self.model_changes.clear()
def after_rollback(self, session):
self.model_changes.clear()
def notify_subscribers(changes):
new_posts = [target for target, op in changes if isinstance(target, Post) and op in ('insert', 'update')]
# notify about new and updated posts
# pass all the callbacks (if you have more than notify_subscribers)
mce = ModelChangeEvent(db.session, notify_subscribers)
# or you can append more callbacks
mce.callbacks.append(my_other_callback)