Currently I have a project using django and rest_framework to get some basic APIs on the run.
The problem is, when i make a view using the generic lib on rest_framework and DjangoModelPermissions, my method get_queryset is being called twice
My Permission Class
class DefaultModelPermissions(DjangoModelPermissions):
"""
The request is authenticated using `django.contrib.auth` permissions.
See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions
It ensures that the user is authenticated, and has the appropriate
`view`/`add`/`change`/`delete` permissions on the model.
This permission can only be applied against view classes that
provide a `.queryset` attribute.
"""
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
'POST': ['%(app_label)s.add_%(model_name)s'],
'PUT': ['%(app_label)s.change_%(model_name)s'],
'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}
class DefaultModelViewPermissions:
permission_classes = (DefaultModelPermissions,)
My View
class AgentListCreateView(DefaultModelViewPermissions, generics.ListCreateAPIView):
serializer_class = serializers.AgentSerializer
def get_queryset(self):
print('get_queryset')
return models.Agent.objects.all()
Debbuging the app, I found out that the permission also call the get_queryset to retrieve the model to validate the django's user's permissions.
permission_calling_get_queryset
From my point of view, this is an unecessary operation. Deppending on the size of the DB table, this could be a major performance problem, and leed many other app issues.
My solution was to override this "has_permission" method. So my class got like
class DefaultModelPermissions(DjangoModelPermissions):
"""
The request is authenticated using `django.contrib.auth` permissions.
See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions
It ensures that the user is authenticated, and has the appropriate
`view`/`add`/`change`/`delete` permissions on the model.
This permission can only be applied against view classes that
provide a `.queryset` attribute.
"""
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
'POST': ['%(app_label)s.add_%(model_name)s'],
'PUT': ['%(app_label)s.change_%(model_name)s'],
'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}
def has_permission(self, request, view):
if not request.user or (
not request.user.is_authenticated and self.authenticated_users_only):
return False
# Workaround to ensure DjangoModelPermissions are not applied
# to the root view when using DefaultRouter.
if getattr(view, '_ignore_model_permissions', False):
return True
# Workaround cause base class utilized get_queryset to retrieve the model
# making unecessary requisitions to the database
if hasattr(view, 'get_serializer_class'):
model = view.get_serializer_class().Meta.model
else:
model = view.serializer_class.Meta.model
perms = self.get_required_permissions(request.method, model)
return request.user.has_perms(perms)
My question is: Is there a better way to get this around? Does anybody else got the same problem?