Reputation: 5366
I have extended user model to store user profile related information:
class Profile(models.Model):
user = models.OneToOneField(User, blank=True, on_delete=models.CASCADE, )
name = models.CharField(max_length=50, blank=True, null = True, )
age = models.IntegerField(blank=True, null = True, )
EDUCATION_CHOICES = (
('VOC', 'Vocational'),
('DPL', 'Diploma'),
('BCL', 'Bachelor'),
('MST', 'Master'),
('DOC', 'Doctor'),
)
education = models.CharField(blank=True, null = True, choices=EDUCATION_CHOICES, max_length=3, )
short_story = models.TextField(blank=True, null = True, max_length=500)
ROLE_CHOICES = (
('INT', 'Intern'),
('WOR', 'Worker'),
('SUP', 'Supervisor'),
('MAN', 'Manager'),
)
role = models.CharField(blank=True, null = True, choices=ROLE_CHOICES, max_length=3, )
hobbies = models.TextField(blank=True, null = True, max_length=500)
rational_thinker = models.NullBooleanField(blank=True, null = True, default=False)
welcome_new_changes = models.NullBooleanField(blank=True, null = True, default=False)
embrace_science = models.NullBooleanField(blank=True, null = True, default=False)
if_social = models.NullBooleanField(blank=True, null = True, default=False)
seek_latest_info = models.NullBooleanField(blank=True, null = True, default=False)
exciting_about_job = models.TextField(blank=True, null = True, max_length=500)
not_exciting_about_job = models.TextField(blank=True, null = True, max_length=500)
aspiration = models.TextField(blank=True, null = True, max_length=500)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
Its serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
And view:
@api_view(['GET', 'PUT', 'DELETE'])
def profile(request):
"""
Get, udpate, or delete a specific profile
"""
try:
profile = Profile.objects.get(user=request.user.id)
print(profile)
print(request.data)
except Profile.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = ProfileSerializer(profile)
return Response(serializer.data)
elif request.method == 'PUT':
print('PUT called')
serializer = ProfileSerializer(profile, data=request.data)
if serializer.is_valid():
print('Valid')
serializer.save(user=request.user)
return Response(serializer.data)
else:
print('Else')
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
profile.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Profile is created automatically when the user is created.
While updating a Profile when I send partially filled data i.e. some fields are sent blank, I get Bad Request error. User should be able to fill only fields he wishes to and must not all. If I make a PUT request with all the data, then it is successful.
Why is it happening?
Upvotes: 1
Views: 2763
Reputation: 3827
Usually PUT method used to update all fields. PATCH method is used for partial update. But you can override it by adding partial=True
in the serializer. If you still want to use PUT for partial update, then set serializer as
serializer = ProfileSerializer(profile, data=request.data, partial=True)
Applying this on your view will looks like:
@api_view(['GET', 'PUT', 'DELETE'])
def profile(request):
"""
Get, udpate, or delete a specific profile
"""
try:
profile = Profile.objects.get(user=request.user.id)
except Profile.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = ProfileSerializer(profile)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = ProfileSerializer(profile, data=request.data, partial=True)
# setting raise_exception=True in the serializer's is_valid method will raise exception on error. So you don't have implement extra logics
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user)
return Response(serializer.data)
elif request.method == 'DELETE':
profile.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Upvotes: 2
Reputation: 2029
PUT method needs all the fields. If you want to pass only few fields, use PATCH method.
Upvotes: 0