将 prefetch_related() 添加到 Django 身份验证后端
Add prefetch_related() to Django Authentication backend
在我的项目中,我同时拥有基于组和自定义用户的权限。
我有一个自定义身份验证后端,它主要检查用户是否具有组权限,然后查看他们是否有任何需要从已检查权限中删除的已撤销权限。
现在我正在 运行 遇到一个优化问题,因为我正在测试上述撤销权限的实现,因为我的 CustomUser 模型有一个 M2M 字段,其中包含与 [=13= 相关的这些撤销权限],我的 BackendAuthentication 检查它,我在页面加载时获得了疯狂的数据库点击量。
如何将预取对象传递到我的 AuthBackend?
这是我的 AuthBackend:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission
class UsersAuthenticationBackend(ModelBackend):
def _get_revoked_perms(self, user_obj):
if user_obj.is_superuser or user_obj.is_admin:
revoked_perms = Permission.objects.none()
elif hasattr(user_obj, 'revoked_permissions'):
# this causes the issue, I need to pass in the prefetch related to my model backend...HOW?
# this should be something like CustomUser.objects.prefetch_related('revoked_permissions')
revoked_perms = getattr(user_obj, 'revoked_permissions').values_list('content_type__app_label', 'codename')
else:
revoked_perms = Permission.objects.none()
revoked_perms = ["{}.{}".format(perm[0], perm[1]) for perm in revoked_perms]
print(revoked_perms)
return revoked_perms
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active:
return False
revoked_perms = self._get_revoked_perms(user_obj)
all_perms = self.get_all_permissions(user_obj)
allowed_perms = [p for p in all_perms if not p in revoked_perms]
if isinstance(perm, str):
return perm in allowed_perms
elif isinstance(perm, Permission):
return '{}.{}'.format(perm.content_type.app_label, perm.codename) in allowed_perms
else:
return False
这里是CustomUser的相关部分,如果你需要看的话
class CustomUser(AbstractUser, SafeDeleteModel):
...
revoked_permissions = models.ManyToManyField(Permission, blank=True)
我想出了一个解决方案来完成我需要的,尽管它是一个有点不错的解决方法...
我将 "Revoked Permissions" 更改为 "Extra Applied Permissions"(出于要求原因)并将模型字段从 M2M 关系更改为存储权限 content_type.app_label
和 codename
作为连接字符串,然后我将其用于比较。
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission
class UsersAuthenticationBackend(ModelBackend):
def _get_allowed_perms(self, user_obj):
if user_obj.is_superuser or user_obj.is_admin:
allowed_perms = []
elif hasattr(user_obj, 'extra_allowed_permissions'):
allowed_perms = user_obj.extra_allowed_permissions
else:
allowed_perms = []
# 'content_type__app_label'.'codename'
allowed_perms = [perm for perm in allowed_perms]
# print(allowed_perms)
return allowed_perms
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active:
return False
allowed_perms = self._get_allowed_perms(user_obj)
group_perms = self.get_group_permissions(user_obj)
# concat the perms for comparison
combined_perms = list(group_perms) + allowed_perms
if isinstance(perm, str):
return perm in combined_perms
elif isinstance(perm, Permission):
perm_string = '{}.{}'.format(perm.content_type.app_label, perm.codename)
return perm_string in combined_perms
else:
return False
这是模型更改:
class CustomUser(AbstractUser, SafeDeleteModel):
...
extra_allowed_permissions = JSONField(default=list, null=True, blank=True)
在我的项目中,我同时拥有基于组和自定义用户的权限。
我有一个自定义身份验证后端,它主要检查用户是否具有组权限,然后查看他们是否有任何需要从已检查权限中删除的已撤销权限。
现在我正在 运行 遇到一个优化问题,因为我正在测试上述撤销权限的实现,因为我的 CustomUser 模型有一个 M2M 字段,其中包含与 [=13= 相关的这些撤销权限],我的 BackendAuthentication 检查它,我在页面加载时获得了疯狂的数据库点击量。
如何将预取对象传递到我的 AuthBackend?
这是我的 AuthBackend:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission
class UsersAuthenticationBackend(ModelBackend):
def _get_revoked_perms(self, user_obj):
if user_obj.is_superuser or user_obj.is_admin:
revoked_perms = Permission.objects.none()
elif hasattr(user_obj, 'revoked_permissions'):
# this causes the issue, I need to pass in the prefetch related to my model backend...HOW?
# this should be something like CustomUser.objects.prefetch_related('revoked_permissions')
revoked_perms = getattr(user_obj, 'revoked_permissions').values_list('content_type__app_label', 'codename')
else:
revoked_perms = Permission.objects.none()
revoked_perms = ["{}.{}".format(perm[0], perm[1]) for perm in revoked_perms]
print(revoked_perms)
return revoked_perms
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active:
return False
revoked_perms = self._get_revoked_perms(user_obj)
all_perms = self.get_all_permissions(user_obj)
allowed_perms = [p for p in all_perms if not p in revoked_perms]
if isinstance(perm, str):
return perm in allowed_perms
elif isinstance(perm, Permission):
return '{}.{}'.format(perm.content_type.app_label, perm.codename) in allowed_perms
else:
return False
这里是CustomUser的相关部分,如果你需要看的话
class CustomUser(AbstractUser, SafeDeleteModel):
...
revoked_permissions = models.ManyToManyField(Permission, blank=True)
我想出了一个解决方案来完成我需要的,尽管它是一个有点不错的解决方法...
我将 "Revoked Permissions" 更改为 "Extra Applied Permissions"(出于要求原因)并将模型字段从 M2M 关系更改为存储权限 content_type.app_label
和 codename
作为连接字符串,然后我将其用于比较。
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission
class UsersAuthenticationBackend(ModelBackend):
def _get_allowed_perms(self, user_obj):
if user_obj.is_superuser or user_obj.is_admin:
allowed_perms = []
elif hasattr(user_obj, 'extra_allowed_permissions'):
allowed_perms = user_obj.extra_allowed_permissions
else:
allowed_perms = []
# 'content_type__app_label'.'codename'
allowed_perms = [perm for perm in allowed_perms]
# print(allowed_perms)
return allowed_perms
def has_perm(self, user_obj, perm, obj=None):
if not user_obj.is_active:
return False
allowed_perms = self._get_allowed_perms(user_obj)
group_perms = self.get_group_permissions(user_obj)
# concat the perms for comparison
combined_perms = list(group_perms) + allowed_perms
if isinstance(perm, str):
return perm in combined_perms
elif isinstance(perm, Permission):
perm_string = '{}.{}'.format(perm.content_type.app_label, perm.codename)
return perm_string in combined_perms
else:
return False
这是模型更改:
class CustomUser(AbstractUser, SafeDeleteModel):
...
extra_allowed_permissions = JSONField(default=list, null=True, blank=True)