This commit is contained in:
Uriel Corfa 2014-05-28 02:44:38 +00:00
commit d0b3bb4d6a
3 changed files with 70 additions and 8 deletions

View File

@ -64,7 +64,8 @@ Each of the concrete generic views provided is built by combining `GenericAPIVie
The following attributes control the basic view behavior.
* `queryset` - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the `get_queryset()` method.
* `serializer_class` - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the `get_serializer_class()` method.
* `serializer_class` - The serializer class that should be used for validating and deserializing input. Typically, you must either set this attribute, or override the `get_serializer_class()` method.
* `serializer_class_for_output` - The serializer class that should be used for deserializing input, and for serializing output. You don't have to set this, if it is unset, `serializer_class` is used instead by default. You can override `get_serializer_class_for_output()` to change this behavior.
* `lookup_field` - The model field that should be used to for performing object lookup of individual model instances. Defaults to `'pk'`. Note that when using hyperlinked APIs you'll need to ensure that *both* the API views *and* the serializer classes set the lookup fields if you need to use a custom value.
* `lookup_url_kwarg` - The URL keyword argument that should be used for object lookup. The URL conf should include a keyword argument corresponding to this value. If unset this defaults to using the same value as `lookup_field`.
@ -141,7 +142,7 @@ For example:
Returns the class that should be used for the serializer. Defaults to returning the `serializer_class` attribute, or dynamically generating a serializer class if the `model` shortcut is being used.
May be override to provide dynamic behavior such as using different serializers for read and write operations, or providing different serializers to different types of users.
May be override to provide dynamic behavior such as providing different serializers to different types of users. To usie different serializers for read and write operations, see `get_serializer_class_for_output`.
For example:
@ -150,6 +151,36 @@ For example:
return FullAccountSerializer
return BasicAccountSerializer
#### `get_serializer_class_for_output(self)`
Returns the class that should be used for the serializer when deserializing objects. By default this returns the `serializer_class_for_output` attribute. If this attribute is not set, this is identical to `get_serializer_class`.
This method allows you to use a different serializer for read and write operations on objects. For example:
class Album(Model):
title = CharField(max_length=127)
class Track(Model):
title = CharField(max_length=127)
album = ForeignKey(Album, related_name='tracks')
class TrackSerializer(ModelSerializer):
class Meta:
fields = ('title', 'album')
class TrackSerializerWithDetails(ModelSerializer):
album = AlbumSerializer()
class Meta:
fields = ('title', 'album')
In this situation you may wish to display the full album information in the Track view, but you want the album field to be editable, and you don't want to supply a full Album object when updating or creating a Track. This is easily done by creating your ModelViewSet as such:
class TrackViewSet(ModelViewSet):
queryset = Track.objects.all()
serializer_class = TrackSerializer
serializer_class_for_output = TrackSerializerWithDetails
#### `get_paginate_by(self)`
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the client if the `paginate_by_param` attribute is set.

View File

@ -46,6 +46,11 @@ class GenericAPIView(views.APIView):
queryset = None
serializer_class = None
# You may set this attribute to use a different serializer for
# deserializing objects. You can override
# `get_serializer_class_for_output()` instead of setting it.
serializer_class_for_output = None
# This shortcut may be used instead of setting either or both
# of the `queryset`/`serializer_class` attributes, although using
# the explicit style is generally preferred.
@ -94,7 +99,7 @@ class GenericAPIView(views.APIView):
partial=False, allow_add_remove=False):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
deserializing input.
"""
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
@ -103,13 +108,23 @@ class GenericAPIView(views.APIView):
allow_add_remove=allow_add_remove,
context=context)
def get_serializer_for_output(self, instance=None, many=False):
"""
Return the serializer instance that should be used for
serializing output. Defaults to the serializer instance used
for deserializing input.
"""
serializer_class = self.get_serializer_class_for_output()
context = self.get_serializer_context()
return serializer_class(instance, context=context, many=many)
def get_pagination_serializer(self, page):
"""
Return a serializer instance to use with paginated data.
"""
class SerializerClass(self.pagination_serializer_class):
class Meta:
object_serializer_class = self.get_serializer_class()
object_serializer_class = self.get_serializer_class_for_output()
pagination_serializer_class = SerializerClass
context = self.get_serializer_context()
@ -252,6 +267,19 @@ class GenericAPIView(views.APIView):
model = self.model
return DefaultSerializer
def get_serializer_class_for_output(self):
"""
Return the class to use for the serializer when deserializing
objects.
Defaults to using `self.serializer_class_for_output`, if None,
defaults to `self.get_serializer()`.
"""
serializer_class = self.serializer_class_for_output
if serializer_class is None:
return self.get_serializer_class()
return serializer_class
def get_queryset(self):
"""
Get the list of items for this view.

View File

@ -53,8 +53,9 @@ class CreateModelMixin(object):
self.pre_save(serializer.object)
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
out_serializer = self.get_serializer_for_output(self.object)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
return Response(out_serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@ -93,7 +94,8 @@ class ListModelMixin(object):
if page is not None:
serializer = self.get_pagination_serializer(page)
else:
serializer = self.get_serializer(self.object_list, many=True)
serializer = self.get_serializer_for_output(
self.object_list, many=True)
return Response(serializer.data)
@ -104,7 +106,7 @@ class RetrieveModelMixin(object):
"""
def retrieve(self, request, *args, **kwargs):
self.object = self.get_object()
serializer = self.get_serializer(self.object)
serializer = self.get_serializer_for_output(self.object)
return Response(serializer.data)
@ -136,7 +138,8 @@ class UpdateModelMixin(object):
self.object = serializer.save(force_update=True)
self.post_save(self.object, created=False)
return Response(serializer.data, status=status.HTTP_200_OK)
out_serializer = self.get_serializer_for_output(self.object)
return Response(out_serializer.data, status=status.HTTP_200_OK)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True