Mishter_Jingles
Mishter_Jingles

Reputation: 104

creating two models in one serializer of django rest framework

During registration of a user I would like to have both a User object and a EmailContact object created in one api call. The two objects should not be linked. I have the following serializer:

class RegistrationSerializer(serializers.Serializer):
    userserializer=UserAccountSerializer() #reuse existing modelserializer
    emailcontactserializer=EmailContactSerializer()  #reuse existing modelserializer  

    def create(self, validated_data):
        emailcontact_data = validated_data.pop('emailcontactserializer')
        user_data = validated_data.pop('userserializer')
        emailcontact= EmailContact.objects.create(**emailcontact_data)
        user= User.objects.create(**user_data) 
        return user 

and the following Apiview:

class RegistrationAPIView(APIView):
    permission_classes = (AllowAny,)
    serializer_class = RegistrationSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

The error I get is the following (occurs after the serializer.save()):

AttributeError at /api/register Got AttributeError when attempting to get a value for field userserializer on serializer RegistrationSerializer. The serializer field might be named incorrectly and not match any attribute or key on the User instance. Original exception text was: 'User' object has no attribute 'userserializer'.

Upvotes: 1

Views: 2129

Answers (1)

Symmetric
Symmetric

Reputation: 4743

In your RegistrationSerializer.create() method, you're returning a User object. The serializer will try to serialize that object into this representation:

{
  'userserializer': x,
  'emailcontactserializer': y
}

But it's complaining because the User you returned doesn't have a userserializer field.

If you really want to return a User from this API call, you could make your RegistrationSerializer a ModelSerializer with Meta.model=User, and override perform_create to pop out the emailcontact_data. (I'd name the field something like RegistrationSerializer.email_contact to make the representation clearer, IMO the phrase "serializer" shouldn't be present on the client-visible portion of the API).

Alternatively, if you want to render both of your sub-serializers, you can create a RegistrationSerializer instance in RegistrationSerializer.create by passing in the data, something like

return RegistrationSerializer(data={'emailcontactserializer': 
    emailcontact_data, 'userserializer': user_data})

Upvotes: 1

Related Questions