Django-rest-framework: Allow specifying fields to be serialized when instantiating Serializer

Created on 28 Jun 2013  路  7Comments  路  Source: encode/django-rest-framework

It would be very useful to be able to specify fields or exclude at the point of instantiating a Serializer, and have that override Meta. Am I right in thinking there's no way of doing this at the moment?

Most helpful comment

In case someone is looking for it, the docs url changed to:

http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields

All 7 comments

Could you list some examples of when this would be useful?

I can't visualize it, I know that for our project at work we just sub-classed and overrided the Meta (and sub-classed that when necessary) and that was good enough for all our use cases.

Right, subclassing does do the job, but it means that you have to create a subclass for every combination of fields that you want to serialise, and you have to repeat all the fields in each subclass.

One use case is when you're sending differential updates to a client, and you know that only some of the fields could have changed. In that case you want to do something like Serializer(data, fields=('id', 'this_may_have_changed')).

Another is when you have a serializer defined containing nested serializers. When serialising for the purposes of bootstrapping a client, or doing a full refresh/update, you want to do a full (deep) serialisation, but at other times you only want to serialise the model's core data, and not its related data.

I did a bit of messing around and came up with this:

class ExtraFieldsMixin(object):
    def __init__(self, *args, **kwargs):
        self.extra = kwargs.pop('extra', True)
        super(ExtraFieldsMixin, self).__init__(*args, **kwargs)

    def get_fields(self):
        if self.extra:
            self.opts.fields += self.opts.extra
        return super(ExtraFieldsMixin, self).get_fields()


class SerializerOptions(serializers.ModelSerializerOptions):
    """
    Meta class options for Serializer
    """
    def __init__(self, meta):
        super(SerializerOptions, self).__init__(meta)
        self.extra = getattr(meta, 'extra', ())


class ModelSerializer(ExtraFieldsMixin,
                      serializers.ModelSerializer):
    _options_class = SerializerOptions

This then just allows you to define some fields as being "extra" (not a great name) and pass a boolean option to the serializer. A simple solution to the deep/shallow serialization problem.

It does seem to me that it would make sense to at least allow setting of fields when instatiating.

Ah okay that use case does make sense.

The solution looks good too.

An alternative to passing in the fields as a keyword argument is setting it
after the fact, I'm not looking at the code right now but I thought that
there was a get_serializer method available? Is that a good or merely
passable alternative to your idea?

I've created some extra documentation addressing how serializer fields can be modified dynamically.

I think this ticket is a pretty reasonable request, but I'd prefer to leave out the extra API that it'd create, given that there is already a route to doing what you need. This is also more in line which Django's forms API, also see Jacob's related blog post on dynamic forms... http://jacobian.org/writing/dynamic-form-generation/

If you think the additional documentation doesn't adequately address the issue feel free to reopen the ticket for further discussion.

@tomchristie good job with the documentation! :+1:

In case someone is looking for it, the docs url changed to:

http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields

Was this page helpful?
0 / 5 - 0 ratings