Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting model ContentType in migration - Django 1.7

I have a data migration that updates some permissions. I know there are some known issues with permissions in migrations and i was able to avoid some trouble by creating the permissions in the migration it self (rather then using the tuple shortcut in the model).

The migration :

from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings

def create_feature_groups(apps, schema_editor):
    app = models.get_app('myauth')

    Group = apps.get_model("auth", "Group")
    pro = Group.objects.create(name='pro')

    Permission = apps.get_model("auth", "Permission")
    ContentType = apps.get_model("contenttypes", "ContentType")
    invitation_contenttype = ContentType.objects.get(name='Invitation')

    send_invitation = Permission.objects.create(
         codename='send_invitation',
         name='Can send Invitation',
         content_type=invitation_contenttype)

    pro.permissions.add(receive_invitation)    

class Migration(migrations.Migration):

    dependencies = [
        ('myauth', '0002_initial_data'),
    ]

    operations = [
            migrations.RunPython(create_feature_groups),
    ]

After some trial and error i was able to make this work using manage.py migrate but i'm getting errors in the test manage.py test.

__fake__.DoesNotExist: ContentType matching query does not exist.

Debugging a bit discovered that there are no ContentType at this point in the migration when run in test (not sure why). Following the advice in this post i tried updating the content types manually in the migration it self. Added :

from django.contrib.contenttypes.management import update_contenttypes
update_contenttypes(app, models.get_models())

before fetching the content type for the Invitation model. Got the following error

  File "C:\Python27\lib\site-packages\django-1.7-py2.7.egg\django\contrib\contenttypes\management.py", line 14, in update_contenttypes
    if not app_config.models_module:
AttributeError: 'module' object has no attribute 'models_module'

There must be some way to create/update permissions in data migrations in a testable way.

Thanks.

EDIT

Finally made it work by adding

from django.contrib.contenttypes.management import update_all_contenttypes
update_all_contenttypes() 

oddly enough this one was not sufficient

update_contenttypes(apps.app_configs['contenttypes'])

I would love to know why all of this is necessary

like image 749
haki Avatar asked Oct 20 '14 11:10

haki


People also ask

How do you known that the changes are migrated in Django?

Adding migrations to apps Now, run python manage.py migrate --fake-initial , and Django will detect that you have an initial migration and that the tables it wants to create already exist, and will mark the migration as already applied.

Where are migration files in Django?

The migration files for each app live in a “migrations” directory inside of that app, and are designed to be committed to, and distributed as part of, its codebase.

How do I reapply migrations in Django?

Steps to rerun a Django migration:Fake back to the migration immediately before the one you want to rerun. Rerun the target migration. Fake back to the latest migration.


3 Answers

For Django 2.1 I had to import apps from global registry because passed apps into migration were instances of django.db.migrations.state.AppConfigStub without populated models_module attribute. And create_contenttypes is checking this attribute.

from django.apps.registry import Apps, apps as global_apps
from django.contrib.contenttypes.management import create_contenttypes
from django.db import migrations


def add_permision(apps: Apps, schema_editor):
    my_app_config = global_apps.get_app_config('my_app')
    create_contenttypes(my_app_config)

    ...
like image 78
Petr Přikryl Avatar answered Oct 19 '22 10:10

Petr Přikryl


The answer is:

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

:) Needed it myself today.

like image 21
gabn88 Avatar answered Oct 19 '22 10:10

gabn88


Having a similar issue when writing a data migration that spans several apps. Turns out Django only loads those models into the app registry that are affected by what the "dependencies" member of the migration states: https://code.djangoproject.com/ticket/24303

Had to basically add an entry to the migration dependencies that I use that is not directly related by e.g. a ForeignKey to the app that is currently being migrated.

like image 7
Sakuraba Avatar answered Oct 19 '22 10:10

Sakuraba