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?
Asked
Active
Viewed 3,970 times
7

anon
- 1,069
- 1
- 12
- 17
-
Do you mean you want to make information in the admin read-only? – markwalker_ Oct 19 '15 at 03:50
-
@marksweb : Yes, but only for a specific group of users. I don't to make it read only globally across all the groups. – anon Oct 19 '15 at 07:08
-
3Nobody has answered the question why is the `view` permission missing. – mehmet Oct 27 '16 at 14:43
-
My suspect is that you use custom managers and the objects that are not viewable gets filtered out in the first place so there is no need to check view permission. But I am not sure if this will work in all scenarios, e.g. related models. – mehmet Oct 27 '16 at 14:47
-
1It's being added in 2.1: https://code.djangoproject.com/ticket/8936 – Nick Sweeting Jun 18 '18 at 21:12
2 Answers
6
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(self, 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.
-
How does it compare with django-admin-view-permission [https://github.com/ctxis/django-admin-view-permission] ? – Don Sep 28 '17 at 10:19
2
I think this should work:
1.Add "view" permission, see https://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')
-
I want the permissions to be assigned differently across different groups as in my comment to the question. – anon Oct 19 '15 at 07:11
-