From 1adac020a4889c8c4cb6fa1d51d6a509aaefb144 Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Thu, 5 Nov 2015 10:24:21 -0500 Subject: [PATCH 1/8] added a get_resource_type_from_model replaced other usages of getting model type by __name__ --- rest_framework_json_api/serializers.py | 2 +- rest_framework_json_api/utils.py | 28 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/rest_framework_json_api/serializers.py b/rest_framework_json_api/serializers.py index c0eaed72..61943b80 100644 --- a/rest_framework_json_api/serializers.py +++ b/rest_framework_json_api/serializers.py @@ -29,7 +29,7 @@ def to_representation(self, instance): } def to_internal_value(self, data): - if data['type'] != format_relation_name(self.model_class.__name__): + if data['type'] != get_resource_type_from_model(self.model_class): self.fail('incorrect_model_type', model_type=self.model_class, received_type=data['type']) pk = data['id'] try: diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index da88b5e8..d8a4e67a 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -50,7 +50,7 @@ def get_resource_name(context): return get_resource_type_from_serializer(serializer) except AttributeError: try: - resource_name = view.model.__name__ + resource_name = get_resource_type_from_model(view.model) except AttributeError: resource_name = view.__class__.__name__ @@ -182,7 +182,7 @@ def get_related_resource_type(relation): relation_model = parent_model_relation.field.related.model else: return get_related_resource_type(parent_model_relation) - return format_relation_name(relation_model.__name__) + return get_resource_type_from_model(relation_model) def get_instance_or_manager_resource_type(resource_instance_or_manager): @@ -193,25 +193,31 @@ def get_instance_or_manager_resource_type(resource_instance_or_manager): pass +def get_resource_type_from_model(model): + json_api_meta = getattr(model, 'JSONAPIMeta', None) + return getattr( + json_api_meta, + 'resource_name', + format_relation_name(model.__name__)) + + def get_resource_type_from_queryset(qs): - return format_relation_name(qs.model._meta.model.__name__) + return get_resource_type_from_model(qs.model) def get_resource_type_from_instance(instance): - return format_relation_name(instance._meta.model.__name__) + return get_resource_type_from_model(instance._meta.model) def get_resource_type_from_manager(manager): - return format_relation_name(manager.model.__name__) + return get_resource_type_from_model(manager.model) def get_resource_type_from_serializer(serializer): - try: - # Check the meta class for resource_name - return serializer.Meta.resource_name - except AttributeError: - # Use the serializer model then pluralize and format - return format_relation_name(serializer.Meta.model.__name__) + return getattr( + serializer.Meta, + 'resource_name', + get_resource_type_from_model(serializer.Meta.model)) def get_included_serializers(serializer): From 0d78f7ffaebae2c7564dc0ce98e5b82f1df05d72 Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Thu, 5 Nov 2015 10:28:27 -0500 Subject: [PATCH 2/8] dropped format_relation_name from wrapping get_resource_type* This isnt required anymore as the get_resource_type calls handle this --- rest_framework_json_api/relations.py | 4 ++-- rest_framework_json_api/serializers.py | 7 ++++--- rest_framework_json_api/views.py | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/rest_framework_json_api/relations.py b/rest_framework_json_api/relations.py index bd53b205..95cf3972 100644 --- a/rest_framework_json_api/relations.py +++ b/rest_framework_json_api/relations.py @@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework_json_api.exceptions import Conflict -from rest_framework_json_api.utils import format_relation_name, Hyperlink, \ +from rest_framework_json_api.utils import Hyperlink, \ get_resource_type_from_queryset, get_resource_type_from_instance @@ -137,7 +137,7 @@ def to_representation(self, value): else: pk = value.pk - return OrderedDict([('type', format_relation_name(get_resource_type_from_instance(value))), ('id', str(pk))]) + return OrderedDict([('type', get_resource_type_from_instance(value)), ('id', str(pk))]) @property def choices(self): diff --git a/rest_framework_json_api/serializers.py b/rest_framework_json_api/serializers.py index 61943b80..f68d984e 100644 --- a/rest_framework_json_api/serializers.py +++ b/rest_framework_json_api/serializers.py @@ -3,8 +3,9 @@ from rest_framework.serializers import * from rest_framework_json_api.relations import ResourceRelatedField -from rest_framework_json_api.utils import format_relation_name, get_resource_type_from_instance, \ - get_resource_type_from_serializer, get_included_serializers +from rest_framework_json_api.utils import ( + get_resource_type_from_model, get_resource_type_from_instance, + get_resource_type_from_serializer, get_included_serializers) class ResourceIdentifierObjectSerializer(BaseSerializer): @@ -24,7 +25,7 @@ def __init__(self, *args, **kwargs): def to_representation(self, instance): return { - 'type': format_relation_name(get_resource_type_from_instance(instance)), + 'type': get_resource_type_from_instance(instance), 'id': str(instance.pk) } diff --git a/rest_framework_json_api/views.py b/rest_framework_json_api/views.py index 36c89687..a43fad89 100644 --- a/rest_framework_json_api/views.py +++ b/rest_framework_json_api/views.py @@ -12,7 +12,7 @@ from rest_framework_json_api.exceptions import Conflict from rest_framework_json_api.serializers import ResourceIdentifierObjectSerializer -from rest_framework_json_api.utils import format_relation_name, get_resource_type_from_instance, OrderedDict, Hyperlink +from rest_framework_json_api.utils import get_resource_type_from_instance, OrderedDict, Hyperlink class RelationshipView(generics.GenericAPIView): @@ -154,7 +154,7 @@ def _instantiate_serializer(self, instance): def get_resource_name(self): if not hasattr(self, '_resource_name'): instance = getattr(self.get_object(), self.kwargs['related_field']) - self._resource_name = format_relation_name(get_resource_type_from_instance(instance)) + self._resource_name = get_resource_type_from_instance(instance) return self._resource_name def set_resource_name(self, value): From 10c44518f36b1e3390feaa45a31ca63ba4790285 Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Tue, 1 Dec 2015 12:15:31 -0500 Subject: [PATCH 3/8] Added basic test for model resource_name property --- .../tests/integration/test_model_resource_name.py | 13 +++++++++++++ example/views.py | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 example/tests/integration/test_model_resource_name.py diff --git a/example/tests/integration/test_model_resource_name.py b/example/tests/integration/test_model_resource_name.py new file mode 100644 index 00000000..289c8f1e --- /dev/null +++ b/example/tests/integration/test_model_resource_name.py @@ -0,0 +1,13 @@ +import pytest +from django.core.urlresolvers import reverse + +from example.tests.utils import load_json + +pytestmark = pytest.mark.django_db + + +def test_model_resource_name_on_list(single_entry, client): + response = client.get(reverse("renamed-authors-list")) + data = load_json(response.content)['data'] + # name should be super-author instead of model name RenamedAuthor + assert [x.get('type') for x in data] == ['super-author'], 'List included types are incorrect' diff --git a/example/views.py b/example/views.py index 59ca1a05..5982e09e 100644 --- a/example/views.py +++ b/example/views.py @@ -2,7 +2,7 @@ from rest_framework_json_api.views import RelationshipView from example.models import Blog, Entry, Author, Comment from example.serializers import ( - BlogSerializer, EntrySerializer, AuthorSerializer, CommentSerializer) + BlogSerializer, EntrySerializer, AuthorSerializer, CommentSerializer) class BlogViewSet(viewsets.ModelViewSet): @@ -41,4 +41,3 @@ class CommentRelationshipView(RelationshipView): class AuthorRelationshipView(RelationshipView): queryset = Author.objects.all() self_link_view_name = 'author-relationships' - From 0a4db2f832e4967554b2a9a82b8fa44c90efedf6 Mon Sep 17 00:00:00 2001 From: Mojtaba Kohram Date: Fri, 11 Dec 2015 18:02:56 -0500 Subject: [PATCH 4/8] started testing all combinations of resource_name on model, serializer and view remove proxy=True on model --- .../integration/test_model_resource_name.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/example/tests/integration/test_model_resource_name.py b/example/tests/integration/test_model_resource_name.py index 289c8f1e..733f0c83 100644 --- a/example/tests/integration/test_model_resource_name.py +++ b/example/tests/integration/test_model_resource_name.py @@ -3,6 +3,8 @@ from example.tests.utils import load_json +from rest_framework.test import APITestCase +from example import models, serializers pytestmark = pytest.mark.django_db @@ -11,3 +13,77 @@ def test_model_resource_name_on_list(single_entry, client): data = load_json(response.content)['data'] # name should be super-author instead of model name RenamedAuthor assert [x.get('type') for x in data] == ['super-author'], 'List included types are incorrect' + +@pytest.mark.usefixtures("single_entry") +class ResourceNameConsistencyTest(APITestCase): + + def test_type_match_on_included_and_inline_base(self): + self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + + def test_type_match_on_included_and_inline_with_JSONAPIMeta(self): + models.Comment.__bases__ += (self._PatchedModel,) + + self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + + def test_type_match_on_included_and_inline_with_serializer_resource_name(self): + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + + self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + + def test_type_match_on_included_and_inline_with_serializer_resource_name_and_JSONAPIMeta(self): + models.Comment.__bases__ += (self._PatchedModel,) + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + + self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + + def test_resource_and_relationship_type_match(self): + self._check_resource_and_relationship_comment_type_match() + + def test_resource_and_relationship_type_match_with_serializer_resource_name(self): + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + + self._check_resource_and_relationship_comment_type_match() + + def test_resource_and_relationship_type_match_with_JSONAPIMeta(self): + models.Comment.__bases__ += (self._PatchedModel,) + + self._check_resource_and_relationship_comment_type_match() + + def test_resource_and_relationship_type_match_with_serializer_resource_name_and_JSONAPIMeta(self): + models.Comment.__bases__ += (self._PatchedModel,) + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + + self._check_resource_and_relationship_comment_type_match() + + def _check_resource_and_relationship_comment_type_match(self): + entry_response = self.client.get(reverse("entry-list")) + comment_response = self.client.get(reverse("comment-list")) + + comment_resource_type = load_json(comment_response.content).get('data')[0].get('type') + comment_relationship_type = load_json(entry_response.content).get( + 'data')[0].get('relationships').get('comments').get('data')[0].get('type') + + assert comment_resource_type == comment_relationship_type, "The resource type seen in the relationships and head resource do not match" + + def _check_relationship_and_included_comment_type_are_the_same(self, url): + response = self.client.get(url + "?include=comments") + data = load_json(response.content).get('data')[0] + comment = load_json(response.content).get('included')[0] + + comment_relationship_type = data.get('relationships').get('comments').get('data')[0].get('type') + comment_included_type = comment.get('type') + + assert comment_relationship_type == comment_included_type, "The resource type seen in the relationships and included do not match" + + def tearDown(self): + models.Comment.__bases__ = (models.Comment.__bases__[0],) + try: + delattr(serializers.CommentSerializer.Meta, "resource_name") + except AttributeError: + pass + + class _PatchedModel: + + class JSONAPIMeta: + resource_name = "resource_name_from_JSONAPIMeta" + \ No newline at end of file From eace45cc2d0729b2f588799f4dd5963ac4801959 Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Wed, 16 Dec 2015 11:11:39 -0500 Subject: [PATCH 5/8] leftover uses of model.__name__ --- rest_framework_json_api/renderers.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index 61ff20b8..a8e852cf 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -281,8 +281,7 @@ def extract_included(fields, resource, resource_instance, included_resources): if isinstance(field, ListSerializer): serializer = field.child - model = serializer.Meta.model - relation_type = utils.format_relation_name(model.__name__) + relation_type = utils.get_resource_type_from_serializer(serializer) relation_queryset = list(relation_instance_or_manager.all()) # Get the serializer fields @@ -303,15 +302,16 @@ def extract_included(fields, resource, resource_instance, included_resources): ) if isinstance(field, ModelSerializer): - model = field.Meta.model - relation_type = utils.format_relation_name(model.__name__) + + relation_type = utils.get_resource_type_from_serializer(field) # Get the serializer fields serializer_fields = utils.get_serializer_fields(field) if serializer_data: included_data.append( - JSONRenderer.build_json_resource_obj(serializer_fields, serializer_data, relation_instance_or_manager, - relation_type) + JSONRenderer.build_json_resource_obj( + serializer_fields, serializer_data, + relation_instance_or_manager, relation_type) ) included_data.extend( JSONRenderer.extract_included( From 3aff5d2ae5ca77a04d3002bbd0e761364e6fedfa Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Wed, 16 Dec 2015 12:53:29 -0500 Subject: [PATCH 6/8] use an included serializer's resource_name even when not included --- rest_framework_json_api/relations.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/rest_framework_json_api/relations.py b/rest_framework_json_api/relations.py index 95cf3972..b7ccce36 100644 --- a/rest_framework_json_api/relations.py +++ b/rest_framework_json_api/relations.py @@ -6,7 +6,8 @@ from rest_framework_json_api.exceptions import Conflict from rest_framework_json_api.utils import Hyperlink, \ - get_resource_type_from_queryset, get_resource_type_from_instance + get_resource_type_from_queryset, get_resource_type_from_instance, \ + get_included_serializers, get_resource_type_from_serializer class ResourceRelatedField(PrimaryKeyRelatedField): @@ -137,7 +138,18 @@ def to_representation(self, value): else: pk = value.pk - return OrderedDict([('type', get_resource_type_from_instance(value)), ('id', str(pk))]) + # check to see if this resource has a different resource_name when + # included and use that name + resource_type = None + root = getattr(self.parent, 'parent', self.parent) + field_name = self.field_name if self.field_name else self.parent.field_name + if getattr(root, 'included_serializers', None) is not None: + includes = get_included_serializers(root) + if field_name in includes.keys(): + resource_type = get_resource_type_from_serializer(includes[field_name]) + + resource_type = resource_type if resource_type else get_resource_type_from_instance(value) + return OrderedDict([('type', resource_type), ('id', str(pk))]) @property def choices(self): From 008f4df81cc251ce4d02e7652d7beb5269c5d98f Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Wed, 16 Dec 2015 13:17:32 -0500 Subject: [PATCH 7/8] cleaned up tests added view precedence test Use py.test client over drf client to fix Django 1.7 tests --- example/serializers.py | 2 +- .../integration/test_model_resource_name.py | 154 ++++++++++++------ 2 files changed, 102 insertions(+), 54 deletions(-) diff --git a/example/serializers.py b/example/serializers.py index 5ea1b4fe..c16b7cdf 100644 --- a/example/serializers.py +++ b/example/serializers.py @@ -51,7 +51,7 @@ def get_body_format(self, obj): class Meta: model = Entry fields = ('blog', 'headline', 'body_text', 'pub_date', 'mod_date', - 'authors', 'comments', 'suggested',) + 'authors', 'comments', 'suggested',) meta_fields = ('body_format',) diff --git a/example/tests/integration/test_model_resource_name.py b/example/tests/integration/test_model_resource_name.py index 733f0c83..979b55b5 100644 --- a/example/tests/integration/test_model_resource_name.py +++ b/example/tests/integration/test_model_resource_name.py @@ -3,87 +3,135 @@ from example.tests.utils import load_json -from rest_framework.test import APITestCase -from example import models, serializers +from example import models, serializers, views pytestmark = pytest.mark.django_db -def test_model_resource_name_on_list(single_entry, client): - response = client.get(reverse("renamed-authors-list")) - data = load_json(response.content)['data'] - # name should be super-author instead of model name RenamedAuthor - assert [x.get('type') for x in data] == ['super-author'], 'List included types are incorrect' +class _PatchedModel: + class JSONAPIMeta: + resource_name = "resource_name_from_JSONAPIMeta" -@pytest.mark.usefixtures("single_entry") -class ResourceNameConsistencyTest(APITestCase): - - def test_type_match_on_included_and_inline_base(self): - self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) - def test_type_match_on_included_and_inline_with_JSONAPIMeta(self): - models.Comment.__bases__ += (self._PatchedModel,) +def _check_resource_and_relationship_comment_type_match(django_client): + entry_response = django_client.get(reverse("entry-list")) + comment_response = django_client.get(reverse("comment-list")) - self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + comment_resource_type = load_json(comment_response.content).get('data')[0].get('type') + comment_relationship_type = load_json(entry_response.content).get( + 'data')[0].get('relationships').get('comments').get('data')[0].get('type') - def test_type_match_on_included_and_inline_with_serializer_resource_name(self): - serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + assert comment_resource_type == comment_relationship_type, "The resource type seen in the relationships and head resource do not match" - self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) - def test_type_match_on_included_and_inline_with_serializer_resource_name_and_JSONAPIMeta(self): - models.Comment.__bases__ += (self._PatchedModel,) - serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" +def _check_relationship_and_included_comment_type_are_the_same(django_client, url): + response = django_client.get(url + "?include=comments") + data = load_json(response.content).get('data')[0] + comment = load_json(response.content).get('included')[0] - self._check_relationship_and_included_comment_type_are_the_same(reverse("entry-list")) + comment_relationship_type = data.get('relationships').get('comments').get('data')[0].get('type') + comment_included_type = comment.get('type') - def test_resource_and_relationship_type_match(self): - self._check_resource_and_relationship_comment_type_match() + assert comment_relationship_type == comment_included_type, "The resource type seen in the relationships and included do not match" - def test_resource_and_relationship_type_match_with_serializer_resource_name(self): + +@pytest.mark.usefixtures("single_entry") +class TestModelResourceName: + + def test_model_resource_name_on_list(self, client): + models.Comment.__bases__ += (_PatchedModel,) + response = client.get(reverse("comment-list")) + data = load_json(response.content)['data'][0] + # name should be super-author instead of model name RenamedAuthor + assert (data.get('type') == 'resource_name_from_JSONAPIMeta'), ( + 'resource_name from model incorrect on list') + + # Precedence tests + def test_resource_name_precendence(self, client): + # default + response = client.get(reverse("comment-list")) + data = load_json(response.content)['data'][0] + assert (data.get('type') == 'comments'), ( + 'resource_name from model incorrect on list') + + # model > default + models.Comment.__bases__ += (_PatchedModel,) + response = client.get(reverse("comment-list")) + data = load_json(response.content)['data'][0] + assert (data.get('type') == 'resource_name_from_JSONAPIMeta'), ( + 'resource_name from model incorrect on list') + + # serializer > model serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" + response = client.get(reverse("comment-list")) + data = load_json(response.content)['data'][0] + assert (data.get('type') == 'resource_name_from_serializer'), ( + 'resource_name from serializer incorrect on list') + + # view > serializer > model + views.CommentViewSet.resource_name = 'resource_name_from_view' + response = client.get(reverse("comment-list")) + data = load_json(response.content)['data'][0] + assert (data.get('type') == 'resource_name_from_view'), ( + 'resource_name from view incorrect on list') + + def teardown_method(self, method): + models.Comment.__bases__ = (models.Comment.__bases__[0],) + try: + delattr(serializers.CommentSerializer.Meta, "resource_name") + except AttributeError: + pass + try: + delattr(views.CommentViewSet, "resource_name") + except AttributeError: + pass + + +@pytest.mark.usefixtures("single_entry") +class TestResourceNameConsistency: + + # Included rename tests + def test_type_match_on_included_and_inline_base(self, client): + _check_relationship_and_included_comment_type_are_the_same(client, reverse("entry-list")) + + def test_type_match_on_included_and_inline_with_JSONAPIMeta(self, client): + models.Comment.__bases__ += (_PatchedModel,) - self._check_resource_and_relationship_comment_type_match() + _check_relationship_and_included_comment_type_are_the_same(client, reverse("entry-list")) - def test_resource_and_relationship_type_match_with_JSONAPIMeta(self): - models.Comment.__bases__ += (self._PatchedModel,) + def test_type_match_on_included_and_inline_with_serializer_resource_name(self, client): + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" - self._check_resource_and_relationship_comment_type_match() + _check_relationship_and_included_comment_type_are_the_same(client, reverse("entry-list")) - def test_resource_and_relationship_type_match_with_serializer_resource_name_and_JSONAPIMeta(self): - models.Comment.__bases__ += (self._PatchedModel,) + def test_type_match_on_included_and_inline_with_serializer_resource_name_and_JSONAPIMeta(self, client): + models.Comment.__bases__ += (_PatchedModel,) serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" - self._check_resource_and_relationship_comment_type_match() + _check_relationship_and_included_comment_type_are_the_same(client, reverse("entry-list")) + + # Relation rename tests + def test_resource_and_relationship_type_match(self, client): + _check_resource_and_relationship_comment_type_match(client) - def _check_resource_and_relationship_comment_type_match(self): - entry_response = self.client.get(reverse("entry-list")) - comment_response = self.client.get(reverse("comment-list")) + def test_resource_and_relationship_type_match_with_serializer_resource_name(self, client): + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" - comment_resource_type = load_json(comment_response.content).get('data')[0].get('type') - comment_relationship_type = load_json(entry_response.content).get( - 'data')[0].get('relationships').get('comments').get('data')[0].get('type') + _check_resource_and_relationship_comment_type_match(client) - assert comment_resource_type == comment_relationship_type, "The resource type seen in the relationships and head resource do not match" + def test_resource_and_relationship_type_match_with_JSONAPIMeta(self, client): + models.Comment.__bases__ += (_PatchedModel,) - def _check_relationship_and_included_comment_type_are_the_same(self, url): - response = self.client.get(url + "?include=comments") - data = load_json(response.content).get('data')[0] - comment = load_json(response.content).get('included')[0] + _check_resource_and_relationship_comment_type_match(client) - comment_relationship_type = data.get('relationships').get('comments').get('data')[0].get('type') - comment_included_type = comment.get('type') + def test_resource_and_relationship_type_match_with_serializer_resource_name_and_JSONAPIMeta(self, client): + models.Comment.__bases__ += (_PatchedModel,) + serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer" - assert comment_relationship_type == comment_included_type, "The resource type seen in the relationships and included do not match" + _check_resource_and_relationship_comment_type_match(client) - def tearDown(self): + def teardown_method(self, method): models.Comment.__bases__ = (models.Comment.__bases__[0],) try: delattr(serializers.CommentSerializer.Meta, "resource_name") except AttributeError: pass - - class _PatchedModel: - - class JSONAPIMeta: - resource_name = "resource_name_from_JSONAPIMeta" - \ No newline at end of file From fed0bf6c91b9728c46073592466ca8606bcc5bc1 Mon Sep 17 00:00:00 2001 From: Scott Fisk Date: Tue, 26 Jan 2016 11:21:12 -0500 Subject: [PATCH 8/8] Updated docs to include model resource_name --- docs/usage.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 6809a0da..7f951e1c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -36,10 +36,15 @@ per request via the `PAGINATE_BY_PARAM` query parameter (`page_size` by default) ### Setting the resource_name -You may manually set the `resource_name` property on views or serializers to -specify the `type` key in the json output. It is automatically set for you as the -plural of the view or model name except on resources that do not subclass +You may manually set the `resource_name` property on views, serializers, or +models to specify the `type` key in the json output. In the case of setting the +`resource_name` property for models you must include the property inside a +`JSONAPIMeta` class on the model. It is automatically set for you as the plural +of the view or model name except on resources that do not subclass `rest_framework.viewsets.ModelViewSet`: + + +Example - `resource_name` on View: ``` python class Me(generics.GenericAPIView): """ @@ -56,6 +61,23 @@ If you set the `resource_name` property on the object to `False` the data will be returned without modification. +Example - `resource_name` on Model: +``` python +class Me(models.Model): + """ + A simple model + """ + name = models.CharField(max_length=100) + + class JSONAPIMeta: + resource_name = "users" +``` +If you set the `resource_name` on a combination of model, serializer, or view +in the same hierarchy, the name will be resolved as following: view > +serializer > model. (Ex: A view `resource_name` will always override a +`resource_name` specified on a serializer or model) + + ### Inflecting object and relation keys This package includes the ability (off by default) to automatically convert json