Django-rest-framework: Suspected django 2 incompatibility in DRF >= 3.7.4 request.py __init__ method's request object

Created on 18 Feb 2018  ·  7Comments  ·  Source: encode/django-rest-framework

Checklist

  • [x] I have verified that that issue exists against the master branch of Django REST framework.
  • [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
  • [x] This is not a usage question. (Those should be directed to the discussion group instead.)
  • [x] This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
  • [x] I have reduced the issue to the simplest possible case.
  • [ ] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)

Steps to reproduce

DRF >= 3.7.4 and Django 2

Try a basic view similar to this.

class FooList(generics.ListAPIView):
    permission_classes = (permissions.isAuthenticated,)
    model = Foo
    serializer_class = FooSerializer
    pagination_class = None

    def get_queryset(self):
        return Foo.objects.filter(business_logic_here)

More discussion here: https://groups.google.com/d/msg/django-rest-framework/mxzgI0n_VZg/ra-M95fhCgAJ

Expected behavior

Valid Http response

Actual behavior

Works fine in 3.7.3, fails in >= 3.7.4. Traceback: (assuming our venv is in /srv)

File “/srv/lib/python3.6/site-packages/django/core/handlers/exception.py” in inner
35.             response = get_response(request)
File “/srv/lib/python3.6/site-packages/django/core/handlers/base.py” in _get_response
128.                 response = self.process_exception_by_middleware(e, request)
File “/srv/lib/python3.6/site-packages/django/core/handlers/base.py” in _get_response
126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/srv/lib/python3.6/site-packages/django/views/decorators/csrf.py” in wrapped_view
54.         return view_func(*args, **kwargs)
File “/srv/lib/python3.6/site-packages/django/views/generic/base.py” in view
69.             return self.dispatch(request, *args, **kwargs)
File “/srv/lib/python3.6/site-packages/django/utils/decorators.py” in _wrapper
62.             return bound_func(*args, **kwargs)
File “/srv/lib/python3.6/site-packages/django/views/decorators/csrf.py” in wrapped_view
54.         return view_func(*args, **kwargs)
File “/srv/lib/python3.6/site-packages/django/views/generic/base.py” in view
69.             return self.dispatch(request, *args, **kwargs)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in dispatch
494.             response = self.handle_exception(exc)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in handle_exception
454.             self.raise_uncaught_exception(exc)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in dispatch
491.             response = handler(request, *args, **kwargs)
File “/srv/lib/python3.6/site-packages/rest_framework/decorators.py” in handler
53.             return func(*args, **kwargs)
File “/srv/lib/python3.6/site-packages/django/utils/decorators.py” in bound_func
58.                 return func.__get__(self, type(self))(*args2, **kwargs2)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in dispatch
477.         request = self.initialize_request(request, *args, **kwargs)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in initialize_request
381.             parser_context=parser_context
File “/srv/lib/python3.6/site-packages/rest_framework/request.py” in _init_
159.             .format(request.__class__.__module__, request.__class__.__name__)

Exception Type: AssertionError at /API/foo/the_pk/ Exception Value: The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`.
Needs information

Most helpful comment

I seem to be suffering from this same issue. I'm trying to return the response from a different view function from my view. i.e. I'm calling another view function and passing in the request I got passed. e.g. return my_other_view(request, slug)

I've worked around it by changing the above to my_other_view(request._request, slug), which seems a little hacky.

All 7 comments

This part of the trace doesn't looks right:

File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in dispatch
494.             response = self.handle_exception(exc)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in handle_exception
454.             self.raise_uncaught_exception(exc)
File “/srv/lib/python3.6/site-packages/rest_framework/views.py” in dispatch
491.             response = handler(request, *args, **kwargs)
File “/srv/lib/python3.6/site-packages/rest_framework/decorators.py” in handler
53.             return func(*args, **kwargs)

handle_exception doesn't re-dispatch a view.

Can you provide more context? Or, better yet, add a test case which demonstrates this behaviour.
(As described this is a pretty basic use-case, which is covered by the test suite, so it looks like something else is going on in your project.)

Let's close this off. We can consider re-opening if there's more info or if anyone else confirms similar issue.

I seem to be suffering from this same issue. I'm trying to return the response from a different view function from my view. i.e. I'm calling another view function and passing in the request I got passed. e.g. return my_other_view(request, slug)

I've worked around it by changing the above to my_other_view(request._request, slug), which seems a little hacky.

Hi @lllama. There is related discussion in #5771, but the short answer is that requests are not designed to be reprocessed by a view, and there may be unintended side effects. You can do this safely under certain conditions, but it's not supported functionality. i.e., it is hacky.

Thanks @rpkilby I've looked through our code path and it looks like we were being super lazy and perhaps taking DRY a little too far. I'll copy/paste the ~5 lines of code and remove the hack.

What are the ~5 lines of code we can use instead of the _request hack? @lllama

@littlehome-eugene: Extract your business logic into a reusable function, so it can be imported and called independently of the request-reponse cycle. Then call that in your other view, rather than reusing the view directly. (That's it. 🙂)

Was this page helpful?
0 / 5 - 0 ratings