2
votes

I have extended user model in Django, and it is of Customer type. I am using django rest framework (DRF). So, while going through docs in DRF I came to know about writing in nested models, so I did override create and update methods in serializer, creation is working fine but not the update as it says :

HTTP 400 Bad Request
Allow: GET, PUT, PATCH, DELETE, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "user": {
        "username": [
            "A user with that username already exists."
        ]
    }
}

Here is my Customer model:

from django.db import models
from django.contrib.auth.models import User


class Customer(models.Model):
    user = models.OneToOneField(User, related_name="customer", on_delete=models.CASCADE)
    date_of_birth = models.DateField(max_length=8)

    def __unicode__(self):
        return u'%s' % self.user.username

My User serializer:

from django.contrib.auth.models import User

from rest_framework import serializers


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'is_staff')

And my extended customer model serializer:

from django.contrib.auth.models import User
from django.contrib.auth import get_user_model

from rest_framework import serializers

from customers.models import Customer
from api.serializers import UserSerializer


class CustomerSerializer(serializers.HyperlinkedModelSerializer):
    user = UserSerializer()
    class Meta:
        model = Customer
        fields = ('url', 'date_of_birth', 'user')
        depth = 1

    def create(self, validated_data):
        print "coming inside create"
        user_data = validated_data.pop("user")
        user = User.objects.create(**user_data)
        customer = Customer.objects.create(user=user, **validated_data)
        return customer

    def update(self, instance, validated_data):
        print "coming inside update"
        user_data = validated_data.pop("user")
        username = user_data.pop('username')
        user = get_user_model().objects.get_or_create(username=username)[0]
        user.email = user_data.get('email', user.email)
        user.save()

        instance.user = user
        instance.date_of_birth = validated_data.get('date_of_birth', instance.date_of_birth)
        instance.save()



        return instance

Here is the viewset view:

from rest_framework import viewsets

from customers.models import Customer
from customers.serializers import CustomerSerializer


class CustomerViewSet(viewsets.ModelViewSet):
    serializer_class = CustomerSerializer
    queryset = Customer.objects.all()

So, what could be wrong here that it is creating a new profile of customer even the new user but not updating?


Edit 1 Ok, so I did this on UserSerializer:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'is_staff')
        extra_kwargs = {
            'username': {'validators': []},
        }

So, update is fine for all the other fields of user or customer fields but

  • if I try to set a new username it creates an entirely new user,
  • and also when trying to create a new user, it gives the following error:

    IntegrityError at /api/customers/

    duplicate key value violates unique constraint "auth_user_username_key" DETAIL: Key (username)=(customer1) already exists.

1

1 Answers

4
votes

You should drop the unique validator for the nested serializer:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'is_staff')
        extra_kwargs = {
            'username': {'validators': []},
        }

You may want to print your serializer before to make sure you don't have other validators on that field. If you have some, you'll have to include them in the list.