Bad request 400 while trying to do partial update with UpdateAPIView - django

I am using DRF UpdateAPIView to take in PATCH method and partially update my model. It should by default handel correctly partial update but i somehow get Bad request error. What could be issue here?
View:
class ProfileViewUpdate(generics.UpdateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'token'
lookup_url_kwarg = 'pk'
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
Serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'bio', 'name', 'email', 'sport', 'location', 'image')

Related

Why Django's OneToOneField returns 500 if relation aready exists

In a Django REST Framework POST view, is there any way to avoid an HTTP 500 if the OneToOneField relation already exists?
Instead, it would be great to get an HTTP 400.
models.py
class Club(TimeStampModel):
owner = models.OneToOneField(User, on_delete=models.PROTECT)
name = models.CharField(max_length=255, unique=True)
serializers.py
class ClubSerializer(serializers.ModelSerializer):
class Meta:
model = Club
fields = '__all__'
read_only_fields = ['owner', 'active']
views.py
class ClubRegistrationView(generics.CreateAPIView):
queryset = Club.objects.all()
serializer_class = ClubSerializer
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
Thanks.
When you passed owner like this serializer.save(owner=self.request.user) serializer doesn't perform validation. You should rewrite create instead of perform_create method for this
class ClubRegistrationView(generics.CreateAPIView):
queryset = Club.objects.all()
serializer_class = ClubSerializer
permission_classes = [IsAuthenticated]
def create(self, request, *args, **kwargs):
request.data["owner"] = request.user.pk
return super().create(request, *args, **kwargs)
Here a validation error:
{'user': ['This field must be unique.']}

Allow partial update in serializer_class in Django REST

I am trying to partially update my ProfileSerializer when i am making PATCH request. However i am not able to make it beacuse by default Serializer doesn't allow partial changes to be made. I am using Django Rest Framwork UpdateModelMixin to handle my patch request. Where can i set partial=True in my case?
View:
class ProfileViewPartialUpdate(GenericAPIView, UpdateModelMixin):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'token'
lookup_url_kwarg = 'pk'
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
Serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'bio', 'name', 'email', 'sport', 'location', 'image')
View:
from rest_framework import generics
class ProfileViewPartialUpdate(generics.RetrieveUpdateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'pk'
Serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'bio', 'name', 'email', 'sport', 'location', 'image')
Look at this snippet code from one of my projects. You can modify accordingly. Add this to ProfileViewPartialUpdate class instead of patch.
def partial_update(self, request, slug):
user = self.request.user
get_blog = Blog.objects.get(slug=slug)
instance = self.get_object()
serializer = BlogSerializer(instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data, status=HTTP_201_CREATED)
return Response(data="wrong parameters", status=HTTP_400_BAD_REQUEST)
Hope this might help

partial_update only if not exist (PATCH Django Rest Framework)

I am currently using partial_update to update info but I want to update it only if that specific field is empty.
views.py
class TitleViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
queryset = Title.objects.all()
serializer_class = TitleSerializer
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
serializers.py
class TitleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Title
fields = ['pk', 'name', 'steam_appid', 'website', 'twitter']
So instead of updating for example 'twitter' field. I ONLY want to update if its empty. Also I dont want to specify 'twitter' as a field since I have many more.
Found a solution, it basically checks of the attribute is empty, if its not it does nothing. If it is empty, it will update it.
class TitleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Title
fields = ['pk', 'name', 'steam_appid', 'website', 'twitter']
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if not getattr(instance, attr):
setattr(instance, attr, value)
instance.save()
return instance

How to implicitly pass user from a request to corresponding serializer?

I have a following code:
class Article(models.Model):
...
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ('id', 'title', 'content', 'owner')
extra_kwargs = {
'owner': {'write_only': True},
}
class ArticleList(generics.ListCreateAPIView):
serializer_class = ArticleSerializer
def get_queryset(self):
user = self.request.user
return Article.objects.filter(owner=user.id)
def post(self, request, *args, **kwargs):
request.data['owner'] = self.request.user.id
return self.create(request, *args, **kwargs)
I have to explicitly pass user from request in post method of ArticleList ApiView to satisfy ForeignKey non-empty requirement. This is fine. But I have another models with a ForeignKey to User and as a result it leads to many copy-paste lines, especially in POST and PUT methods.
Does anybody knows more elegant DRY solution?

django rest framework RetrieveUpdateAPIView

I come from Vietnam.
I want to update User by Django Rest FrameWork. I can update User by 'pk'. But I can't update User by 'username'. I hope that everyone help me. Thank you so much.
serializers.py
class UserDetailSerializer(serializers.ModelSerializer):
url_update = serializers.HyperlinkedIdentityField(view_name='api:UserUpdateAPIView', lookup_field='username')
class Meta:
model = User
fields = ('url_update', 'username', 'email', 'user_permissions', 'is_staff', 'groups', 'last_login')
class UserUpdateSerialier(serializers.ModelSerializer):
password = serializers.CharField(
style={'input_type': 'password'}
)
class Meta:
model = User
fields = ('pk', 'username', 'password')
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.set_password(validated_data.get('password', instance.password))
instance.save()
return instance
views.py
class UserDetailAPIView(generics.RetrieveAPIView):
permission_classes = (permissions.IsAdminUser,)
serializer_class = UserDetailSerializer
#queryset = User.objects.all()
lookup_field = 'username'
def get_object(self):
username = self.kwargs["username"]
return get_object_or_404(User, username=username)
class UserUpdateAPIView(generics.RetrieveUpdateAPIView):
permission_classes = (permissions.IsAdminUser,)
#queryset = User.objects.all()
serializer_class = UserUpdateSerialier
def get_object(self):
username = self.kwargs["username"]
return get_object_or_404(User, username=username)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
urls.py
url(r'^$', views.UserListAPIView.as_view(), name='UserListAPIView'),
url(r'^(?P<username>.*)/$', views.UserDetailAPIView.as_view(), name='UserDetailAPIView'),
url(r'^(?P<username>.*)/update/$', views.UserUpdateAPIView.as_view(), name='UserUpdateAPIView'),
HTTP 404 Not Found
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"detail": "Not found."
}
Try editing your view like this,
class UserUpdateAPIView(generics.RetrieveUpdateAPIView):
permission_classes = (permissions.IsAdminUser,)
serializer_class = UserUpdateSerialier
lookup_field = 'username'
def get_object(self):
username = self.kwargs["username"]
return get_object_or_404(User, username=username)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
You need to set lookup_field = 'username' to the UserUpdateAPIView just like you did with the UserDetailAPIView