Repository: django-json-api/django-rest-framework-json-api

Issue:
Including data fails on a List endpoint
/api/widgets?include=parent_widget

```
rest_framework_json_api/utils.py", line 419, in extract_included
    relation_instance_or_manager = getattr(resource_instance, field_name)
AttributeError: 'NoneType' object has no attribute 'parent_widget'
```



Discussion:
You're going to need to include a little more information. What does your serializer look like, if you want to include a relation you need to specify the `included_serializers` property.

Obviously an Http 500 error code is not the correct response. Personally I'm unsure what should be returned when you include a resource on a collection. Does JSON-API allow for includes on resource collections?

@rollokb I think @jerel is making ourselves a note here - :smile: 

While I personally don't have similar issues with the code I wrote (beside some issues that were encountered namely in #127 and #126) @jerel for the sake of clarity - it is true that adding your models and serializers could help here :)

Yeah, I'm recording the issue for anyone that wants to fix or that hits the same error. I doubt I'll work on it before Thursday. http://jsonapi.org does not explicitly say if inclusion should work on a collection endpoint but the very last example here shows it: http://jsonapi.org/format/#fetching-includes

``` python
from rest_framework_json_api import serializers

class WidgetSerializer(serializers.ModelSerializer):

    included_serializers = {
        'parent_widget': ParentWidgetSerializer,
    }

    class Meta:
        model = Widget
        fields = ('id', 'parent_widget',)
```

where the `Widget` model has a foreign key pointing at `ParentWidget`. Detail views work fine, this is just a List issue.


Resolving patch:
diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py
--- a/rest_framework_json_api/utils.py
+++ b/rest_framework_json_api/utils.py
@@ -402,8 +402,11 @@ def extract_relationships(fields, resource, resource_instance):
 
 
 def extract_included(fields, resource, resource_instance, included_resources):
-    included_data = list()
+    # this function may be called with an empty record (example: Browsable Interface)
+    if not resource_instance:
+        return
 
+    included_data = list()
     current_serializer = fields.serializer
     context = current_serializer.context
     included_serializers = get_included_serializers(current_serializer)
@@ -419,13 +422,19 @@ def extract_included(fields, resource, resource_instance, included_resources):
 
         try:
             included_resources.remove(field_name)
-            new_included_resources = [key.replace('%s.' % field_name, '', 1) for key in included_resources]
-            relation_instance_or_manager = getattr(resource_instance, field_name)
-            serializer_data = resource.get(field_name)
         except ValueError:
             # Skip fields not in requested included resources
             continue
 
+        try:
+            relation_instance_or_manager = getattr(resource_instance, field_name)
+        except AttributeError:
+            # For ManyRelatedFields if `related_name` is not set we need to access `foo_set` from `source`
+            relation_instance_or_manager = getattr(resource_instance, field.child_relation.source)
+
+        new_included_resources = [key.replace('%s.' % field_name, '', 1) for key in included_resources]
+        serializer_data = resource.get(field_name)
+
         if isinstance(field, ManyRelatedField):
             serializer_class = included_serializers.get(field_name)
             field = serializer_class(relation_instance_or_manager.all(), many=True, context=context)


Test patch:
diff --git a/example/tests/integration/test_includes.py b/example/tests/integration/test_includes.py
new file mode 100644
--- /dev/null
+++ b/example/tests/integration/test_includes.py
@@ -0,0 +1,20 @@
+import pytest, json
+from django.core.urlresolvers import reverse
+from example.tests.utils import load_json
+
+pytestmark = pytest.mark.django_db
+
+
+def test_included_data_on_list(multiple_entries, client):
+    multiple_entries[1].comments = []
+    response = client.get(reverse("entry-list") + '?include=comments')
+    included = load_json(response.content).get('included')
+
+    assert [x.get('type') for x in included] == ['comments']
+
+def test_included_data_on_detail(single_entry, client):
+    response = client.get(reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=comments')
+    included = load_json(response.content).get('included')
+
+    assert [x.get('type') for x in included] == ['comments']
+
diff --git a/example/tests/utils.py b/example/tests/utils.py
--- a/example/tests/utils.py
+++ b/example/tests/utils.py
@@ -3,6 +3,10 @@
 from django.utils.encoding import force_bytes, force_text
 
 
+def load_json(data):
+    return json.loads(force_text(data))
+
+
 def dump_json(data):
     '''
     Converts a Python object to a JSON formatted string.