Skip to content
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

Add Serializer per action to ViewSets #4632

Closed
dyve opened this issue Oct 27, 2016 · 4 comments

Comments

Projects
None yet
3 participants
@dyve
Copy link

commented Oct 27, 2016

A common use case is to list objects first, and then retrieve details.

The current implementation of ViewSet is to use one Serializer for every action (list, retrieve, etc).

This means listing and then retrieving yields no additional data.

A good solution would be to allow a default Serializer (using the serializer_class attribute of a ViewSet), and an optional dict of action to Serializer, as described in this StackOverflow answer:
http://stackoverflow.com/a/22922156/117831

class MultiSerializerViewSetMixin(object):
    def get_serializer_class(self):
        """
        Look for serializer class in self.serializer_action_classes, which
        should be a dict mapping action name (key) to serializer class (value),
        i.e.:

        class MyViewSet(MultiSerializerViewSetMixin, ViewSet):
            serializer_class = MyDefaultSerializer
            serializer_action_classes = {
               'list': MyListSerializer,
               'my_action': MyActionSerializer,
            }

            @action
            def my_action:
                ...

        If there's no entry for that action then just fallback to the regular
        get_serializer_class lookup: self.serializer_class, DefaultSerializer.

        Thanks gonz: http://stackoverflow.com/a/22922156/11440

        """
        try:
            return self.serializer_action_classes[self.action]
        except (KeyError, AttributeError):
            return super(MultiSerializerViewSetMixin, self).get_serializer_class()

Note: I am not the author of this answer and code, this is just an answer to a problem I have with DRF, and I think it's worth looking at this as an enhancement.

@dyve

This comment has been minimized.

Copy link
Author

commented Oct 27, 2016

This might relate to #2062, and even be a partial solution for that issue.

@netcitylife

This comment has been minimized.

Copy link

commented Oct 27, 2016

Yes, the problem is very actual. Currently I have to create a new serializer per any viewset action, because serializer fields most of the time differ for each method:

  1. List - a short summary of fields to display in a table, most often with nested relations
  2. Retrieve - get all model fields, most often with nested relations
  3. Create - all models fields, but without nested relations, because when we pass model data to api from a form - we most often pass relations as primary keys, retrieved from "select" elements.
  4. Update - mostly the same as create.

And then configure an appropriate serializer to be used for certain viewset actions. Suggested approach would make it easier than now, but I would advise a little bit different way:
We should try to create just one Serializer and one Viewset per Model. So Serializer should be more flexible with "fields" configuration out of the box. This can be achieved rof example this way:

Allow to configure several lists of fields in the serilizer. For example:

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        list_fields: [...],
        retrieve_fields: [...],
        create_fields: [...]
        fields: [...] # default fallback

Fields here are specified as "viewset action"_fields. So appropriate fields will be invoked for viewset actions.
Allow to configure several Serializer fields per one Model field. For example (asume that "relation" is a gjango model foreign key field):

class MyModelSerializer(serializers.ModelSerializer):
    relation_obj = RelationSerializer(model_field='relation', action='list')

    class Meta:
        list_fields: ['relation_obj', 'relation'],
        retrieve_fields: ['relation', ...],
        create_fields: ['relation', ...]
        fields: [...] # default fallback

In this example list action will return "relation" primary key and the whole "relation_obj" object, as specified in RelationSerializer "list_fields" meta property.

@dyve

This comment has been minimized.

Copy link
Author

commented Oct 28, 2016

@soulhunter1987 That solution is a bit more complex than what I'd like to see (and suggested).

@tomchristie

This comment has been minimized.

Copy link
Member

commented Oct 28, 2016

I'd like to see someone tackle this as a third party mixin class rather than bringing in anything else to core right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.