mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-27 08:29:59 +03:00
Allow custom serializer class for request and response
This commit is contained in:
parent
f378f98a40
commit
dab91c36c3
|
@ -295,6 +295,8 @@ As with `ModelViewSet`, you'll normally need to provide at least the `queryset`
|
||||||
|
|
||||||
Again, as with `ModelViewSet`, you can use any of the standard attributes and method overrides available to `GenericAPIView`.
|
Again, as with `ModelViewSet`, you can use any of the standard attributes and method overrides available to `GenericAPIView`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Custom ViewSet base classes
|
# Custom ViewSet base classes
|
||||||
|
|
||||||
You may need to provide custom `ViewSet` classes that do not have the full set of `ModelViewSet` actions, or that customize the behavior in some other way.
|
You may need to provide custom `ViewSet` classes that do not have the full set of `ModelViewSet` actions, or that customize the behavior in some other way.
|
||||||
|
@ -321,3 +323,44 @@ By creating your own base `ViewSet` classes, you can provide common behavior tha
|
||||||
|
|
||||||
[cite]: https://guides.rubyonrails.org/action_controller_overview.html
|
[cite]: https://guides.rubyonrails.org/action_controller_overview.html
|
||||||
[routers]: routers.md
|
[routers]: routers.md
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Custom serializer for request and response
|
||||||
|
|
||||||
|
It is possible to define at the view level (or for each custom method via the @action decorator) a custom serialization class for each request and response.
|
||||||
|
To do this you need to define `request_serializer_response` and `response_serializer_response` and call them via `get_request_serializer` and `get_response_serializer`.
|
||||||
|
|
||||||
|
|
||||||
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
|
"""
|
||||||
|
A viewset that provides the standard actions
|
||||||
|
"""
|
||||||
|
queryset = User.objects.all()
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
|
||||||
|
@action(
|
||||||
|
detail=True,
|
||||||
|
methods=['post'],
|
||||||
|
request_serializer_class=PasswordSerializer
|
||||||
|
)
|
||||||
|
def set_password(self, request, pk=None):
|
||||||
|
user = self.get_object()
|
||||||
|
serializer = self.get_request_serializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
user.set_password(serializer.validated_data['password'])
|
||||||
|
user.save()
|
||||||
|
return Response({'status': 'password set'})
|
||||||
|
else:
|
||||||
|
return Response(serializer.errors,
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
@action(
|
||||||
|
detail=True,
|
||||||
|
methods=['get'],
|
||||||
|
request_response_class=ExtendedUserSerializer
|
||||||
|
)
|
||||||
|
def complete_profile(self, request, pk=None):
|
||||||
|
user = self.get_object()
|
||||||
|
response_serializer = self.get_response_serializer(user)
|
||||||
|
return Response(response_serializer.data)
|
||||||
|
|
|
@ -33,6 +33,8 @@ class GenericAPIView(views.APIView):
|
||||||
# for all subsequent requests.
|
# for all subsequent requests.
|
||||||
queryset = None
|
queryset = None
|
||||||
serializer_class = None
|
serializer_class = None
|
||||||
|
request_serializer_class = None
|
||||||
|
response_serializer_class = None
|
||||||
|
|
||||||
# If you want to use object lookups other than pk, set 'lookup_field'.
|
# If you want to use object lookups other than pk, set 'lookup_field'.
|
||||||
# For more complex lookup requirements override `get_object()`.
|
# For more complex lookup requirements override `get_object()`.
|
||||||
|
@ -109,6 +111,23 @@ class GenericAPIView(views.APIView):
|
||||||
kwargs.setdefault('context', self.get_serializer_context())
|
kwargs.setdefault('context', self.get_serializer_context())
|
||||||
return serializer_class(*args, **kwargs)
|
return serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_request_serializer(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return the serializer instance that should be used for validating and
|
||||||
|
deserializing input.
|
||||||
|
"""
|
||||||
|
serializer_class = self.get_request_serializer_class()
|
||||||
|
kwargs.setdefault('context', self.get_serializer_context())
|
||||||
|
return serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_response_serializer(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return the serializer instance that should be used for serializing output.
|
||||||
|
"""
|
||||||
|
serializer_class = self.get_response_serializer_class()
|
||||||
|
kwargs.setdefault('context', self.get_serializer_context())
|
||||||
|
return serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
"""
|
"""
|
||||||
Return the class to use for the serializer.
|
Return the class to use for the serializer.
|
||||||
|
@ -127,6 +146,18 @@ class GenericAPIView(views.APIView):
|
||||||
|
|
||||||
return self.serializer_class
|
return self.serializer_class
|
||||||
|
|
||||||
|
def get_request_serializer_class(self):
|
||||||
|
"""
|
||||||
|
Return the class to use as input serializer.
|
||||||
|
"""
|
||||||
|
return self.request_serializer_class or self.get_serializer_class()
|
||||||
|
|
||||||
|
def get_response_serializer_class(self):
|
||||||
|
"""
|
||||||
|
Returns the class to use as output serializer.
|
||||||
|
"""
|
||||||
|
return self.response_serializer_class or self.get_serializer_class()
|
||||||
|
|
||||||
def get_serializer_context(self):
|
def get_serializer_context(self):
|
||||||
"""
|
"""
|
||||||
Extra context provided to the serializer class.
|
Extra context provided to the serializer class.
|
||||||
|
|
|
@ -627,15 +627,41 @@ class AutoSchema(ViewInspector):
|
||||||
Override this method if your view uses a different serializer for
|
Override this method if your view uses a different serializer for
|
||||||
handling request body.
|
handling request body.
|
||||||
"""
|
"""
|
||||||
|
view = self.view
|
||||||
|
|
||||||
|
if not hasattr(view, "get_request_serializer"):
|
||||||
return self.get_serializer(path, method)
|
return self.get_serializer(path, method)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return view.get_request_serializer()
|
||||||
|
except exceptions.APIException:
|
||||||
|
warnings.warn(
|
||||||
|
"{}.get_request_serializer() raised an exception during "
|
||||||
|
"schema generation. Serializer fields will not be "
|
||||||
|
"generated for {} {}.".format(view.__class__.__name__, method, path)
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
def get_response_serializer(self, path, method):
|
def get_response_serializer(self, path, method):
|
||||||
"""
|
"""
|
||||||
Override this method if your view uses a different serializer for
|
Override this method if your view uses a different serializer for
|
||||||
populating response data.
|
populating response data.
|
||||||
"""
|
"""
|
||||||
|
view = self.view
|
||||||
|
|
||||||
|
if not hasattr(view, "get_response_serializer"):
|
||||||
return self.get_serializer(path, method)
|
return self.get_serializer(path, method)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return view.get_response_serializer()
|
||||||
|
except exceptions.APIException:
|
||||||
|
warnings.warn(
|
||||||
|
"{}.get_response_serializer() raised an exception during "
|
||||||
|
"schema generation. Serializer fields will not be "
|
||||||
|
"generated for {} {}.".format(view.__class__.__name__, method, path)
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
def _get_reference(self, serializer):
|
def _get_reference(self, serializer):
|
||||||
return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))}
|
return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))}
|
||||||
|
|
||||||
|
|
|
@ -692,3 +692,45 @@ class TestSerializer(TestCase):
|
||||||
serializer = response.serializer
|
serializer = response.serializer
|
||||||
|
|
||||||
assert serializer.context is context
|
assert serializer.context is context
|
||||||
|
|
||||||
|
def test_get_request_serializer_class(self):
|
||||||
|
class View(generics.GenericAPIView):
|
||||||
|
request_serializer_class = BasicSerializer
|
||||||
|
|
||||||
|
view = View()
|
||||||
|
assert view.get_request_serializer_class() == BasicSerializer
|
||||||
|
|
||||||
|
def test_get_response_serializer_class(self):
|
||||||
|
class TestResponseSerializerView(generics.GenericAPIView):
|
||||||
|
response_serializer_class = BasicSerializer
|
||||||
|
|
||||||
|
view = TestResponseSerializerView()
|
||||||
|
assert view.get_response_serializer_class() == BasicSerializer
|
||||||
|
|
||||||
|
def test_get_request_serializer(self):
|
||||||
|
class View(generics.ListAPIView):
|
||||||
|
request_serializer_class = BasicSerializer
|
||||||
|
|
||||||
|
def list(self, request):
|
||||||
|
response = Response()
|
||||||
|
response.serializer = self.get_request_serializer()
|
||||||
|
return response
|
||||||
|
|
||||||
|
view = View.as_view()
|
||||||
|
request = factory.get('/')
|
||||||
|
response = view(request)
|
||||||
|
assert isinstance(response.serializer, BasicSerializer)
|
||||||
|
|
||||||
|
def test_get_response_serializer(self):
|
||||||
|
class View(generics.ListAPIView):
|
||||||
|
response_serializer_class = BasicSerializer
|
||||||
|
|
||||||
|
def list(self, request):
|
||||||
|
response = Response()
|
||||||
|
response.serializer = self.get_response_serializer()
|
||||||
|
return response
|
||||||
|
|
||||||
|
view = View.as_view()
|
||||||
|
request = factory.get('/')
|
||||||
|
response = view(request)
|
||||||
|
assert isinstance(response.serializer, BasicSerializer)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user