Daniel van Flymen February 2016

Get or Create Functionality on a Writable Nested Serializer

Suppose I have the following models:

Order(models.Model):
    user = models.ForeignKey('User')
    ...

User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=100)
    ...

Note: USERNAME_FIELD = 'email'.

When a new order is created, I would like to link it to a customer with the supplied email, or create the customer if the they do not exist already.


This is what I've tried so far:

serializers.py:

class OrderSerializer(serializers.ModelSerializer):
    customer = UserSerializer(many=False)

    class Meta:
        model = Order

    def create(self, validated_data):
        user_data = validated_data.pop('user')

        # Get or create a User
        user, created = User.objects.get_or_create(
            email=user_data['email'],
            defaults={
                'email': user_data['email']
            }
        )
        order = Order.objects.create(user=user, **validated_data)
        return order

The problem is, if a User exists, I get a 400 "Email already exists" error.

Answers


Daniel van Flymen February 2016

To do this, I had to disable the unique validators on a User. This seemed like a bad idea considering that I would need those validators when creating Users from a different endpoint.

email had to be unique and the nested serializer runs the valdiation from the UserSerializer.

Instead, I created another serializer called OrderUserSerializer as follows:

serializers.py:

class OrderUserSerializer(serializers.Serializer):
    email = serializers.EmailField(max_length=200)


class OrderSerializer(serializers.ModelSerializer):
    user = OrderUserSerializer(many=False)

    class Meta:
        model = Order

    def create(self, validated_data):
        user_data = validated_data.pop('user')

        user, created = User.objects.get_or_create(
            email=user_data['email'],
            defaults={
                'email': user_data['email']
            }
        )

        order = Order.objects.create(user=user, **validated_data)
        return order

Post Status

Asked in February 2016
Viewed 1,620 times
Voted 14
Answered 1 times

Search




Leave an answer