Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: ContentTypes during migration while running tests

I migrated a ForeignKey to a GenericForeignKey, using the contrib.contenttypes framework. To access the ContentType object I need to migrate the data, I used this code:

ContentType = apps.get_model('contenttypes', 'ContentType')

my_model_content_type = ContentType.objects.get(
    app_label='my_app',
    model='my_model'
)

The migration works when I run manage.py migrate, and I can then play with the updated model in the shell without problems.

However, when I attempt to run manage.py test, I get the following error in the ContentTypes.object.get() line:

__fake__.DoesNotExist: ContentType matching query does not exist.

Querying for ContentType.objects.all() at that time returns an empty queryset.

I have tried (as directed by another answer here in SO) to run this before my query, but to no avail:

update_contenttypes(apps.app_configs['contenttypes'])
update_contenttypes(apps.app_configs['my_app'])

How can I ensure that the ContentType rows exist at that point in the test database migration?

like image 339
slezica Avatar asked Oct 31 '16 15:10

slezica


People also ask

What are migrations in Django?

Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema. They’re designed to be mostly automatic, but you’ll need to know when to make migrations, when to run them, and the common problems you might run into.

What quality checks do you use for your Django migrations?

We use a very strict django project setup with several quality checks for our migrations: We write all data migration as typed functions in our main source code. Then we check everything with mypy and test as regular functions

How does the Django test runner reorder tests?

In order to guarantee that all TestCasecode starts with a clean database, the Django test runner reorders tests in the following way: All TestCasesubclasses are run first. Then, all other Django-based tests (test cases based on SimpleTestCase, including TransactionTestCase) are run with no particular ordering guaranteed nor enforced among them.

How to test forward and rollback migrations in Django?

You can test forward and rollback migrations and their ordering with the help of django-test-migrations. It is simple, friendly, and already works with the test framework of your choice. I also want to say “thank you” to these awesome people. Without their work it would take me much longer to come up with the working solution.


1 Answers

This is what ended up working for me. First, import update_contenttypes:

from django.contrib.contenttypes.management import update_contenttypes

Second, list the initial ContentType migration as a dependency:

dependencies = [
    ('contenttypes', '0001_initial'),
    ...
]

Finally, in the forward migration function (invoked via RunPython in the migration operations):

# Ensure ContentType objects exist at this point:
app_config = apps.get_app_config('my_app')
app_config.models_module = app_config.models_module or True

update_contenttypes(app_config)

You may need to run the above code for more than one app_config. You can obtain the all the app_config objects using apps.get_app_configs() and iterate.

like image 154
slezica Avatar answered Oct 03 '22 22:10

slezica