Solved: Permission-not-found error in data-migrations

Magesh Ravi

Managing permissions in Django is critical to ensuring secure access to sensitive data within your application. However, it can also create unforeseen issues during development and deployment. One such problem is when you encounter a runtime error that complains the permission does not exist after resetting your development environment and running all migrations in a fresh instance. This issue can occur when you have data migrations that grant or revoke specific permissions to users or groups.

The root cause of this issue lies in how Django creates permissions. The framework generates default permissions for new models each time you run migrate, which triggers the post_migrate signal.

Let's assume your project has four migrations,

image 1

You might have run the migrations in multiple parts,

image 2

When you run all migrations at once after resetting the database,

image 3

Therefore, if you have a data migration that modifies permissions, it may not work correctly during development when you reset the database and run all migrations in a fresh instance.

One solution to this problem is to force-create the permissions without waiting for the post_migrate signal. By doing so, you can ensure that the permissions exist before any data migration runs. Here's how you can force-create the permissions:

from import create_permissions
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

def force_create_permissions(apps, schema_editor):
    """creates permissions without waiting for post_migrate signal
    for app_config in apps.get_app_configs():
        app_config.models_module = True
        create_permissions(app_config, apps=apps, verbosity=0)
        app_config.models_module = None

def grant_permissions(apps, schema_editor):
    """your code here"""

def revoke_permissions(apps, schema_editor):
    """your code here"""

class Migration(migrations.Migration):

    dependencies = [
        ('core', '0003_create_books'),

    operations = [
        migrations.RunPython(force_create_permissions, migrations.RunPython.noop),
        migrations.RunPython(grant_permissions, reverse_code=revoke_permissions)

In the above code, we're defining a new function called force_create_permissions. This function uses Django's create_permissions method to create any missing permissions for the specified app configuration.

Thus, when you reset your development environment and run all migrations, the force_create_permissions function will ensure that the necessary permissions exist before any data migration runs. This approach eliminates any runtime errors complaining about missing permissions.

This article summarises what we discussed in the Django Developers Guild monthly meeting on 26 Feb 2023. If you liked this post, share it with someone who might find it helpful.

Have a comment to share or a question to raise? Join our Discord server.