Reputation: 104
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
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