Proto Serializers

The serializers work almost exactly the same with REST framework’s Serializer class and ModelSerializer, but use message instead of data as input and output.

Declaring serializers

Declaring a serializer looks very similar to declaring a rest framework serializer:

from rest_framework import serializers
from django_grpc_framework import proto_serializers

class PersonProtoSerializer(proto_serializers.ProtoSerializer):
    name = serializers.CharField(max_length=100)
    email = serializers.EmailField(max_length=100)

    class Meta:
        proto_class = hrm_pb2.Person

Overriding serialization and deserialization behavior

A proto serializer is the same as one rest framework serializer, but we are adding the following logic:

  • Protobuf message -> Dict of python primitive datatypes.
  • Protobuf message <- Dict of python primitive datatypes.

If you need to alter the convert behavior of a serializer class, you can do so by overriding the .message_to_data() or .data_to_message methods.

Here is the default implementation:

from google.protobuf.json_format import MessageToDict, ParseDict

class ProtoSerializer(BaseProtoSerializer, Serializer):
    def message_to_data(self, message):
        """Protobuf message -> Dict of python primitive datatypes.
        """
        return MessageToDict(
            message, including_default_value_fields=True,
            preserving_proto_field_name=True
        )

    def data_to_message(self, data):
        """Protobuf message <- Dict of python primitive datatypes."""
        return ParseDict(
            data, self.Meta.proto_class(),
            ignore_unknown_fields=True
        )

The default behavior requires you to provide ProtoSerializer.Meta.proto_class, it is the protobuf class that should be used for create output proto message object. You must either set this attribute, or override the data_to_message() method.

Serializing objects

We can now use PersonProtoSerializer to serialize a person object:

>>> serializer = PersonProtoSerializer(person)
>>> serializer.message
name: "amy"
email: "amy@demo.com"
>>> type(serializer.message)
<class 'hrm_pb2.Person'>

Deserializing objects

Deserialization is similar:

>>> serializer = PersonProtoSerializer(message=message)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('name', 'amy'), ('email', 'amy@demo.com')])

ModelProtoSerializer

This is the same as a rest framework ModelSerializer:

from django_grpc_framework import proto_serializers
from hrm.models import Person
import hrm_pb2


class PersonProtoSerializer(proto_serializers.ModelProtoSerializer):
    class Meta:
        model = Person
        proto_class = hrm_pb2.Person
        fields = '__all__'