I'm trying to test some simple abstract mixins using django 2.2.4/sqlite3 2.6.0/python 3.6.8.
Currently I'm having issues deleting a model from the test database using the schema editor.
I have the following test case:
from django.test import TestCase
from django.db.models.base import ModelBase
from django.db import connection
class ModelMixinTestCase(TestCase):
"""
Test Case for abstract mixin models.
"""
mixin = None
model = None
@classmethod
def setUpClass(cls) -> None:
# Create a real model from the mixin
cls.model = ModelBase(
"__Test" + cls.mixin.__name__,
(cls.mixin,),
{'__module__': cls.mixin.__module__}
)
# Use schema_editor to create schema
with connection.schema_editor() as editor:
editor.create_model(cls.model)
super().setUpClass()
@classmethod
def tearDownClass(cls) -> None:
# Use schema_editor to delete schema
with connection.schema_editor() as editor:
editor.delete_model(cls.model)
super().tearDownClass()
Which can be used like this:
class MyMixinTestCase(ModelMixinTestCase):
mixin = MyMixin
def test_true(self):
self.assertTrue(True)
This does allow for a model to be created and tested. The problem is that within ModelMixinTestCase.tearDownClass
, connection.schema_editor()
is unable to disable constraint checking which is done in django.db.backends.sqlite3.base
using:
def disable_constraint_checking(self):
with self.cursor() as cursor:
cursor.execute('PRAGMA foreign_keys = OFF')
# Foreign key constraints cannot be turned off while in a multi-
# statement transaction. Fetch the current state of the pragma
# to determine if constraints are effectively disabled.
enabled = cursor.execute('PRAGMA foreign_keys').fetchone()[0]
return not bool(enabled)
this leads to an exception in __enter__
of the DatabaseSchemaEditor
in django.db.backends.sqlite3.schema
:
def __enter__(self):
# Some SQLite schema alterations need foreign key constraints to be
# disabled. Enforce it here for the duration of the schema edition.
if not self.connection.disable_constraint_checking():
raise NotSupportedError(
'SQLite schema editor cannot be used while foreign key '
'constraint checks are enabled. Make sure to disable them '
'before entering a transaction.atomic() context because '
'SQLite does not support disabling them in the middle of '
'a multi-statement transaction.'
)
return super().__enter__()
So based on all this I'm assuming we are in an atomic context but I'm currently not sure what the cleanest way is to exit that context and delete the model.