Aithusa
Aithusa

Reputation: 169

Creating custom permission in data migration

I was trying to create a custom permission in a migration, however after running migrate, the permission was not created in the permission table. Could someone point out what the error was? Also I am not sure what I should use as the related model for ContentType as the permission is used for restricting users that can view a page which shows summary of users on the site. Any help will be greatly appreciated, thanks.

def add_view_aggregated_data_permissions(apps, schema_editor):
    ContentType = apps.get_model('django', 'ContentType')
    Permission = apps.get_model('auth', 'Permission')
    content_type = ContentType.objects.get(app_label='auth', model='user')
    permission = Permission.objects.create(codename='can_view_data',
                                           name='Can view data',
                                           content_type=content_type)

Upvotes: 4

Views: 5030

Answers (3)

Shil Nevado
Shil Nevado

Reputation: 766

I wanted to created a custom permission (read) for all app models. I did this two steps:

  1. Create an extended permission from DjangoModelPermissions:

    class DjangoModelPermissionsExtended(DjangoModelPermissions):
        """
        """
        perms_map = {
            'GET': ['%(app_label)s.read_%(model_name)s'],
            'OPTIONS': [],
            'HEAD': [],
            'POST': ['%(app_label)s.add_%(model_name)s'],
            'PUT': ['%(app_label)s.change_%(model_name)s'],
            'PATCH': ['%(app_label)s.change_%(model_name)s'],
            'DELETE': ['%(app_label)s.delete_%(model_name)s'],
        }
    
  2. Put it in each view I want to have read permission:

    class ExampleViewSet(viewsets.ModelViewSet):
        permission_classes = (
            DjangoModelPermissionsExtended,
        )
    
  3. Create a django command customread.py:

    from django.core.management.base import BaseCommand, CommandError
    from project.app import models as app_models
    from django.db import models
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    import inspect
    
    class Command(BaseCommand):
    help = 'Create the read permission to app models'
    
    def handle(self, *args, **options):
        for name, obj in inspect.getmembers(app_models):
            if inspect.isclass(obj) and issubclass(obj, models.Model):
                try:
                    self.add_canread(obj)
                    self.stdout.write(self.style.SUCCESS(
                        'created permission for %s' % obj
                    ))
                except Exception as e:
                    self.stdout.write(self.style.ERROR(
                        'Permission already exists for %s' % obj
                    ))
    
    def add_canread(self, object_class):
        """This a function that can be executed in order to create
        new permissions (read view) to a class in DB.
    
        """
        if inspect.isclass(object_class):
            content_type = ContentType.objects.get_for_model(object_class)
            permission = Permission.objects.create(
                codename='read_{}'.format(object_class._meta.model_name),
                name='Can view {}'.format(object_class.__name__),
                content_type=content_type,
            )
        else:
            msg = "The object is not a class"
            print(msg)
    
  4. Execute it after doing migrations:

    python manage.py customread
    

Upvotes: 1

elewinso
elewinso

Reputation: 2521

As of django 1.8 and built-in migrations this is very painless.

  1. All you need to do is add the permissions you want to the relevant model
  2. Run makemigration

    ./manage.py makemigrations

  3. run the migration created in the step above

    ./manage.py migrate

Upvotes: 0

Wtower
Wtower

Reputation: 19902

I would recommend you to use the standard way to use custom permissions as described in the Django documentation. You will avoid many issues altogether.

To create custom permissions for a given model object, use the permissions model Meta attribute.

This example model creates a custom permission:

class MyModel(models.Model):
    ...
    class Meta:
        permissions = (
            ('view_data', "Can see available data"),
        )

The only thing this does is create those extra permissions when you run manage.py migrate. Your code is in charge of checking the value of these permissions when a user is trying to access the functionality provided by the application...

Then you can use the permission_required decorator with your view to check for the specific permission:

from django.contrib.auth.decorators import permission_required

@permission_required('myapp.view_data')
def my_view(request):
    ...

Upvotes: 5

Related Questions