My API allows access (any request) to certain objects only when a user is authenticated and certain other conditions are satisfied.
class SomethingViewSet(viewsets.ModelViewSet):
queryset = Something.objects.filter(query_hiding_non_authorized_objects)
serializer_class = SomethingSerializer
permission_classes = (permissions.IsAuthenticated, SomePermission)
If a user attempts to view a non-authorized object DRF returns a 403 error, however, this gives away that an object with the requested id exists. How can I return 404 errors in these cases?
Note: I also use a custom queryset to hide non-authorized objects from being listed.
The Http404 exceptionIf you raise Http404 at any point in a view function, Django will catch it and return the standard error page for your application, along with an HTTP error code 404. In order to show customized HTML when Django returns a 404, you can create an HTML template named 404.
Custom exception handlingThe exception handler function should either return a Response object, or return None if the exception cannot be handled. If the handler returns None then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page. Let's do that by turning off Django debug mode. For this, we need to update the settings.py file.
REST framework requires the following: Python (3.6, 3.7, 3.8, 3.9, 3.10) Django (2.2, 3.0, 3.1, 3.2, 4.0, 4.1)
As you already hide them in get_queryset just removing the permission will net you a 404 instead.
edit: you can also override the permission_denied method in your View class to throw another exception, this is the default implementation:
def permission_denied(self, request, message=None):
""" If request is not permitted, determine what kind of exception to raise.
"""
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message)
I think you can use custom exception handler in this case,
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response.status_code == 403:
response.status_code = 404
return response
In settings:
REST_FRAMEWORK = {
'EXCEPTION_HANDLER':
'my_project.my_app.utils.custom_exception_handler'
}
Second Method
from rest_framework.exceptions import APIException
class CustomForbidden(APIException):
status_code = status.HTTP_404_NOT_FOUND
class CustomPermission(permissions.BasePermission):
def has_permission(self, request, view):
if not_allowed:
raise CustomForbidden
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