6

I'm using Django Rest Framework and want to create a custom Field to use in my serializers.

class PivotField(serializers.Field):
    def __init__(self, *args, **kwargs):
        self.key_attr   = kwargs.get('key_attr')
        self.value_attr = kwargs.get('value_attr')
        super(PivotField, self).__init__(*args, **kwargs)

    def to_representation(self, value):
        data = {}
        for model in value.all():
            # this is where I'd use the key_attr and value_attr
            data[model.type.name] = model.uri
        return data

I'd like to be able to pass additional arguments to the field like this.

resources = PivotField(key_attr='type.name', value_attr='uri')

However, I keep getting the following error.

TypeError: init() got an unexpected keyword argument 'key_attr'

Is there some way to register these as valid kwargs within the field?

Soviut
  • 88,194
  • 49
  • 192
  • 260
  • Is `PivotField` your child class? Why don't overwrite the `_init_` method on it? – trinchet May 19 '16 at 14:30
  • Please add code for `PivotField`. – Rahul Gupta May 19 '16 at 17:13
  • @RahulGupta I've added it but I don't see how it'll help since the error is happening long before it gets to its representation. The only solution I can think of is to actually extract the values from the kwargs before passing it to `super`. – Soviut May 19 '16 at 17:32
  • I think you should use `kwargs.pop()` here instead of `kwargs.get()`. – Rahul Gupta May 19 '16 at 17:34

1 Answers1

5

A custom field created by subclassing Field class does not accept extra arguments using **kwargs option in __init__() method. You should override the __init__() method in PivotField and pop those extra arguments after setting them on the instance.

DRF source code for __init__() method in Field class:

class Field(object):

    def __init__(self, read_only=False, write_only=False,
                 required=None, default=empty, initial=empty, source=None,
                 label=None, help_text=None, style=None,
                 error_messages=None, validators=None, allow_null=False):
       ...

We can see from above that there is no option for sending extra arguments other than the defined keyword arguments.

So, you should pop those extra arguments from kwargs while setting them on instance.

class PivotField(serializers.Field):
    def __init__(self, *args, **kwargs):
        self.key_attr = kwargs.pop('key_attr', None) # pop the custom kwarg
        self.value_attr = kwargs.pop('value_attr', None) # pop the custom kwarg
        super(PivotField, self).__init__(*args, **kwargs)
Rahul Gupta
  • 46,769
  • 10
  • 112
  • 126