TAGS :Viewed: 5 - Published at: a few seconds ago

[ Why does Django not have a view permission? ]

I have an active Django project where the admin panel is used by the customer support team. Django lacks a view permission because of which I have to assign the change permission to the customer support team which is slightly dangerous. I have some models for which the customer support team needs just the view access and not the change access because of security issues. Why is the view permision missing in Django? Any workaround to this?

Answer 1


I think this should work:

1.Add "view" permission, see http://stackoverflow.com/a/23411901/1266258

2.Customize "change" permission:

class FooAdmin(ModelAdmin):
    def has_change_permission(self, request, obj=None):
        # user can view the change list
        if not obj and request.user.has_perm('myapp.view_foo'):
            return True
        # user can view the change form and change the obj
        return request.user.has_perm('myapp.change_foo')

Answer 2


Here's a workaround.

Models

Simply create models with view permission by inheriting them from mixin:

class ViewPermissionsMixin(models.Model):
    """
        Mixin adds view permission to model.
    """
    class Meta:
        abstract=True
        default_permissions = ('add', 'change', 'delete', 'view')

Example model:

class ExampleModel(ViewPermissionsMixin):
    name = models.CharField(max_length=255)

    class Meta(ViewPermissionsMixin.Meta):
        abstract = False

This will add view permission that can be assigned to certain user/group. But such permission is useless without proper admin modification.

Admins

Here is mixin for your admins:

class AdminViewMixin(admin.ModelAdmin):

    def has_perm(self,user,permission):
        """
            Usefull shortcut for `user.has_perm()`
        """
        if user.has_perm("%s.%s_%s" % (self.model._meta.app_label,permission,self.model.__name__.lower(),)):
            return True
        return False

    def has_module_permission(request): # Django 1.8
        pass

    def has_change_permission(self, request, obj=None):
        """
            Necessary permission check to let Django show change_form for `view` permissions
        """
        if request.user.is_superuser:
            return True
        elif self.has_perm(request.user,'change'):
            return True
        elif self.has_perm(request.user,'view'):
            return True
        return super(AdminMixin, self).has_change_permission(request, obj)

    def get_readonly_fields(self, request, obj=None):
        """
            Turn each model field into read-only for `viewers`
        """
        all_model_fields = []
        for field in self.model._meta.fields:
            # TODO in Django 1.8 use ModelAdmin.get_fields()
            if not field.auto_created \
                and (not hasattr(field,'auto_now_add') or not field.auto_now_add) \
                and (not hasattr(field,'auto_now') or not field.auto_now) \
                :
                all_model_fields.append(field.name)
        if request.user.is_superuser:
            return self.readonly_fields
        elif self.has_perm(request.user,'change'):
            return self.readonly_fields
        elif self.has_perm(request.user,'view'):
            return all_model_fields
        return self.readonly_fields

    def change_view(self, request, object_id, extra_context=None):
        """
            Disable buttons for `viewers` in `change_view`
        """
        if request.user.is_superuser:
            pass
        elif self.has_perm(request.user,'change'):
            pass
        elif self.has_perm(request.user,'view'):
            extra_context = extra_context or {}
            extra_context['hide_save_buttons'] = True
        return super(AdminViewMixin, self).change_view(request, object_id, extra_context=extra_context)

Example admin:

@admin.register(models.ExampleModel)
class ExampleAdmin(AdminViewMixin):
    list_display = ('name',)
    pass

Finally just assign view permission for specific models to any user or group in your Django Admin.