0

I have two models User and Address. The Address model is connected to User model as OneToOneField. In my case I trying to update the User model, in Initial case the address field of User model is null. So in first case When I update User model, I want to create an Address. In other cases only need to update address. How to achieve this?

models.py

class User(AbstractUser):
    first_name = models.CharField(max_length=100, blank=True, default=None, null=True)
    dp = models.ImageField(upload_to='profiles/', blank=True)
    gender = models.CharField(choices=GENDER_TYPE_CHOICES, max_length=10, default=None, blank=True, null=True)
    marital_status = models.BooleanField(default=False)
    dob = models.DateField(default=None, blank=True, null=True, )
    email = models.EmailField(default=None, blank=True, null=True, unique=True)
    mobile = PhoneNumberField(blank=True, null=True, unique=True)
    fire_token = models.TextField(blank=True, default=None, null=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=True)

    def __str__(self):
        return str(self.first_name)


class Address(models.Model):
    user = models.OneToOneField(User, default=None, null=True, blank=True, related_name="address_user",
                                on_delete=models.CASCADE)
    raw = models.CharField(max_length=100, blank=True, default=None, null=True)
    street_number = models.CharField(max_length=100, blank=True, default=None, null=True)
    route = models.CharField(max_length=100, blank=True, default=None, null=True)
    locality = models.CharField(max_length=100, blank=True, default=None, null=True)
    postal_code = models.CharField(max_length=6, blank=True, default=None, null=True)
    state = models.CharField(max_length=100, blank=True, default=None, null=True)
    state_code = models.CharField(max_length=6, blank=True, default=None, null=True)
    country = models.CharField(max_length=100, blank=True, default=None, null=True)
    country_code = models.CharField(max_length=6, blank=True, default=None, null=True)

    def __str__(self):
        return str(self.raw)

serializers.py

  class AddressSerializer(ModelSerializer):
    class Meta:
      model = Address
      fields = '__all__'
  class UpdateUserProfileSerializer(ModelSerializer):
    class Meta:
      model = User
      fields = ('first_name', 'dp', 'gender', 'marital_status', 'dob', 'address')

views.py

class UserProfileAPIView(APIView):
    serializer_class = UserProfileSerializer
    permission_classes = [IsAuthenticated]

    # Get User Profile
    def get(self, request):
        serializer = UserProfileSerializer(request.user, context={'request': request})
        return Response({'result ': serializer.data},
                        status=status.HTTP_200_OK)


    def patch(self, request):

        user_serializer = UpdateUserProfileSerializer(request.user, data=request.data, context={'request': request})
        if user_serializer.is_valid():
            user_serializer.save()
            return Response({'response': 'Successfully updated', 'result': user_serializer.data},
                            status=status.HTTP_200_OK)
        else:
            return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

I need out like below

{
    "result ": {
        "first_name": "Alwin Lazar V",
        "dp": null,
        "gender": null,
        "marital_status": false,
        "dob": null,
        "email": "[email protected]",
        "mobile": null,
        "address": null
    }
}

The address filed contain address object as response.

Request Data Format

first_name: Alwin
gender: m
marital_status: false
raw: <String>
street_number: <String>
route: <String> 
locality: <String>
postal_code: <String>
state: <String>
state_code: <String>
country: <String>
country_code: <String>
2

1 Answer 1

2

You can use the nested serializer and override the update method:

serializers.py

class AddressSerializer(ModelSerializer):
  
    class Meta:
       model = Address
       exclude = ('user',)
  

class UpdateUserProfileSerializer(ModelSerializer):
    address = AddressSerializer()
  
    class Meta:
        model = User
        fields = ('first_name', 'dp', 'gender', 'marital_status', 'dob', 'address')

   def update(self, instance, validated_data):
      address = validated_data.pop('address')
      instance = super().update(instance, validated_data)
      if hasattr(instance, 'address'):
         for key, value in address.items():
            setattr(instance.address, key, value)
         instance.address.save()
      else:
          Address.objects.create(user=instance, **address)
      return instance
Sign up to request clarification or add additional context in comments.

3 Comments

how to pass parameters using this way... I want to pass raw, city..etc as parameters in request.
I updated my question with request data format. Sorry for late replay
when I pass { "address": { "raw":"address line 1", "state":"Kerala" } } as raw of body in postman.. It shows an error in python console if hasattr(instance, address): TypeError: hasattr(): attribute name must be string... how to overcome this issue

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.