Skip to content

Instantly share code, notes, and snippets.

@mcursa-jwt
Last active July 10, 2023 17:05
Show Gist options
  • Save mcursa-jwt/5021b4f2e67e014a816de1b194da0b43 to your computer and use it in GitHub Desktop.
Save mcursa-jwt/5021b4f2e67e014a816de1b194da0b43 to your computer and use it in GitHub Desktop.
Dynamic Custom Permission Registration for Django + DRF (thread-unsafe)

dynamically registering custom permissions

if you use this method of declaring custom drf permissions for your custom django model's Meta class perimssions

it might get tiring and difficult to maintain if you manually define a new class for each custom permission.

you can dynamically register these custom model permissions as drf permission classes using a base class factory that dynamically sets the __init__() method.

from django.apps import AppConfig
class YourappConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'yourapp'
def ready(self):
from yourapp.services import cust_permission
cust_permission.register_custom_permissions()
from django.contrib.auth.models import Permission
from typing import Iterable
class CustomPermission(BasePermission):
def __init__(self):
self.perms = ()
def has_permission(self, request, view):
if request.user.has_perms(self.perms):
return True
return False
def has_object_permission(self, request, view, obj):
return super().has_object_permission(request, view, obj)
def get_all(custom=True):
try:
if custom:
# custom permissions that don't follow default conventions
# can also search using models' `Meta` classes
perms = Permission.objects.all().filter(codename__regex=r'^(?!(add|change|delete|view)_).+')
else:
perms = Permission.objects.all()
except:
perms = None
finally:
return perms
def get_all_permission_labels(custom=True):
perms_q = get_all(custom)
if perms_q:
return [f"{perm.content_type.app_label}.{perm.codename}" for perm in perms_q]
def parse_permissions(permission_label:"str"):
if type(permission_label) == str:
return (permission_label,)
else:
raise Exception("invalid permission format. Each custom permission class can only have 1 custom permission")
def create_custom_drf_permission(name,permissoin_label:"str"):
CustomClass = type(name,(CustomPermission,),{})
def custom_init(self):
self.perms = parse_permissions(permissoin_label)
CustomClass.__init__ = custom_init
return CustomClass
permission_store = {}
def generate_custom_permissions():
permission_labels = get_all_permission_labels(custom=True)
for permission_label in permission_labels:
class_name = permission_label.replace(".","App_") # replace illegal class name char, add some info
permission_store[permission_label]=create_custom_drf_permission(class_name,permission_label)
def register_custom_permissions():
generate_custom_permissions()
import yourapp.permissions
from django.conf import settings
for PermTypeClass in permission_store.values():
setattr(yourapp.permissions, PermTypeClass.__name__, PermTypeClass)
settings.REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'].append(f"yourapp.permissions.{PermTypeClass.__name__}") # requires this to be created in settings.py
def get_custom_permission_type_class(permissionLabel):
return permission_store[permissionLabel] # might want to make this thread-safe in future
# empty placeholder module
# classes are registered by yourapp.services.cust_permission.register_custom_permissions
@mcursa-jwt
Copy link
Author

please let me know if you have a better solution! i have been searching for an easier way to no avail..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment