-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Allow custom serializer class for request and response #8347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow custom serializer class for request and response #8347
Conversation
788f74d
to
b22d728
Compare
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
b22d728
to
dab91c3
Compare
Hello, do you need anything so it pass and can be merged I'm interested in this feature. |
dab91c3
to
ff075ef
Compare
@tomchristie hi! would you mind taking a look at this? |
I don't really understand this, since it adds methods on the view sets, but doesn't actually plug the view sets behaviour into those methods. We've pushed back on differing requests/response serialisers (with the small exception of allowing a way for those to be defined by the schema) and I don't think that's going to change at this point in the project's lifespan. |
@tomchristie Thanks for answering! To be able to define serializers in the schema as proposed here (#7424), we need the methods As far as separating the request and response serializers, that would have been the ultimate goal indeed. I like the way it is handled in flask-smorest and we wouldn't be far off to do something like that in DRF. I know DRF is getting old but many of us still use it and it's far from being dead to us :) |
@tomchristie @khamaileon, Hi, thank you for your time :). For my point of view, allowing to dissociate request/response serializer is crucial, because it allows to have schema generation libraries work out of the box. My pipeline using drf-spectacular for schema generation and openapi-generators for frontend service libraries can't work without a new generic view or a lot of decorator. My main issue is that I wanted to have this behavior in ModelViewset, so I could have a view like this : class WeaponViewSet(LendModelViewSet):
queryset = Weapon.objects.all()
serializer_class = WeaponSerializer
output_serializer_class = WeaponSerializer
filterset_class = WeaponFilter
@action(detail=True, methods=['post'])
def return_weapon(self, request, pk=None):
"""Return the weapon"""
loan = Loan.objects.get(weapon_lent=pk, date_end=None)
if loan.date_end is not None:
return Response({'detail':"Cannot complete an already completed loan"}, HTTP_400_BAD_REQUEST)
with transaction.atomic():
loan.date_end = timezone.now()
loan.weapon_lent.is_available = True
loan.weapon_lent.save()
loan.save()
serializer = self.serializer_class(loan.weapon_lent)
return Response(data=serializer.data)
def get_serializer_class(self):
if self.action in ['create', 'update', 'partial_update']:
return InputWeaponSerializer
if self.action in ['return_weapon']:
return EmptySerializer
return super().get_serializer_class() This view will always use WeaponSerializer for response, but have different request serializer (Empty and InputWeapon), because some fields (like id, created_at, etc ...) must not be in the request schema. To do that, I obviously get the same behavior as a Modelviewset, but modified all mixins to incorporate input/ouput logic: class LendUpdateModelMixin:
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
output_serializer = self.get_output_serializer(serializer.instance)
return Response(output_serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs) Without modifying the generics/mixins, I can't use ModelViewset without specifying in/out request by overiding methods on each of my viewset, which is kinda counterproductive ... I guess this behavior might be outside the basic behavior of drf, so I could make an external modules to do that. |
Following this commit, this PR add the possibility to specify classes that will be used when generating the input/output specs in the OpenAPI documentation.