@@ -23,6 +23,21 @@ def configure_psycopg():
2323 pass
2424
2525
26+ # ============================================================================
27+ # HELPER FUNCTIONS
28+ # ============================================================================
29+
30+
31+ async def _truncate_all_tables (ctx ) -> None :
32+ """Truncate all tables in the given context."""
33+ if ctx .apps :
34+ for model in ctx .apps .get_models_iterable ():
35+ quote_char = model ._meta .db .query_class .SQL_CONTEXT .quote_char
36+ await model ._meta .db .execute_script (
37+ f"DELETE FROM { quote_char } { model ._meta .db_table } { quote_char } " # nosec
38+ )
39+
40+
2641# ============================================================================
2742# PYTEST FIXTURES FOR TESTS
2843# These fixtures provide different isolation patterns for test scenarios
@@ -57,6 +72,9 @@ async def db(db_module):
5772 Each test runs inside a transaction that gets rolled back at the end,
5873 providing isolation without the overhead of schema recreation.
5974
75+ For databases that don't support transactions (e.g., MySQL MyISAM),
76+ falls back to truncation cleanup.
77+
6078 This is the FASTEST isolation method - use for most tests.
6179
6280 Usage:
@@ -69,18 +87,25 @@ async def test_something(db):
6987 # Get connection from the context using its default connection
7088 conn = db_module .db ()
7189
72- # Start a savepoint/transaction
73- transaction = conn ._in_transaction ()
74- await transaction .__aenter__ ()
75-
76- try :
90+ # Check if the database supports transactions
91+ if conn .capabilities .supports_transactions :
92+ # Start a savepoint/transaction
93+ transaction = conn ._in_transaction ()
94+ await transaction .__aenter__ ()
95+
96+ try :
97+ yield db_module
98+ finally :
99+ # Rollback the transaction (discards all changes made during test)
100+ class _RollbackException (Exception ):
101+ pass
102+
103+ await transaction .__aexit__ (_RollbackException , _RollbackException (), None )
104+ else :
105+ # For databases without transaction support (e.g., MyISAM),
106+ # fall back to truncation cleanup
77107 yield db_module
78- finally :
79- # Rollback the transaction (discards all changes made during test)
80- class _RollbackException (Exception ):
81- pass
82-
83- await transaction .__aexit__ (_RollbackException , _RollbackException (), None )
108+ await _truncate_all_tables (db_module )
84109
85110
86111@pytest_asyncio .fixture (scope = "function" )
@@ -148,14 +173,7 @@ async def test_with_transactions(db_truncate):
148173 # Table truncated after test
149174 """
150175 yield db_module
151-
152- # Truncate all tables after the test using context's apps
153- if db_module .apps :
154- for model in db_module .apps .get_models_iterable ():
155- quote_char = model ._meta .db .query_class .SQL_CONTEXT .quote_char
156- await model ._meta .db .execute_script (
157- f"DELETE FROM { quote_char } { model ._meta .db_table } { quote_char } " # nosec
158- )
176+ await _truncate_all_tables (db_module )
159177
160178
161179# ============================================================================
0 commit comments