Repository: django-tastypie/django-tastypie

Issue:
AsgiRequest object has no attribute '_read_started'
Hello.

There is a incompatibility with [Django Channels](https://channels.readthedocs.io/en/latest/).

Basically when I try to PATCH or PUT against a resource, it fails giving this traceback

```
Traceback:
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
  58.         return view_func(*args, **kwargs)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in wrapper
  220.                 response = callback(request, *args, **kwargs)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in dispatch_detail
  460.         return self.dispatch('detail', request, **kwargs)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in dispatch
  483.         response = method(request, **kwargs)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in patch_detail
  1652.         request = convert_post_to_patch(request)
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in convert_post_to_patch
  2528.     return convert_post_to_VERB(request, verb='PATCH')
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in convert_post_to_VERB
  2516.             request._load_post_and_files()
File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/http/request.py" in _load_post_and_files
  249.         if self._read_started and not hasattr(self, '_body'):

Exception Type: AttributeError at /api/v1/newsitem/1495/
Exception Value: 'AsgiRequest' object has no attribute '_read_started'
```

It get solved if I add `request._read_started = False` to `convert_post_to_VERB`, but I'm not sure if that's the right solution. I can send a pull request if that's OK.

By the way the issue is also opened at Django Channels github, but they say it's Tastypie fault. https://github.com/andrewgodwin/channels/issues/160

Thanks!



Discussion:
I recall looking into this during a code review, and at the time there was
no other alternative.  There are quite a few places where we have to dig
into django's internal 'private' vars due to no other options.

In this case, we could code even more defensively and check for
._read_started existing.  I worry, though, that we don't have good test
coverage for uploading files, so if django's internals ever do change we'll
suddenly be unable to upload files and have no test to catch it before a
release.

On Mon, Jul 4, 2016 at 6:00 AM, Miguel Sánchez notifications@github.com
wrote:

> Hello.
> 
> There is a incompatibility with Django Channels
> https://channels.readthedocs.io/en/latest/.
> 
> Basically when I try to PATCH or PUT against a resource, it fails giving
> this traceback
> 
> Traceback:
> File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
> 1.                     response = wrapped_callback(request, _callback_args, *_callback_kwargs)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
> 2.         return view_func(_args, *_kwargs)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in wrapper
> 3.                 response = callback(request, _args, *_kwargs)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in dispatch_detail
> 4.         return self.dispatch('detail', request, **kwargs)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in dispatch
> 5.         response = method(request, **kwargs)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in patch_detail
> 6.         request = convert_post_to_patch(request)
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in convert_post_to_patch
> 7.     return convert_post_to_VERB(request, verb='PATCH')
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/tastypie/resources.py" in convert_post_to_VERB
> 8.             request._load_post_and_files()
>    File "/home/miguelsanchez/.virtualenvs/accesohub/local/lib/python2.7/site-packages/django/http/request.py" in _load_post_and_files
> 9.         if self._read_started and not hasattr(self, '_body'):
> 
> Exception Type: AttributeError at /api/v1/newsitem/1495/
> Exception Value: 'AsgiRequest' object has no attribute '_read_started'
> 
> It get solved if I add request._read_started = False to
> convert_post_to_VERB, but I'm not sure if that's the right solution. I
> can send a pull request if that's OK.
> 
> By the way the issue is also opened at Django Channels github, but they
> say it's Tastypie fault. andrewgodwin/channels#160
> https://github.com/andrewgodwin/channels/issues/160
> 
> Thanks!
> 
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> https://github.com/django-tastypie/django-tastypie/issues/1473, or mute
> the thread
> https://github.com/notifications/unsubscribe/AAOl20bLWNDpe7rmNN2TVl-9UaTART4Qks5qSQQFgaJpZM4JEWay
> .


Resolving patch:
diff --git a/tastypie/resources.py b/tastypie/resources.py
--- a/tastypie/resources.py
+++ b/tastypie/resources.py
@@ -2522,6 +2522,9 @@ def convert_post_to_VERB(request, verb):
     Force Django to process the VERB.
     """
     if request.method == verb:
+        if not hasattr(request, '_read_started'):
+            request._read_started = False
+
         if hasattr(request, '_post'):
             del request._post
             del request._files


Test patch: