Skip to content

Missing permission warnings when migrating #65

@XanderVertegaal

Description

@XanderVertegaal

If I start with an empty database and try to run this migration, my console is flooded with warnings such as ContentType for problem.knowledgebase does not exist. Cannot add permission ('problem', 'add_knowledgebase') to group Master Annotators.

My guess is that this is because Django only creates the permissions after the migrations have run.

The migrations themselves 'pass' and there is an easy workaround for the now missing permissions: unapply and reapply the migration in question with

python manage.py migrate user 0003
python manage.py migrate

Still, it would be nicer to avoid having to do this manual step, especially since the warnings are easily missed.

One solution would be to create the relevant permissions themselves within the migration, i.e. update create_groups to:

def create_groups(apps, schema_editor):
    """
    Creates user groups for annotators and master annotators and assigns permissions to them.
    """
    Group = apps.get_model("auth", "Group")
    Permission = apps.get_model("auth", "Permission")
    ContentType = apps.get_model("contenttypes", "ContentType")

    problem_model_name = apps.get_model("problem", "Problem")._meta.model_name
    knowledgebase_model_name = apps.get_model("problem", "KnowledgeBase")._meta.model_name
    ContentType.objects.get_or_create(app_label="problem", model=problem_model_name)
    ContentType.objects.get_or_create(app_label="problem", model=knowledgebase_model_name)

    for group_name, perms in PERMISSION_MAP.items():
        group, created = Group.objects.get_or_create(name=group_name.value)
        for perm_codename in perms:
            app_label, codename = perm_codename

            # Determine which model this permission is for
            if 'knowledgebase' in codename:
                model_name = knowledgebase_model_name
            else:
                model_name = problem_model_name

            try:
                content_type = ContentType.objects.get(app_label=app_label, model=model_name)
                permission, _ = Permission.objects.get_or_create(
                    content_type=content_type,
                    codename=codename,
                    defaults={'name': f'Can {codename.replace("_", " ")}'},
                )
                group.permissions.add(permission)
            except ContentType.DoesNotExist:
                print(
                    f"ContentType for {app_label}.{model_name} does not exist. Cannot add permission {perm_codename} to group {group_name.value}."
                )
            except Exception as e:
                print(
                    f"Error adding permission {perm_codename} to group {group_name.value}: {e}"
                )

This works, but it requires maintenance if we add permissions for more models, for instance. It also feels clunky to create permissions ourselves when Django is about to do that for us.

An alternative would be to use fixtures instead of data migrations. We can store the permission data as JSON and use Django's loaddata to populate a new database after migrations have run. This is how we do it in DIAPP, for instance, and I think it works well for this static/initial data that we need to load in.

What do you think @jgonggrijp ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    No fields configured for Bug.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions