Create default model permissions before running application migrations

I’m trying to create users using datamigrations on a new project. None of the default permissions are being created for the User model (nor any other model). If I skip setting that user with those permissions or do it after I already ran migration, it would work.

I don’t think this is a desired behavior. If data migrations are being run, it should do after dependency application data is already in.

How to reproduce:

  1. Create an empty project

  2. Create an app “test”

  3. Create an initial empty migration file ./manage.py makemigration test --empty

  4. Add the following content for “test/migrations/0001_initial.py”:

    def create_user(apps, schema_editor):
        User = apps.get_model("auth", "User")
        Permission = apps.get_model("auth", "Permission")
        ContentType = apps.get_model("contenttypes", "contenttype")
    
        user = User.objects.create_user("new_user")
       
        alias = schema_editor.connection.alias
        content_type_manager = ContentType.objects.db_manager(alias)
        user_type = content_type_manager.get_for_model(User, for_concrete_model=False)
    
        add_user_permission = Permission.objects.get(content_type=user_type, codename="add_user")
    
        user.user_permissions.add(add_user_permission)
    
    class Migration(migrations.Migration):
    
        dependencies = [
            migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ]
    
        operations = [
            migrations.RunPython(create_user),
        ]
    
  5. Run ./manage.py migrate

If you ran migrate before you created the data migration, it will work. If the application is deployed on the field, it will fail deployment.

You are running into #29843.

A workaround might be to use Permission.objects.get_or_create instead or to call django.contrib.auth.management.create_permissions manually prior to doing Permission.objects.get instead by passing (apps.get_app_config('auth'), using=schema_editor.connection.alias, apps=apps).