heywbj / django-rest-framework-recursive

Recursive Serialization for Django REST framework
ISC License
367 stars 39 forks source link

AttributeError: 'RecursiveField' object has no attribute 'get_fields' #10

Closed ckcollab closed 8 years ago

ckcollab commented 8 years ago

Heyo! First of all: thanks for releasing and supporting this, really appreciate it!

class CategorySerializer(serializers.ModelSerializer):
    # We need special recursive serialization here for Category (parent) -> Category (child) relationship
    children = serializers.ListSerializer(read_only=True, child=RecursiveField())
    alternate_namings = CategoryOfficeNamingSerializer(many=True, required=False)

    class Meta:
        model = Category
        fields = (
            'id',
            'children',
            'parent',
            'order',
            'name',
            'alternate_namings',
        )

Using this Serializer with django-rest-swagger I get this error:

AttributeError: 'RecursiveField' object has no attribute 'get_fields'

Not sure if maybe I'm misusing RecursiveField? Thanks for any advice!

heywbj commented 8 years ago

What version of Python, Django, DRF are you using?

A stack trace would be nice too. Because I'm not sure why get_fields() is being called on the RecursiveField

ckcollab commented 8 years ago

Python 3.5 Django 1.9 django-rest-swagger==0.3.5 djangorestframework==3.3.2 djangorestframework-recursive==0.1.1

Stacktrace:

Internal Server Error: /docs/api-docs/api/categories
Traceback (most recent call last):
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 466, in dispatch
    response = self.handle_exception(exc)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 463, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework_swagger/views.py", line 164, in get
    'models': generator.get_models(apis),
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework_swagger/docgenerator.py", line 133, in get_models
    self._find_field_serializers(serializers)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework_swagger/docgenerator.py", line 279, in _find_field_serializers
    serializers_set))
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework_swagger/docgenerator.py", line 271, in _find_field_serializers
    fields = serializer().get_fields()
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework_recursive/fields.py", line 115, in __getattribute__
    return object.__getattribute__(self, name)
AttributeError: 'RecursiveField' object has no attribute 'get_fields'

Yeah I'm not sure why it's getting called either--should point to my actual serializer? I tried to add it as a "proxied" attribute while poking around RecursiveField source, but haven't been successful yet.

heywbj commented 8 years ago

https://github.com/marcgibbons/django-rest-swagger/blob/master/rest_framework_swagger/docgenerator.py#L273

There's a recursive method that is trying to discover serializer fields. For some reason, it detects the RecursiveField as an instance of BaseSerializer which is odd, since RecusiveField actually subclasses Field. Serializers do have a method get_fields, but Fields do not.

Edit: I went into my python interpreter to test if RecursiveField qualifies as an instance of BaseSerializer and it does not. I would go into the debugger in your program to see why it is happening.

ckcollab commented 8 years ago

The field is a ListSerializer with Child=RecursiveField() -- could that possibly be why? It seems to make sense that django-rest-swagger would detect it as inheriting BaseSerializer.

However, ListSerializer doesn't implement the get_fields method? I think I'll post this on rest-swagger github and try there--thanks!

heywbj commented 8 years ago

Oh... maybe you should try ListField instead of ListSerializer? I have always used ListField, anyway.

ckcollab commented 8 years ago

Ahhh! Nooo! Alright, trying that still seems to be borked:

TypeError: 'RelatedManager' object is not iterable

Full traceback, hope this is helpful:

Internal Server Error: /api/categories/
Traceback (most recent call last):
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/viewsets.py", line 87, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 466, in dispatch
    response = self.handle_exception(exc)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 463, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/mixins.py", line 48, in list
    return Response(serializer.data)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 674, in data
    ret = super(ListSerializer, self).data
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 239, in data
    self._data = self.to_representation(self.instance)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in to_representation
    self.child.to_representation(item) for item in iterable
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in <listcomp>
    self.child.to_representation(item) for item in iterable
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 472, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/fields.py", line 1476, in to_representation
    return [self.child.to_representation(item) for item in data]
TypeError: 'RelatedManager' object is not iterable
Internal Server Error: /api/categories/
Traceback (most recent call last):
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/viewsets.py", line 87, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 466, in dispatch
    response = self.handle_exception(exc)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/views.py", line 463, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/mixins.py", line 48, in list
    return Response(serializer.data)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 674, in data
    ret = super(ListSerializer, self).data
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 239, in data
    self._data = self.to_representation(self.instance)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in to_representation
    self.child.to_representation(item) for item in iterable
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 614, in <listcomp>
    self.child.to_representation(item) for item in iterable
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/serializers.py", line 472, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
  File "/Users/eric/.virtualenvs/image_first/lib/python3.5/site-packages/rest_framework/fields.py", line 1476, in to_representation
    return [self.child.to_representation(item) for item in data]
TypeError: 'RelatedManager' object is not iterable

Still digging... thanks for all your help!

heywbj commented 8 years ago

I've seen that before. It's got something to do with the fact that your 'children' field is a object manager, not an iterable in and of itself. I suspect you need to use the 'source' argument or something like that.

Someone else had your problem. They used a listserializer :) https://github.com/heywbj/django-rest-framework-recursive/issues/3

ckcollab commented 8 years ago

@heywbj thanks for all your help!

For anyone elses' reference, here's what ended up (kind of) working: children = serializers.ListField(child=RecursiveField(), source='children.all')

However, the swagger clientside stuff is still broken, some new JavaScript error now :(