Django REST Framework show multiple forms on HTML

2019-08-12 04:49发布

问题:

I have a ViewSet using Django REST Framework that has both standard and custom routes. The serializer for each route is different.

Example:

class UserViewSet(ViewSet):

    model = User
    serializer_class = UserSerializer

    @decorators.detail_route(methods=['put'])
    def change_password(self, request, pk, *args, **kwargs):
        serializer = UserChangePasswordSerializer(data=request.data)
        ...

    @decorators.detail_route(methods=['put'])
    def update_prefs(self, request, *args, **kwargs):
        serializer = UserPreferencesSerializer(data=request.data)
        ...

I have everything working such that I can perform standard get, post, put, delete actions on the User object and the two extra routes work. However, I can't figure out how to make the HTML forms for the custom routes display when using the BrowsableAPIRenderer. It would be very handy for developers to be able to see forms demonstrating the fields that are expected on the above put methods, for example.

I tried adding get methods for the two routes, but this is non-sensical for the first one. Regardless, I don't see the right serializer displayed when I go to the URL for the route, I see the serializer specified in serializer_class.

About the only thing I haven't tried is overriding get_serializer_class() because this involves putting knowledge of every serializer for every route in a single place rather than being able to specify the serializer within the route method itself... is this the way I should be trying to get the desired effect?

回答1:

It turns out I need to not use serializer_class and instead override get_serializer_class. Since this takes an action, I can if..elif..else on that to return the right serializer. Clever use of a dictionary then makes this easy:

serializers = {
    'DEFAULT': UserSerializer,
    'password_update': PasswordUpdateSerializer,
    'register': UserRegisterSerializer,
}

def get_serializer_class(self, *args, **kwargs):
    return self.serializers.get(self.action, self.serializers['DEFAULT'])

This will return the UserSerializer for all actions unless I specify a different serializer in the serializers dictionary. Easier than I thought it would be.