According to the docs custom permissions can be created and used like this:
class Task(models.Model):
...
class Meta:
permissions = (
("view_task", "Can see available tasks"),
)
Using the permission:
user.has_perm('app.view_task')
Source: https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#custom-permissions
If there is a typo in the permission string. For example: I use user.has_perm('app.view_tasks')
, then this typo won't be noticed.
I would like to get an exception or warning if not existing permissions get used.
To avoid typos in the first place, I would like to have constants: user.PERM_APP_VIEW_TASKS
or something like this.
Override the has_perm
method of the ModelBackend
class, from my backends.py
file:
import logging
from difflib import get_close_matches
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
class ModelBackendHelper(ModelBackend):
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active:
return False
else:
obj_perms = self.get_all_permissions(user_obj, obj)
allowed = perm in obj_perms
if not allowed:
if settings.DEBUG:
similar = get_close_matches(perm, obj_perms)
if similar:
logging.warn("{0} not found, but is similar to: {1}".format(perm, ','.join(similar)))
return allowed
How it works:
Same logic of has_perm
but if settings.DEBUG
is True
and similar versions of perm
are found then output a warning log message of level WARN
:
WARNING:root:myapp.view_tasks not found, but is similar to: myapp.view_task
Change the value of AUTHENTICATION_BACKENDS
in settings.py
:
AUTHENTICATION_BACKENDS = ['myapp.backends.ModelBackendHelper']
This can be used both in production and development environments but personally I wouldn't include this in a production site, I hope that when everything goes to production permissions are consolidated.
Permissions belong to models and to keep this DRY I'm reusing the permissions defined in Meta
:
from django.db import models
class Task(models.Model):
name = models.CharField(max_length=30)
description = models.TextField()
class Meta:
permissions = (
("view_task", "Can see available tasks"),
)
def _get_perm(model, perm):
for p in model._meta.permissions:
if p[0] == perm:
return p[0]
err = "Permission '{0}' not found in model {1}".format(perm, model)
raise Exception(err)
def format_perm(perm):
return '{0}.{1}'.format(__package__, perm)
def get_perm(model, type):
return format_perm(_get_perm(model, type))
PERM_APP_VIEW_TASK = get_perm(Task, "view_task")
Permissions can be accessed with get_perm
or with a shortcut PERM_APP_VIEW_TASK
:
models.PERM_APP_VIEW_TASK
# or
get_perm(Task, "view_task")
# or
format_perm(_get_perm(Task, "view_task"))
In case of searching for a missing permission get_perm
will raise an Exception
:
PERM_APP_VIEW_TASK = get_perm(Task, "add_task")
Message:
Exception: Permission 'add_task' not found in model <class 'myapp.models.Task'>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With