Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1e2594f

Browse files
uliSchustersliverc
andauthored
Allow users to overwrite get_serializer_class while using related urls (#860)
* This attempt to fix the issues breaks tests An attempt to fix #859, which unfortunately breaks two tests in test_views. * Removed misleading comment Tha basic method was copied over from the GenericAPIView. The comment here does not fit, though. * bein more explicit about the changes * Use correct serializer for rendering Ensure that the correct resource is returned during rendering, which in turn requires to use the correct serializer, depending on if it is a related resource or the parent resource. sliverc pointed out the issue here. * Add provision for tests * Describe the fix. * Fixed failing tests As pointed out by n2ygk, the schema names here must reflect the Serializer class names, which I changed in the two affected test cases. * Update CHANGELOG.md Clarified changelog entry * Fixed linting issues Co-authored-by: Ulrich Schuster <ulrich.schuster@koing.de> Co-authored-by: Oliver Sauder <sliverc@users.noreply.github.com>
1 parent c392a43 commit 1e2594f

File tree

8 files changed

+47
-14
lines changed

8 files changed

+47
-14
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ Sergey Kolomenkin <https://kolomenkin.com>
3333
Stas S. <stas@nerd.ro>
3434
Tim Selman <timcbaoth@gmail.com>
3535
Tom Glowka <glowka.tom@gmail.com>
36+
Ulrich Schuster <ulrich.schuster@mailworks.org>
3637
Yaniv Peer <yanivpeer@gmail.com>

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ any parts of the framework not mentioned in the documentation should generally b
1414

1515
* Ability for the user to select `included_serializers` to apply when using `BrowsableAPI`, based on available `included_serializers` defined for the current endpoint.
1616

17+
### Fixed
18+
19+
* Allow users to overwrite a view's `get_serializer_class()` method when using [related urls](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#related-urls)
20+
1721

1822
## [4.0.0] - 2020年10月31日
1923

‎example/serializers.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,14 @@ def get_first_entry(self, obj):
261261
return obj.entries.first()
262262

263263

264+
class AuthorListSerializer(AuthorSerializer):
265+
pass
266+
267+
268+
class AuthorDetailSerializer(AuthorSerializer):
269+
pass
270+
271+
264272
class WriterSerializer(serializers.ModelSerializer):
265273
included_serializers = {
266274
'bio': AuthorBioSerializer

‎example/tests/snapshots/snap_test_openapi.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
"properties": {
6666
"data": {
6767
"items": {
68-
"$ref": "#/components/schemas/Author"
68+
"$ref": "#/components/schemas/AuthorList"
6969
},
7070
"type": "array"
7171
},
@@ -171,7 +171,7 @@
171171
"schema": {
172172
"properties": {
173173
"data": {
174-
"$ref": "#/components/schemas/Author"
174+
"$ref": "#/components/schemas/AuthorDetail"
175175
},
176176
"included": {
177177
"items": {

‎example/tests/test_views.py‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -367,32 +367,32 @@ def test_get_related_instance_model_field(self):
367367
got = view.get_related_instance()
368368
self.assertEqual(got, self.author.id)
369369

370-
def test_get_serializer_class(self):
370+
def test_get_related_serializer_class(self):
371371
kwargs = {'pk': self.author.id, 'related_field': 'bio'}
372372
view = self._get_view(kwargs)
373-
got = view.get_serializer_class()
373+
got = view.get_related_serializer_class()
374374
self.assertEqual(got, AuthorBioSerializer)
375375

376-
def test_get_serializer_class_many(self):
376+
def test_get_related_serializer_class_many(self):
377377
kwargs = {'pk': self.author.id, 'related_field': 'entries'}
378378
view = self._get_view(kwargs)
379-
got = view.get_serializer_class()
379+
got = view.get_related_serializer_class()
380380
self.assertEqual(got, EntrySerializer)
381381

382382
def test_get_serializer_comes_from_included_serializers(self):
383383
kwargs = {'pk': self.author.id, 'related_field': 'type'}
384384
view = self._get_view(kwargs)
385385
related_serializers = view.serializer_class.related_serializers
386386
delattr(view.serializer_class, 'related_serializers')
387-
got = view.get_serializer_class()
387+
got = view.get_related_serializer_class()
388388
self.assertEqual(got, AuthorTypeSerializer)
389389

390390
view.serializer_class.related_serializers = related_serializers
391391

392-
def test_get_serializer_class_raises_error(self):
392+
def test_get_related_serializer_class_raises_error(self):
393393
kwargs = {'pk': self.author.id, 'related_field': 'unknown'}
394394
view = self._get_view(kwargs)
395-
self.assertRaises(NotFound, view.get_serializer_class)
395+
self.assertRaises(NotFound, view.get_related_serializer_class)
396396

397397
def test_retrieve_related_single_reverse_lookup(self):
398398
url = reverse('author-related', kwargs={'pk': self.author.pk, 'related_field': 'bio'})

‎example/views.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
from example.models import Author, Blog, Comment, Company, Entry, Project, ProjectType
1717
from example.serializers import (
18+
AuthorDetailSerializer,
19+
AuthorListSerializer,
1820
AuthorSerializer,
1921
BlogDRFSerializer,
2022
BlogSerializer,
@@ -185,7 +187,16 @@ class NoFiltersetEntryViewSet(EntryViewSet):
185187

186188
class AuthorViewSet(ModelViewSet):
187189
queryset = Author.objects.all()
188-
serializer_class = AuthorSerializer
190+
serializer_classes = {
191+
"list": AuthorListSerializer,
192+
"retrieve": AuthorDetailSerializer}
193+
serializer_class = AuthorSerializer # fallback
194+
195+
def get_serializer_class(self):
196+
try:
197+
return self.serializer_classes.get(self.action, self.serializer_class)
198+
except AttributeError:
199+
return self.serializer_class
189200

190201

191202
class CommentViewSet(ModelViewSet):

‎rest_framework_json_api/utils.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ def get_resource_name(context, expand_polymorphic_types=False):
5252
resource_name = getattr(view, 'resource_name')
5353
except AttributeError:
5454
try:
55-
serializer = view.get_serializer_class()
55+
if 'kwargs' in context and 'related_field' in context['kwargs']:
56+
serializer = view.get_related_serializer_class()
57+
else:
58+
serializer = view.get_serializer_class()
5659
if expand_polymorphic_types and issubclass(serializer, PolymorphicModelSerializer):
5760
return serializer.get_polymorphic_types()
5861
else:

‎rest_framework_json_api/views.py‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,15 @@ def retrieve_related(self, request, *args, **kwargs):
144144
if isinstance(instance, Iterable):
145145
serializer_kwargs['many'] = True
146146

147-
serializer = self.get_serializer(instance, **serializer_kwargs)
147+
serializer = self.get_related_serializer(instance, **serializer_kwargs)
148148
return Response(serializer.data)
149149

150-
def get_serializer_class(self):
150+
def get_related_serializer(self, instance, **kwargs):
151+
serializer_class = self.get_related_serializer_class()
152+
kwargs.setdefault('context', self.get_serializer_context())
153+
return serializer_class(instance, **kwargs)
154+
155+
def get_related_serializer_class(self):
151156
parent_serializer_class = super(RelatedMixin, self).get_serializer_class()
152157

153158
if 'related_field' in self.kwargs:
@@ -179,7 +184,8 @@ def get_related_field_name(self):
179184

180185
def get_related_instance(self):
181186
parent_obj = self.get_object()
182-
parent_serializer = self.serializer_class(parent_obj)
187+
parent_serializer_class = self.get_serializer_class()
188+
parent_serializer = parent_serializer_class(parent_obj)
183189
field_name = self.get_related_field_name()
184190
field = parent_serializer.fields.get(field_name, None)
185191

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /