diwakarb
diwakarb

Reputation: 561

How to use custom serializers fields in my HyeprlinkedModelSerializer

I need to store bitmap representation of an image in my code, so I did this in my model

logo = models.BinaryField(blank=True, null=True)

now Django-rest doesn't have a serializer field for BinaryField. If I create my own serializer field for this, how would I be able to use it in my code ? For example, if I create something like

class MyBinaryField(serializers.Field):
    def to_representation(self, obj):
        return base64.b64decode(obj)
    def to_internal_value(self, data):
        return base64.encodestring(data)

How can I plug this mapping of models.BinaryField and MyBinaryField in my serializer. I know there is a default serializer_field_mapping map available and I can override it, but I want to use existing serializer_field_mapping as well. How can I insert my new entry into existing serializer_field_mapping or declare new values in current map ?

Upvotes: 4

Views: 3872

Answers (3)

amoralesc
amoralesc

Reputation: 515

Taking inspiration from @prokher, another way of expanding the serializer_field_mapping attribute of the ModelSerializer would be using a mixin. This method has the added benefit of not overwriting the base serializer, and only using the mixin when you have fields that need to be mapped.

One way of defining this mixin would be overwriting the build_standard_field() method, since this is called in the ModelSerializer to build the fields that can be mapped from the serializer_field_mapping. We can simply expand the dict holding the mapping to add the custom fields that aren't currently supported, and then call the original method to actually build the field.

The mixin for a given field serializer MyCustomField that maps to a Django model field MyModelField can be defined like so:

from rest_framework import serializers

class MyCustomField(serializers.Field):
    pass

class MyCustomFieldMappingMixin:
    """A `ModelSerializer` mixin that extends
    the default serializer field mapping
    to include `MyCustomField`.
    """

    def build_standard_field(self, field_name, model_field):
        self.serializer_field_mapping[MyModelField] = MyCustomField
        return super().build_standard_field(field_name, model_field)

And then your serializer class can extend from this mixin to add support for MyModelField like so:

from rest_framework import serializers

# The mixin has to be imported before the ModelSerializer
# otherwise, MyCustomField won't be used to map your field
def MySerializer(
    MyCustomFieldMappingMixin, 
    serializers.ModelSerializer,
):
    class Meta:
        model = MyModel
        fields = ("my_model_field") # this should map to MyCustomField

Upvotes: 0

prokher
prokher

Reputation: 490

Just make a copy of serializer_field_mapping from the base class of your serializer and update it with new "model field - serializer" field pair. For example if you use ModelSerializer subclass then:

from rest_framework import serializers
class MySerializer(serializers.ModelSerializer):
    serializer_field_mapping = (
        serializers.ModelSerializer.serializer_field_mapping.copy()
    )
    serializer_field_mapping[models.BinaryField] = MyBinaryField

Upvotes: 4

Gagandeep Singh
Gagandeep Singh

Reputation: 5879

One way to do this,

class MySerializer(serializers.Serializer):
    logo = MyBinaryField()

However, I suppose you are asking about overriding model serializer field then you could use the following,

class AccountSerializer(serializers.ModelSerializer):
    logo = MyBinaryField(read_only=True)

    class Meta:
        model = Account

Reference from Docs

Upvotes: 0

Related Questions