Custom Serializers - serializers that do not map directly onto a model

My questions are with regards to Django Rest Framework, and specifically, Custom Serializers - serializers that do not map directly onto a model. I have really done my best to summarize.

Assume we have two tables, User Table and User Information table linked by a one-to-one relationship (user being a field in User Information). I created a custom Serializer which combines all fields of both tables and when save() is called, creates a record in both User Table and User Information Table.

Observations

In the view, serializer.data will be empty. Probably because the serializer does not commit to the db (given that the serializer does not map to one specific model) and therefore serializer.data is not populated. Is this possibly the (most) correct implementation?

I cannot get it to work for both read and write (see code below). It seems to work for reading or writing but not both. If the serializer is not mapped to a model, can it read and write or just write? Maybe my Serializer is poorly done?

SERIALIZER

    first_name = serializers.CharField(
        write_only=True,
        required=True
    )
    last_name = serializers.CharField(
        write_only=True,
        required=True
    )
    phone_number = serializers.CharField(
        write_only=True,
        required=True
    )
    email = serializers.CharField(
        write_only=True,
        required=True
    )    national_id = serializers.CharField(
        write_only=True,
        required=True
    )
    def validate(self, attrs):
       # validation checks for fields have been omitted
        return attrs

    def create(self, validated_data):
        user_data = {
            'email': validated_data.get('email'),
            'first_name': validated_data.get('first_name'),
            'last_name': validated_data.get('last_name'),
            'phone_number': validated_data.get('phone_number'),
        }

        user = User.objects.create_user(**user_data) # custom create_user works well
        user.is_customer = True
        user.is_activated = True
        user.save()

        customer = Customer(
            user=user,
            national_id=validated_data.get('national_id')
        )
        customer.save()
        return customer

VIEW

class CreateCustomer(generics.CreateAPIView):
    queryset = Customer.objects
    serializer_class = CustomRegisterSerializer

    def perform_create(self, serializer):
        return serializer.save() # needed to get the instance

    def create(self, request, *args, **kwargs):
        # TODO: Why is serializer.data empty?
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        customer_instance = self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        customer_data = {
            'id': customer_instance.pk,
            'user_id': customer_instance.user.pk,
            'first_name': customer_instance.user.first_name,
            'last_name': customer_instance.user.last_name,
            'email': customer_instance.user.email,
            'phone_number': customer_instance.user.phone_number,
            'national_id': customer_instance.national_id,
            'username': customer_instance.user.username,
        }
        return Response(customer_data, status=status.HTTP_201_CREATED, headers=headers)

Below Does not work (removed ‘write_only’ and ‘required’): Error - first_name not found

class CustomRegisterSerializer(Serializer):
    first_name = serializers.CharField( )
    last_name = serializers.CharField( )
    phone_number = serializers.CharField( )
    email = serializers.CharField( )
    national_id = serializers.CharField( )

Below Does not work (added defaul=’’): Results in dictionary with empty values

class CustomRegisterSerializer(Serializer):
    first_name = serializers.CharField(default='' )
    last_name = serializers.CharField(default='')
    phone_number = serializers.CharField(default='' )
    email = serializers.CharField(default='')
    national_id = serializers.CharField(default='')

Is this a better solution?

class CustomRegisterSerializer(Serializer):
    user = UserSerailizer()
    user_information = UserInformationSerializer()

I hope my explanation brings out the issues clearly. Please let me know what you think.
Thank you in advance.

1 Like