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

Issue:
get_related_resource_type returns parent model name
This is a simplified version of my API:

```
class Survey(models.Model):
    pass

class Question(models.Model):
    survey = models.ForeignKey(Survey, related_name='questions')

class SurveySerializer(serializers.ModelSerializer):
    class Meta:
        model = Survey
        fields = ('id', 'questions')
        read_only_fields = ('questions',)

class SurveyViewSet(viewsets.ModelViewSet):
     queryset = Survey.objects.all()
     serializer_class = SurveySerializer
```

Now if I request a survey, the type of the questions is not correct :

```
>>> GET '/surveys/1'
{
    'data': {
        'id': '1',
        'type': 'surveys',
        'attributes': {},
        'relationships': {
            'questions': {
                'data': [
                    {
                        'id': '1',
                        'type': 'surveys',
                        'attributes': {},
                    },
                ],
            },
        },
    },
}
```

The issue seems to be in `utils.get_related_resource_type`. I would submit a PR, but I'm not entirely sure how to fix it without breaking something else...

Also, I'm guessing that it will be necessary to be able to define a `resource_name` for related models and the relationships handling code will change, but this is still a big issue.



Discussion:
Pull latest version from github, I fixed that I think in some commit.

Thanks for the quick reply! I upgraded to the latest commit on "develop" and the problem is still happening...

Yes you are right, I couldn't see the whole picture from my cellphone. The `get_related_resource_type` method is hoping to be intelligent and tries to find the related name from the field name when everything else fails.

We are going to refactor this to be able to define a `resouce_name` as you suggested.

Actually, the more I read it the more I think the behavior is the right one - Model 'survey' is referencing to the  same model. so the relation model is in fact `survey` as well. Unless I misread your code...

Are you sure the output is the proper one? it doesn't make sense to have attributes where you put them under `questions`

The records in the `questions` relationship should have the type `questions`, not `surveys`.

Oups - yes you are right - sry

#74 should be merged with this.

This should be fixed by 64f8a6b, if it doesn't resolve your issue I'll reopen.

The proper model is now used, but the first letter is a capital, which is probably not intended ?

```
>>> GET '/surveys/1'
{
    'data': {
        ...
        'relationships': {
            'questions': {
                'data': [
                    {
                        'id': '1',
                        'type': 'Questions',
                        'attributes': {},
                    },
                ],
            },
        },
    },
}
```

@martinmaillard I noticed that behavior as well, I think this was introduced in commit https://github.com/django-json-api/django-rest-framework-json-api/commit/eeab4607a15960e0d784c1129dbfa7830b35b1c7 altough I would like @schtibe to comment on this as he might have done this on purpose

@jsenecal Yes and no. Actually, with this commit it would've been underscored (which wouldn't be the correct behaviour as well I guess?) Commit 5b6456763ed7cdd51660d5293b66cd899bee7a91 then removed the default underscore behaviour without introducing the lowercase-ing again.
Pull Request #92 wouldn't fix that either, and just return the values as-is. But it's exactly the place to fix it, see my comments there.

@martinmaillard FYI there is a new option to format these keys: https://github.com/django-json-api/django-rest-framework-json-api/blob/develop/docs/usage.md#relationship-types

That's great ! Thank you !

Now I'm gonna be really annoying: in my actual use case, the `questions` relationship is polymorphic. Each instance can have a different type subclassing `Question` (`GreatQuestion`, `SuperQuestion`). I think the whole point of specifying the type of each record in json-api is to support this kind of use case. So for `ManyRelatedField` and `ListSerializer`, the `relation_type` should probably be extracted for each instance, instead of once for the whole collection. What do you think ? Do you want me to make a PR so we can discuss on actual code ?

That sounds like a valid use case. I would welcome a PR so we can discuss it further


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
@@ -70,10 +70,10 @@ def get_resource_name(context):
             if not isinstance(resource_name, six.string_types):
                 return resource_name
 
-            resource_name = inflection.pluralize(resource_name.lower())
-
             resource_name = format_value(resource_name)
 
+            resource_name = inflection.pluralize(resource_name)
+
     return resource_name
 
 
@@ -94,17 +94,22 @@ def format_keys(obj, format_type=None):
     if format_type is None:
         format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)
 
-    if format_type in ('dasherize', 'camelize', 'underscore'):
+    if format_type in ('dasherize', 'camelize', 'underscore', 'capitalize'):
 
         if isinstance(obj, dict):
             formatted = OrderedDict()
             for key, value in obj.items():
                 if format_type == 'dasherize':
+                    # inflection can't dasherize camelCase
+                    key = inflection.underscore(key)
                     formatted[inflection.dasherize(key)] \
                         = format_keys(value, format_type)
                 elif format_type == 'camelize':
                     formatted[inflection.camelize(key, False)] \
                         = format_keys(value, format_type)
