Finn
Finn

Reputation: 163

Django manual migration to add group

I am attempting to create a migration that will automatically add a group and permissions to the group when it is run. I adapted some code from the docs and an example. I can get the migration to add the group but not the permissions. I am getting the following error: TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use permissions.set() instead. I am not sure how to implement this suggestion. Any ideas?

The migration:


from django.db import migrations, models
from django.contrib.auth.models import Group, Permission
from django.contrib.auth.management import create_permissions



def add_group_permissions(apps, schema_editor):
    for app_config in apps.get_app_configs():
        create_permissions(app_config, apps=apps, verbosity=0)

    # Employee
    group, created = Group.objects.get_or_create(name='Employee')
    if created:
        permissions_qs = Permission.objects.filter(
                         codename__in=[
                                         'can_add_how_to_entry',
                                         'can_change_how_to_entry',
                                         'can_view_how_to_entry',
                                                      ]
        )
        group.permissions = permissions_qs
        group.save()

class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(add_group_permissions),
    ]

Upvotes: 0

Views: 753

Answers (1)

Jonathan Quispe
Jonathan Quispe

Reputation: 614

Remember that group.permissions is a related query manager, not a field, so if you assign something to that you will destroy it. So you need to do something like:

permissions_qs = Permission.objects ...
for permission in permissions_qs:
    group.permissions.add(permission)
group.save()

Additionally, the Django way to create custom permission is through the Meta class, for example:

# Assuming that you have an "Entry" model

class Entry(models.Model):
    ...
    class Meta:
        ...
        permissions = [
            ('custom_permission_a', 'a description for permission a'),
            ('custom_permission_b', 'a description for permission b'),
        ]

After migrating the changes you will have two additional permissions attached to the Entry model.

Now you can create a group with the custom permissions like:

group, created = Group.objects.get_or_create(name='CustomGroup')
if created:
    permissions = Permission.objects.filter(
        codename__in=[
            'custom_permission_a',
            'custom_permission_b',
        ]
    )
    for p in permissions:
    group.permissions.add(p)
    group.save()

You can include that in a new migration or whatever you want, also if you don't want to use the Meta class to create your custom permissions, you can do it programmatically:

# Assuming that you have an Entry model

# Import Entry model

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

entryContentType = ContentType.objects.get_for_model(Entry)
 
# Create custom permission
custom_permission = Permission.objects.create(
    codename ='custom_permission',
    name ='description for the custom permission',
    content_type = entryContentType
)

A custom_permission will be created and attached to the Entry model. Then you can include that permission in your custom group.

Upvotes: 1

Related Questions