I want to write an abstract model mixin, that I can use to make OneToOne - relations to the user model. Here is my code:
from django.conf import settings
from django.db import models
class Userable(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
class Meta:
abstract = True
I've written the following test for this model:
class TestUserable(TestCase):
mixin = Userable
def setUp(self):
user = User.objects.create_user(
email="[email protected]",
name="Test User",
password="test1234test"
)
self.user = user
self.model = ModelBase(
'__TestModel__' + self.mixin.__name__, (self.mixin,),
{'__module__': self.mixin.__module__}
)
with connection.schema_editor() as schema_editor:
schema_editor.create_model(self.model)
def test_user(self):
self.model.objects.create(user=self.user)
self.assertEqual(self.model.objects.count(), 1)
def tearDown(self):
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(self.model)
My problem is, that this test in it's tearDown()
method throws the follwing error:
django.db.utils.OperationalError: cannot DROP TABLE "core___testmodel__userable" because it has pending trigger events
What could be the cause of this? I did run python manage.py makemigrations
and python manage.py migrate
, but there are no pending migrations (as is expected, since this is an abstract model).
EDIT: It seems to have something to do with OneToOneFields or ForeignKeys (relations). If I use this code altered for regular fields, like CharFields or IntegerFields, it works.
EDIT2: If you have another better way of testing abstract base model that use ForeignKeys, please let me know!
You have not manually edited your database - Django won’t be able to detect that your database doesn’t match your models, you’ll just get errors when migrations try to modify those tables. Migrations can be reversed with migrate by passing the number of the previous migration.
When the migrate --fake-initial option is used, these initial migrations are treated specially. For an initial migration that creates one or more tables ( CreateModel operation), Django checks that all of those tables already exist in the database and fake-applies the migration if so.
A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table. Each model is a Python class that subclasses django.db.models.Model. Each attribute of the model represents a database field.
If you are the maintainer of a third-party app with models, you may need to ship migrations that support multiple Django versions. In this case, you should always run makemigrations with the lowest Django version you wish to support.
Common practice for testing abstract models is to create actual models just for tests
here is example in model-utils
project https://github.com/jazzband/django-model-utils/blob/master/tests/test_models/test_timestamped_model.py
from tests.models import UserableTest
class TestUserable(TestCase):
def setUp(self):
user = User.objects.create_user(
email="[email protected]",
name="Test User",
password="test1234test"
)
self.user = user
def test_user(self):
UserableTest.objects.create(user=self.user)
self.assertEqual(UserableTest.objects.count(), 1)
In this project they have separate settings DJANGO_SETTINGS_MODULE = tests.settings
https://github.com/jazzband/django-model-utils/blob/master/tests/settings.py
INSTALLED_APPS = (
'model_utils',
'tests',
)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3'
}
}
SECRET_KEY = 'dummy'
And models are described in https://github.com/jazzband/django-model-utils/blob/master/tests/models.py
from myapp.models import Userable
class UserableTest(Userable):
pass
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With