Django rest_framework perform_update - django

I trying to move my def update from my serializer.py to my views.py, What it does is well after updating an Item it also saves a log to transaction_log
class ClearanceItemSerialize(serializers.ModelSerializer):
class Meta:
model = ClearanceItem
fields = '__all__'
def update(self, instance, validated_data):
instance.resolve = 'True'
instance.resolve_date = timezone.now()
instance.save()
TransactionLog.objects.create(cl_itemid=ClearanceItem.objects.get(cl_itemid=instance.cl_itemid),
trans_desc="Resolve Clearance Item",
trans_recorded=timezone.now())
return instance
views.py
class APIClerkUpdate(generics.RetrieveUpdateAPIView):
permission_classes = [IsAuthenticated]
queryset = ClearanceItem.objects.all()
serializer_class = ClearanceItemSerialize
def perform_update(self, serializer):
"""
What to put here
"""
hope someone help thank you.

Just like in your serializer:
class APIClerkUpdate(generics.RetrieveUpdateAPIView):
def perform_update(self, serializer):
serializer.save()
instance = serializer.instance
TransactionLog.objects.create(
cl_item=instance,
trans_desc="Resolve Clearance Item",
trans_recorded=timezone.now()
)

Related

How can I update specific field after retrieved in django rest framework

How can I update specific field after retrieved in django rest framework
# Models.py
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
view = models.IntegerField(default=0)
def __str__(self):
return self.title
I want to update view after read a specific data.
# Views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Update view + 1
# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
Please help me
If you want your field to be incremented only on a GET request, you can update it in the retrieve method:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.view = instance.view + 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
If you want it to be incremented with both GET and PATCH, you could update it in get_object instead:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_object(self):
instance = super(ArticleDetail, self).get_object()
instance.view = instance.view + 1
instance.save()
return instance

Check if object parent user == request.user on child object create/update

I want to check if parent object user is request.user to correctly add child amd grandchild object permissions.
Wanna figure out how to do it properly in Django & DRF.
Models:
class Parent(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Child(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='childs')
class SecondChild(models.Model):
parent = models.ForeignKey(Child, on_delete=models.CASCADE, related_name='secondchilds')
Views:
class ParentViewSet(viewsets.ModelViewSet):
queryset = Parent.objects.all()
serializer_class = ParentSerializer
permission_classes = [permissions.IsAuthenticated, IsOwner]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
def get_queryset(self):
user = self.request.user
if user.is_superuser:
return Parent.objects.all()
return Parent.objects.filter(user=user).prefetch_related('childs', 'childs__secondchilds')
class ChildViewSet(viewsets.ModelViewSet):
queryset = Child.objects.all()
serializer_class = ChildSerializer
permission_classes = [permissions.IsAuthenticated]
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
parent_id = self.request.data.get('parent_id')
parent_instance = Parent.objects.filter(id=parent_id).first()
if not serializer.is_valid(raise_exception=True):
print(serializer.errors)
serializer.save(parent=parent_instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
user = self.request.user
if user.is_superuser:
return Parent.objects.all()
return Child.objects.filter(parent__user=user).prefetch_related('SecondChild')
you can do the checking on your custom permission class, then add the it to your view's permission_classes list
permissions
class IsParentOwnerOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
parent_id = int(request.data.get('parent_id'))
parent_instance = Parent.objects.filter(id=parent_id).first()
return (request.method in permissions.SAFE_METHODS or
(parent_instance and request.user == parent_instance.user))
views
class ChildViewSet(viewsets.ModelViewSet):
...
permission_classes = [permissions.IsAuthenticated, IsParentOwnerOrReadOnly]
...

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 I can pass over a field validation in a serializer in Django Rest Framework

I have a Location model and I need to create a Location without specifying a user, if user in empty then the user will be placed in request.user in the viewset.
This is my model:
class Location(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
serializer:
class LocationSerializer(serializers.ModelSerializer):
def is_valid(self):
if not 'user' in self.init_data:
# avoid this validation.. I manage this in the viewset
pass
return not self.errors
class Meta:
model = Location
and viewset
class LocationViewSet(ModelViewSet):
"""
API endpoint that allows location to be created or viewed.
"""
model = Location
serializer_class = LocationSerializer
renderer_classes = (JSONRenderer, JSONPRenderer)
def get_queryset(self):
return self.request.user.locations.filter(deleted=False)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
if not self.object.user:
self.object.user = request.user
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
Thanks for any suggestion
You can use required=False in serializer:
class LocationSerializer(serializers.ModelSerializer):
user = serializers.RelatedField(required=False)
EDIT
Also you can simplify your viewset with:
class LocationViewSet(ModelViewSet):
def pre_save(self, obj):
if obj.user_id is None:
obj.user = self.request.user
This avoid copying code from DRF core.