+                elif format_type == 'capitalize':
+                    formatted[inflection.camelize(key)] \
+                        = format_keys(value, format_type)
                 elif format_type == 'underscore':
                     formatted[inflection.underscore(key)] \
                         = format_keys(value, format_type)
@@ -121,8 +126,12 @@ def format_value(value, format_type=None):
     if format_type is None:
         format_type = getattr(settings, 'JSON_API_FORMAT_KEYS', False)
     if format_type == 'dasherize':
+        # inflection can't dasherize camelCase
+        value = inflection.underscore(value)
         value = inflection.dasherize(value)
     elif format_type == 'camelize':
+        value = inflection.camelize(value, False)
+    elif format_type == 'capitalize':
         value = inflection.camelize(value)
     elif format_type == 'underscore':
         value = inflection.underscore(value)
@@ -132,15 +141,10 @@ def format_value(value, format_type=None):
 def format_relation_name(value, format_type=None):
     if format_type is None:
         format_type = getattr(settings, 'JSON_API_FORMAT_RELATION_KEYS', False)
-    
+
     if not format_type:
-        # let's keep it the way it was
         return value
 
-    # in case the value is going to be changed, make it underscored first
-    # because dasherize does not work with a camel cased string
-    value = inflection.underscore(value)
-
     # format_type will never be None here so we can use format_value
     value = format_value(value, format_type)
 


Test patch:
diff --git a/example/tests/test_format_keys.py b/example/tests/test_format_keys.py
--- a/example/tests/test_format_keys.py
+++ b/example/tests/test_format_keys.py
@@ -37,7 +37,7 @@ def test_camelization(self):
         expected = {
             'data': [
                 {
-                    'type': 'Users',
+                    'type': 'users',
                     'id': encoding.force_text(user.pk),
                     'attributes': {
                         'firstName': user.first_name,
diff --git a/example/tests/test_utils.py b/example/tests/test_utils.py
--- a/example/tests/test_utils.py
+++ b/example/tests/test_utils.py
@@ -1,5 +1,6 @@
 import pytest
 
+from django.conf import settings
 from django.contrib.auth import get_user_model
 from rest_framework import serializers
 from rest_framework.response import Response
@@ -8,7 +9,7 @@
 
 pytestmark = pytest.mark.django_db
 
-class Resource(APIView):
+class ResourceView(APIView):
     pass
 
 class ResourceSerializer(serializers.ModelSerializer):
@@ -17,9 +18,15 @@ class Meta():
         model = get_user_model()
 
 def test_get_resource_name():
-    view = Resource()
+    view = ResourceView()
     context = {'view': view}
-    assert 'resources' == utils.get_resource_name(context), 'derived from view'
+    setattr(settings, 'JSON_API_FORMAT_KEYS', None)
+    assert 'ResourceViews' == utils.get_resource_name(context), 'not formatted'
+
+    view = ResourceView()
+    context = {'view': view}
+    setattr(settings, 'JSON_API_FORMAT_KEYS', 'dasherize')
+    assert 'resource-views' == utils.get_resource_name(context), 'derived from view'
 
     view.model = get_user_model()
     assert 'users' == utils.get_resource_name(context), 'derived from view model'
@@ -33,7 +40,7 @@ def test_get_resource_name():
     view.response = Response(status=500)
     assert 'errors' == utils.get_resource_name(context), 'handles 500 error'
 
-    view = Resource()
+    view = ResourceView()
     context = {'view': view}
     view.serializer_class = ResourceSerializer
     assert 'users' == utils.get_resource_name(context), 'derived from serializer'
@@ -50,6 +57,9 @@ def test_format_keys():
     output = {'firstName': 'a', 'lastName': 'b'}
     assert utils.format_keys(underscored, 'camelize') == output
 
+    output = {'FirstName': 'a', 'LastName': 'b'}
+    assert utils.format_keys(underscored, 'capitalize') == output
+
     output = {'first-name': 'a', 'last-name': 'b'}
     assert utils.format_keys(underscored, 'dasherize') == output
 
@@ -60,12 +70,14 @@ def test_format_keys():
     assert utils.format_keys([underscored], 'dasherize') == output
 
 def test_format_value():
-    assert utils.format_value('first_name', 'camelize') == 'FirstName'
+    assert utils.format_value('first_name', 'camelize') == 'firstName'
+    assert utils.format_value('first_name', 'capitalize') == 'FirstName'
     assert utils.format_value('first_name', 'dasherize') == 'first-name'
     assert utils.format_value('first-name', 'underscore') == 'first_name'
 
 def test_format_relation_name():
-    assert utils.format_relation_name('first_name', 'camelize') == 'FirstNames'
+    assert utils.format_relation_name('first_name', 'capitalize') == 'FirstNames'
+    assert utils.format_relation_name('first_name', 'camelize') == 'firstNames'
 
 def test_build_json_resource_obj():
     resource = {