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
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.
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.
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.
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)
...
The answer is:
apps.get_model('contenttypes', 'ContentType')
:) Needed it myself today.
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.
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