|
7 | 7 | from mongoengine.common import _import_class |
8 | 8 | from mongoengine.connection import ( |
9 | 9 | DEFAULT_CONNECTION_NAME, |
| 10 | + _clear_session, |
10 | 11 | _get_session, |
| 12 | + _set_session, |
| 13 | + get_connection, |
11 | 14 | get_db, |
12 | 15 | ) |
13 | 16 | from mongoengine.pymongo_support import count_documents |
|
21 | 24 | "set_write_concern", |
22 | 25 | "set_read_write_concern", |
23 | 26 | "no_dereferencing_active_for_class", |
| 27 | + "run_in_transaction", |
24 | 28 | ) |
25 | 29 |
|
26 | 30 |
|
@@ -321,3 +325,41 @@ def set_read_write_concern(collection, write_concerns, read_concerns): |
321 | 325 | write_concern=WriteConcern(**combined_write_concerns), |
322 | 326 | read_concern=ReadConcern(**combined_read_concerns), |
323 | 327 | ) |
| 328 | + |
| 329 | + |
| 330 | +@contextmanager |
| 331 | +def run_in_transaction( |
| 332 | + alias=DEFAULT_CONNECTION_NAME, session_kwargs=None, transaction_kwargs=None |
| 333 | +): |
| 334 | + """run_in_transaction context manager |
| 335 | + Execute queries within the context in a database transaction. |
| 336 | +
|
| 337 | + Usage: |
| 338 | +
|
| 339 | + .. code-block:: python |
| 340 | +
|
| 341 | + class A(Document): |
| 342 | + name = StringField() |
| 343 | +
|
| 344 | + with run_in_transaction(): |
| 345 | + a_doc = A.objects.create(name="a") |
| 346 | + a_doc.update(name="b") |
| 347 | +
|
| 348 | + Be aware that: |
| 349 | + - Mongo transactions run inside a session which is bound to a connection. If you attempt to |
| 350 | + execute a transaction across a different connection alias, pymongo will raise an exception. In |
| 351 | + other words: you cannot create a transaction that crosses different database connections. That |
| 352 | + said, multiple transaction can be nested within the same session for particular connection. |
| 353 | +
|
| 354 | + For more information regarding pymongo transactions: https://pymongo.readthedocs.io/en/stable/api/pymongo/client_session.html#transactions |
| 355 | + """ |
| 356 | + conn = get_connection(alias) |
| 357 | + session_kwargs = session_kwargs or {} |
| 358 | + with conn.start_session(**session_kwargs) as session: |
| 359 | + transaction_kwargs = transaction_kwargs or {} |
| 360 | + with session.start_transaction(**transaction_kwargs): |
| 361 | + try: |
| 362 | + _set_session(session) |
| 363 | + yield |
| 364 | + finally: |
| 365 | + _clear_session() |
0 commit comments