Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update Nested Serializers Correctly in Django Rest Framework

I am using django rest framework I am trying to implement an update method to a nested serializer. How do I implement an update method to nested serializer correctly?

I'm trying to update an existing employee but I get the following response:

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

I have implemented an update method on the serializers just to update the user fields.

class EmployeeUpdateSerializer(serializers.ModelSerializer):
    user = UserSerializer()
    contract_type = ContractSerializer(read_only=True)
    company = CompanySerializer(read_only=True)
    job_title = JobSerializer(read_only=True)
    department = DepartmentSerializer(read_only=True)
    skill = SkillSerializer(read_only=True)
    unit = UnitSerializer(read_only=True)

    class Meta:
        model = Employee
        fields = ['id', 'user', 'hr_number', 'nssf_no', 'nhif_no', 'induction_date',
                  'induction_date', 'contract_type', 'company',
                  'tax_id_number', 'joining_date', 'job_title', 'skill', 'unit',
                  'department', 'identification_number', 'is_manager', 'active']

    def update(self, instance, validated_data):
        user = validated_data.get('user')
        instance.user.first_name = user.get('first_name')
        instance.user.save()

        return instance

Then in the views I have implemented the following:

class EmployeeDetailView(APIView):
    permission_classes = [AllowAny]
    # queryset = Employee.objects.all()
    serializer_class = EmployeeUpdateSerializer
    """
    Retrieve, update or delete a employee instance.
    """

    def get(self, request, pk, format=None):
        try:
            employee = Employee.objects.get(pk=pk)
        except Employee.DoesNotExist:
            raise Http404
        serializer = EmployeeUpdateSerializer(employee)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request, pk, format=None):
        try:
            employee = Employee.objects.get(pk=pk)
            serializer = EmployeeUpdateSerializer(
                employee, data=request.data)
        except Employee.DoesNotExist:
            raise Http404
        # serializer = EmployeeUpdateSerializer(data=request.data)
        if serializer.is_valid():
            print(serializer.data)
            serializer.update()
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        return Response(serializer.data, status=status.HTTP_200_OK)
like image 680
Philip Mutua Avatar asked Nov 07 '22 07:11

Philip Mutua


1 Answers

The UniqueValidator on your username field in UserSerializer is causing this issue, it's running a validation against the queryset to check if the username already exists.

You can remove this validation in your UserSerializer by adding the following to the Meta class:

        extra_kwargs = {
        'username': {
            'validators': [],
        },
    }

This is a quick and dirty fix as it will cause integrity issues with your DB if you try and save 2 instances with the same username.

like image 196
Craig Minchin Avatar answered Nov 09 '22 22:11

Craig Minchin