Repository: encode/django-rest-framework

Issue:
AttributeError on self.request, self.args and self.kwargs
## 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](https://groups.google.com/forum/#!forum/django-rest-framework) 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](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.)
- [x] I have reduced the issue to the simplest possible case.
- [x] 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

Create a `ViewSet` and overwrite `dispatch` method and try to access one of `self.request`, `self.args` or `self.kwargs` before calling `super`

## Expected behavior

It should return the appropriate objects

## Actual behavior

It raises `AttributeError`


This should be related to this Django ticket https://code.djangoproject.com/ticket/19316 which was fixed before 5 years in Django 1.6 and backported to Django 1.5.
The solution is to set these in the decorator generated in `as_view` method as Django does (https://github.com/django/django/commit/ea6b95dbec77371d517392ffb465017b8eb7001c)

I can try to prepare a PR


Discussion:

Resolving patch:
diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py
--- a/rest_framework/viewsets.py
+++ b/rest_framework/viewsets.py
@@ -82,6 +82,10 @@ def view(request, *args, **kwargs):
             if hasattr(self, 'get') and not hasattr(self, 'head'):
                 self.head = self.get
 
+            self.request = request
+            self.args = args
+            self.kwargs = kwargs
+
             # And continue as usual
             return self.dispatch(request, *args, **kwargs)
 


Test patch:
diff --git a/tests/test_viewsets.py b/tests/test_viewsets.py
--- a/tests/test_viewsets.py
+++ b/tests/test_viewsets.py
@@ -13,6 +13,15 @@ def list(self, request, *args, **kwargs):
         return Response({'ACTION': 'LIST'})
 
 
+class InstanceViewSet(GenericViewSet):
+
+    def dispatch(self, request, *args, **kwargs):
+        return self.dummy(request, *args, **kwargs)
+
+    def dummy(self, request, *args, **kwargs):
+        return Response({'view': self})
+
+
 class InitializeViewSetsTestCase(TestCase):
     def test_initialize_view_set_with_actions(self):
         request = factory.get('/', '', content_type='application/json')
@@ -42,3 +51,17 @@ def test_initialize_view_set_with_empty_actions(self):
                               "For example `.as_view({'get': 'list'})`")
         else:
             self.fail("actions must not be empty.")
+
+    def test_args_kwargs_request_action_map_on_self(self):
+        """
+        Test a view only has args, kwargs, request, action_map
+        once `as_view` has been called.
+        """
+        bare_view = InstanceViewSet()
+        view = InstanceViewSet.as_view(actions={
+            'get': 'dummy',
+        })(factory.get('/')).data['view']
+
+        for attribute in ('args', 'kwargs', 'request', 'action_map'):
+            self.assertNotIn(attribute, dir(bare_view))
+            self.assertIn(attribute, dir(view))