so I have this put endpoint
def put(self, request):
user_uuid = get_uuid_from_request(request)
user_obj = User.objects.get(pk=user_uuid)
serializer = UpdateUserSerializer(user_obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(dict(error=serializer.errors, user_msg=generic_error_message),
status=status.HTTP_400_BAD_REQUEST)
with the following serializer
class UpdateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('given_name', 'middle_name', 'family_name', 'birthdate')
if the incoming request has missing values as in
request.data ={'given_name':'Tom'}
I'd ideally like it to update anything that isn't missing in the current entity. How do I do this? Currently right now when I test it if an attribute is missing it complains.
You can add the flag partial=True to the serializer to support partial updates:
serializer = UpdateUserSerializer(user_obj, data=request.data, partial=True)
Related
I am trying to do a partial update of a user so that not all the fields should be sent in a request. For this I have created a view like this:
elif request.method == 'PATCH':
user_serializer = UserSerializer(user, data=request.data, partial=True)
if user_serializer.is_valid():
user_serializer.save()
return Response({'message': 'User updated correctly'}, status=status.HTTP_200_OK)
else:
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I have seen that if the partial = True parameter is activated then it will call the partial_update () function of the serializer, but it does not:
def partial_update(self, request, *args, **kwargs):
print("partial update")
So, how can I do this partial_update to update a user field?
Try assigning the serializer to the view:
serializer_class = UserSerializer
Then you can get the serializer from the view instance:
user_serializer = self.get_serializer(user, data=request.data, partial=True)
user_serializer.save()
Finally partial_update method should be triggered at view level.
Models.py
from django.contrib.auth.models import User
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name="conversation")
Urls.py
path('api/conversations/', views.ConversationListView.as_view(),
name='conversation-list'),
Serializers.py
class ConversationSerializer(serializers.ModelSerializer):
participants = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),
many=True)
class Meta:
model = Conversation
fields = ['id', 'participants']
Views.py
class ConversationListView(APIView):
def get(self, request, format=None):
conversations = Conversation.objects.all()
serializer = ConversationSerializer(
conversations, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ConversationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
So I would like to make a POST request on "api/conversations/" with this object:
{"participants": [2,3]} or {"participants": [3,2]}
BUT I would like to check first whether a conversation with participants are both User(id=2) and User(id=3) exist or not. If exists, I need to raise an error. If not exist, create a new conversation. So there is only one conversation between User(id=2) and User(id=3).
What I know so far is I have to make validate_participants(self, value) in the serializer. But I still can't figure out what is the logic to check it. I've tried using Conversation.objects.filter(participants__in=[2,3]) but I think it doesn't work because it does not return the conversation object that has both User(id=2) and User(id=3) as participants.
This code solves my problem. Add this to ConversationSerializer
def validate_participants(self, value):
query1 = Conversation.objects.filter(participants=value[0])
query2 = Conversation.objects.filter(participants=value[1])
if query1.intersection(query2).exists():
raise serializers.ValidationError(
"Conversation with these participants has exist")
return value
so heres my serializer class:
class HeroSerializer(serializers.ModelSerializer):
class Meta:
model=Hero
fields=['id','name','secret_identity']
and my view :
#api_view(['PUT', ])
def api_hero_update(request, name):
try:
character = Hero.objects.get(name=name)
except:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = serializers.HeroSerializer(character, data=request.data)
message={}
if serializer.is_valid():
serializer.save()
print(serializer.data)
message["success"]="Update Successful"
return Response(data=message)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
Let a model object has fields name and secret_identity. and i want to update its name only but the line
serializer = serializers.HeroSerializer(character, data=request.data)
doesnt allow me to update only , one field . how to update only one field?
you have to add partial=True attribute to serializer object. i.e. use this
serializer = serializers.HeroSerializer(character, data=request.data, partial=True)
By overriding the serializers update method:
class HeroSerializer(serializers.ModelSerializer):
class Meta:
model=Hero
fields=['id','name','secret_identity']
def update(self, instance, validated_data):
instance.secret_identity = validated_data.get('your field name', 'defaultvalue')
instance.save()
return instance
Don't forget to save your model inside the update method, or the changes wont be persistent in the database. If you need more information, this is described in the DRF docs.
I need to update my user in REST framework
views.py
class UserUpdate(APIView):
permission_classes = (permissions.IsAuthenticated,)
def post(self,request):
user=User.objects.get(id=request.user.id)
try:
user_serializer=UserSerializer(request.user,data=request.data, partial=True)
if user_serializer.is_valid():
user_serializer.save()
return Response(user_serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except:
return JsonResponse({'status':0,'message':'Error on user update'})
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'avatar']
models.py
class User(AbstractUser):
fb_userid = models.CharField(max_length=256)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
response:
DETAIL: Key (username)=() already exists.
def post(self,request):
user_serializer=UserSerializer(request.user, data=request.data, partial=True)
if user_serializer.is_valid():
user_serializer.save()
return Response(user_serializer.data, status=status.HTTP_200_OK)
else:
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#YKH is right this code is good there may error in your POST data.
In your image, you are passing two parameters in Header. It could possible you are passing the wrong header.
Content-Type should not be for form-data
I found this post where someone has a similar problem as you: Django Rest Framework unable to parse multipart/form data
It seems on your picture that you are putting something into Headers tab. Postman is taking care of that for you, so you shouldn't define anything there. Could you try again without setting anything in the headers?
I'd like to create a SpiderService with a foreign key request.user.
models:
from django.contrib.auth.models import User
class SpiderService(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20)
serializers:
class SpiderServiceSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.id')
class Meta:
model = SpiderService
fields = ('id', 'user', 'name')
class SpiderServiceListSerializer(viewsets.ModelViewSet):
queryset = SpiderService.objects.all()
serializer_class = SpiderService
views:
class SpiderServiceList(APIView):
def get(self, request, format=None):
services = SpiderService.objects.all()
serializer = SpiderServiceSerializer(services, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = SpiderServiceSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def perform_create(elf, serializer):
serializer.save(user=self.request.user)
when I post
{
"name": "2"
}
to the api url, got 500 error:
[01/Feb/2016 15:39:55] "POST /services/ HTTP/1.1" 500 17105
IntegrityError: NOT NULL constraint failed: spmanage_spiderservice.user_id
I have read Serializer relations and found I should not write code as above. The official example is equal to remove user field in SpiderServiceSerializer, and add a spiderservice field to a UserSerializer.Seems aim to achieve the syntax like user.spiderservice_set in django models, which do not fit my purpose.
I just want to create a spiderservice object with request.user.
How to solve it?
You need to add the current user as an extra parameter to the Serializer's save method:
serializer.save(user=request.user)
do you have any Account serializer for the user model ??
if so, in your SpiderServiceSerializer try this :
user = AccountSerializer(read_only=True, required=False)