django的objects级别的权限控制
django自带的权限控制是model级别权限控制,并没有提供对Object级别的权限控制,而只是在架构上留了口子。所以想要进行更细小化颗粒的权限,必须自定义权限,但是对于以下简单的验证来说,自定义权限先得工作量胎发,这里提供django-guardian进行objects级别的权限控制。
步骤如下:
1.安装django-guardian
pip install django-guardian
2. INSTALLED_APPS变量中加入guardian:
INSTALLED_APPS = ( # ... 'guardian', )
3.然后加入到身份验证后端AUTHENTICATION_BACKENDS
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # Django默认
'guardian.backends.ObjectPermissionBackend', # guardian
)
注意事项:
当多数据库时,django的权限控制存在bug,指定数据库路由对于权限来说其实是失效的,此时django只会去找默认的用户数据库里找object对应的表,这样会导致该表不存在。
File "/usr/lib/python2.7/site-packages/guardian/shortcuts.py", line 116, in assign_perm
return model.objects.assign_perm(perm, user, obj)
File "/usr/lib/python2.7/site-packages/guardian/managers.py", line 49, in assign_perm
obj_perm, _ = self.get_or_create(**kwargs)
File "/usr/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 466, in get_or_create
return self._create_object_from_params(lookup, params)
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 498, in _create_object_from_params
obj = self.create(**params)
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 394, in create
obj.save(force_insert=True, using=self.db)
File "/usr/lib/python2.7/site-packages/guardian/models.py", line 32, in save
content_type = get_content_type(self.content_object)
File "/usr/local/lib/python2.7/site-packages/django/contrib/contenttypes/fields.py", line 258, in __get__
rel_obj = ct.get_object_for_this_type(pk=pk_val)
File "/usr/local/lib/python2.7/site-packages/django/contrib/contenttypes/models.py", line 174, in get_object_for_this_type
return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 374, in get
num = len(clone)
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 232, in __len__
self._fetch_all()
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 1118, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch)
File "/usr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 899, in execute_sql
raise original_exception
ProgrammingError: (1146, "Table 'userfeedback.ai_report' doesn't exist")
解决方法:
对报错回溯发现报错是在
File "/usr/local/lib/python2.7/site-packages/django/contrib/contenttypes/models.py", line 174, in get_object_for_this_type这里发生的。
return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
此时进入/usr/local/lib/python2.7/site-packages/django/contrib/contenttypes/models.py的174行,发现调用using(self._state.db)只会调用的当前的默认连接,此时将
return self.model_class()._base_manager.using(self._state.db).get(**kwargs)改为 return self.model_class()._base_manager.get(**kwargs),直接调用django的
orm查询管理器即可解决问题。
具体修改见下图标红的地方。
def get_object_for_this_type(self, **kwargs):
"""
Returns an object of this type for the keyword arguments given.
Basically, this is a proxy around this object_type's get_object() model
method. The ObjectNotExist exception, if thrown, will not be caught,
so code that calls this method should catch it.
"""
#return self.model_class()._base_manager.using(self._state.db).get(**kwargs)
return self.model_class()._base_manager.get(**kwargs)
def get_all_objects_for_this_type(self, **kwargs):
"""
Returns all objects of this type for the keyword arguments given.
"""
#return self.model_class()._base_manager.using(self._state.db).filter(**kwargs)
return self.model_class()._base_manager.filter(**kwargs)