3

I noticed that when I use DRF documentation I get error AttributeError: 'NoneType' object has no attribute 'method' and this is associated with this line if self.request.method == 'POST' Any ideas how can I solve it?

views.py:

@permission_classes([UserPermission])
class UserObject(GenericAPIView):

    def get_serializer_class(self):

        if self.request.method == 'POST':
            return ObjectPostSerializer
        return ObjectSerializer

    def post(self, request, user_id):

        serializer = ObjectSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user_id=user_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def get(self, request, user_id):

        try:
            object = Object.objects.filter(user=user_id)
        except Object.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = ObjectSerializer(object, many=True)
        return Response(serializer.data)

    def put(self, request, user_id):

        try:
            object = Object.objects.get(user=user_id)
        except Object.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        serializer = ObjectSerializer(object, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, user_id):

        try:
            object = Object.objects.filter(user=user_id)
        except Object.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        object.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Traceback without self:

django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
django_1  |     response = get_response(request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
django_1  |     response = self.process_exception_by_middleware(e, request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
django_1  |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
django_1  |     return view_func(*args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
django_1  |     return self.dispatch(request, *args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 489, in dispatch
django_1  |     response = self.handle_exception(exc)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 449, in handle_exception
django_1  |     self.raise_uncaught_exception(exc)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 486, in dispatch
django_1  |     response = handler(request, *args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/views.py", line 31, in get
django_1  |     schema = self.schema_generator.get_schema(request, self.public)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/generators.py", line 279, in get_schema
django_1  |     links = self.get_links(None if public else request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/generators.py", line 317, in get_links
django_1  |     link = view.schema.get_link(path, method, base_url=self.url)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/inspectors.py", line 167, in get_link
django_1  |     fields += self.get_serializer_fields(path, method)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/inspectors.py", line 290, in get_serializer_fields
django_1  |     serializer = view.get_serializer()
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/generics.py", line 110, in get_serializer
django_1  |     serializer_class = self.get_serializer_class()
django_1  |   File "/code/backend/views.py", line 173, in get_serializer_class
django_1  |     if request.method == 'POST':
django_1  | NameError: name 'request' is not defined

Traceback with self:

django_1  | Traceback (most recent call last):
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
django_1  |     response = get_response(request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
django_1  |     response = self.process_exception_by_middleware(e, request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
django_1  |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
django_1  |     return view_func(*args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
django_1  |     return self.dispatch(request, *args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 489, in dispatch
django_1  |     response = self.handle_exception(exc)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 449, in handle_exception
django_1  |     self.raise_uncaught_exception(exc)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 486, in dispatch
django_1  |     response = handler(request, *args, **kwargs)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/views.py", line 31, in get
django_1  |     schema = self.schema_generator.get_schema(request, self.public)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/generators.py", line 279, in get_schema
django_1  |     links = self.get_links(None if public else request)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/generators.py", line 317, in get_links
django_1  |     link = view.schema.get_link(path, method, base_url=self.url)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/inspectors.py", line 167, in get_link
django_1  |     fields += self.get_serializer_fields(path, method)
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/schemas/inspectors.py", line 290, in get_serializer_fields
django_1  |     serializer = view.get_serializer()
django_1  |   File "/usr/local/lib/python3.6/site-packages/rest_framework/generics.py", line 110, in get_serializer
django_1  |     serializer_class = self.get_serializer_class()
django_1  |   File "/code/backend/views.py", line 173, in get_serializer_class
django_1  |     if self.request.method == 'POST':
django_1  | AttributeError: 'NoneType' object has no attribute 'method'
  • have you try without self ? – Aditia Pratama Oct 30 '17 at 09:46
  • @AditiaPratama Without self I get `name 'request' is not defined` –  Oct 30 '17 at 09:46
  • `GenericAPIView` has property `request` if you call it as view, but what are you do? go by url or create some tests – Brown Bear Oct 30 '17 at 09:55
  • 1
    Your method looks ok (`*args, **kwargs` is not needed, but that shouldn't make any difference). Can you edit the question and add the full traceback? – Håken Lid Oct 30 '17 at 09:56
  • @BearBrown I call is as view `url(r'^users/(?P[0-9]+)/objects$', views.UserObject.as_view())` –  Oct 30 '17 at 10:00
  • @HåkenLid I updated my question with tracebacks. –  Oct 30 '17 at 10:00
  • Can you have a look at the answer here? It looks pretty much the same problem https://stackoverflow.com/questions/38281651/django-rest-framework-self-context-doesnt-have-request-attribute – ChatterOne Oct 30 '17 at 10:00
  • Do you overrides the constructor or any other method for this class? If so, do you call the parent method? – luc Oct 30 '17 at 10:03
  • @luc I added my class to the updated question. –  Oct 30 '17 at 10:06
  • @JohnSmith I meant the `UserObject` class view – luc Oct 30 '17 at 10:07
  • @JohnSmith Is there the full code in your original post? – luc Oct 30 '17 at 10:08
  • @luc No, I have there POST, GET, PUT and DELETE mothod. –  Oct 30 '17 at 10:13
  • @JohnSmith I think, we don't need the model but you should put the full code of the view – luc Oct 30 '17 at 10:14
  • From the traceback, it seems you are using a `@csrf_exempt` view decorator? Where's that? – Håken Lid Oct 30 '17 at 10:15
  • @luc I added full code of the view. –  Oct 30 '17 at 10:21
  • @HåkenLid I don't use `@csrf_exempt` decorator in my `views.py`. I have in middleware `'django.middleware.csrf.CsrfViewMiddleware',`. –  Oct 30 '17 at 10:22
  • 1
    You're not even calling `get_serializer` method to invoke the `get_serializer_class` method – Sachin Oct 30 '17 at 10:23
  • @SachinKukreja But it is working properly. There is only a problem with DRF doc. For instance in Swagger I don't have any problem with it. –  Oct 30 '17 at 10:24
  • @JohnSmith Your code is strange because it looks that the traceback doesn't correspond to it. I agree with @SachinKukreja , `get_serializer_class`shouldn't be called here. – luc Oct 30 '17 at 10:29
  • @luc So how it should be done to have separated serializer `ObjectPostSerializer` for POST method and for others `ObjectSerializer`? –  Oct 30 '17 at 10:35
  • Since you're using GenericAPIView without any mixin classes, you have to override the get, post, etc. methods, through which you know that which request method it is. – Sachin Oct 30 '17 at 10:38
  • @SachinKukreja can you show me how it should be done in my GenericAPIView? –  Oct 30 '17 at 10:41

3 Answers3

0

You are using a function decorator with a class based view. This will cause undefined behaviour down the line, since the class instance will not be initialized correctly.

@permission_classes([UserPermission])
class UserObject(GenericAPIView):
    ...

Instead use a class property.

class UserObject(GenericAPIView):
    permission_classes = [UserPermission]

Docs: http://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy

Håken Lid
  • 22,318
  • 9
  • 52
  • 67
0

Remove the get_serializer_class method and you're good to go.

Modifications:

class UserObject(GenericAPIView):
    serializer_class = ObjectSerializer

    def post(self, request, user_id):
        # this is here you change the serializer.
        serializer = ObjectPostSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(user_id=user_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Sachin
  • 3,576
  • 1
  • 15
  • 24
  • I tried in this way before creating `get_serializer_class` and I was getting `'UserObject' should either include a serializer_class attribute, or override the get_serializer_class() method.` –  Oct 30 '17 at 11:08
0

I would separate the view to CreateAPIView and RetreiveAPIView and use different serializers for each of them.

Fedya Grab
  • 36
  • 6