Override RetrieveUpdateAPIView Django Rest Framework - python

Right now I'm overriding the whole retrieve and update function. I want to override only that part, it does not ask for the pk value. Thanks
View.py
class EmployeeView(generics.RetrieveUpdateAPIView):
permission_classes = [EmployeePermission]
serializer_class = EmployeeSerializers
def retrieve(self, request, *args, **kwargs):
employee = Employee.objects.get(user=self.request.user)
serializer = EmployeeSerializers(employee)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
employee_user = Employee.objects.get(user=self.request.user)
serializer = EmployeeSerializers(employee_user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)strong text
urls.py
path('viewEmployee/', views.EmployeeView.as_view()),

what you need is to override the get_queryset method, and write your custom filtering, then django will take care of otherthings.
class EmployeeView(generics.RetrieveUpdateAPIView):
queryset = Employee.objects.all()
permission_classes = [EmployeePermission]
serializer_class = EmployeeSerializers
def get_queryset(self):
return super().get_queryset().filter(
user=self.request.user
)

Related

Django Rest Framework ordering isnt working

Everything is imported, it might not be working because of get_queryset function, but i am not sure.
class ShowStats(ListAPIView):
serializer_class = StatsSerializer
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
ordering_fields = ('date', 'views', 'clicks', 'cost', 'cpc', 'cpm')
ordering = ('views',)
def get_queryset(self):
return Stats.objects.filter(date__range=[self.kwargs['from'], self.kwargs['to']])
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
response_list = serializer.data
for i in range(len(response_list)):
response_list[i]['cpc'] = response_list[i]['cost'] / response_list[i]['clicks']
response_list[i]['cpm'] = response_list[i]['cost'] / response_list[i]['views'] * 1000
return Response(data=response_list)
Change
queryset = self.get_queryset()
to
queryset = self.filter_queryset(self.get_queryset())
to apply filtering and/or ordering.
Here's what DRF's ListModelMixin looks like (for inspiration).
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

Refactoring views in Django REST framework

I am very new to Python and Django. I have this app that returns 4 different types of transport routes (In the code I only showed two, cause they basically are the same...).
These 4 views use the same class-based views, but only the models' names are different. As they all return the same functionality(get, post, put and delete) I ended up repeating the same code over and over again.
Is there any way I can refactor it simpler?
Any help is appreciated! Thank you :)
views.py
********* tube view ***********
class TubeListView(APIView):
def get(self, _request, format=None):
tubeRoutes = TubeRoute.objects.all()
serialized_with_user = NestedTubeRouteSerializer(tubeRoutes, many=True)
return Response(serialized_with_user.data)
def post(self, request, format=None):
request.data['traveler'] = request.user.id
serializer = TubeRouteSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE)
class TubeDetailView(APIView):
def get(self, _request, pk, format=None):
tubeRoute = TubeRoute.objects.get(pk=pk)
serialized_with_user = NestedTubeRouteSerializer(tubeRoute)
return Response(serialized_with_user.data)
def put(self, request, pk, format=None):
request.data['traveler'] = request.user.id
tubeRoute = self.get_object(pk)
if tubeRoute.owner.id != request.user.id:
return Response(status=status.HTTP_401_UNAUTHORIZED)
updated_serializer = TubeRouteSerializer(tubeRoute)
if updated_serializer.is_valid():
updated_serializer.save()
return Response(updated_serializer.data, status=status.HTTP_200_OK)
return Response(updated_serializer.errors, status=status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE)
def delete(self, request, pk, format=None):
tubeRoute = self.get_object(pk)
if tubeRoute.owner.id != request.user.id:
return Response(status=status.HTTP_401_UNAUTHORIZED)
tubeRoute.delete()
return Response(status=status.HTTP_200_OK)
********* bus view ***********
class BusListView(APIView):
def get(self, _request, format=None):
busRoutes = BusRoute.objects.all()
serialized_with_user = NestedBusRouteSerializer(busRoutes, many=True)
return Response(serialized_with_user.data)
def post(self, request, format=None):
request.data['traveler'] = request.user.id
serializer = BusRouteSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE)
class BusDetailView(APIView):
def get(self, _request, pk, format=None):
busRoute = BusRoute.objects.get(pk=pk)
serialized_with_user = NestedBusRouteSerializer(busRoute)
return Response(serialized_with_user.data)
def put(self, request, pk, format=None):
request.data['traveler'] = request.user.id
busRoute = self.get_object(pk)
if busRoute.owner.id != request.user.id:
return Response(status=status.HTTP_401_UNAUTHORIZED)
updated_serializer = BusRouteSerializer(busRoute)
if updated_serializer.is_valid():
updated_serializer.save()
return Response(updated_serializer.data, status=status.HTTP_200_OK)
return Response(updated_serializer.errors, status=status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE)
def delete(self, request, pk, format=None):
busRoute = self.get_object(pk)
if busRoute.owner.id != request.user.id:
return Response(status=status.HTTP_401_UNAUTHORIZED)
busRoute.delete()
return Response(status=status.HTTP_200_OK)
You should take a look to these class based views in DRF.
For instance, the following code should be enough to replace your first TubeListView:
from rest_framework import generics
class TubeListView(generics.ListCreateAPIView):
queryset = TubeRoute.objects.all()
serializer_class = NestedTubeRouteSerializer
def post(self, request, *args, **kwargs):
request.data['traveler'] = request.user.id
return super().post(self, request, *args, **kwargs)
If you don't need any special behavior, you don't have to redefine get, post, etc methods. But if you need to change data, for instance in your POST method, you can do your stuff and then call the usual behavior of the superclass with super().post(self, request, *args, **kwargs)
I would recommend checking Viewsets in Django Rest Framework, specifically ModelViewset.
The actions provided by the ModelViewSet class are .list(), .retrieve(), .create(), .update(), .partial_update(), and .destroy() which coincide with the following:
get ----> .retrieve()
list ----> .list()
post ----> .create()
patch ----> .partial_update()
put ----> .update()
delete ----> .destroy()
Let me provide a case using the Bus Views
The Modelviewset form would be:
class BusViewset(ModelViewset):
queryset = BusRoute.objects.all()
serializer_class = NestedBusRouteSerializer
def get_queryset(self):
return self.queryset.filter(
owner__id=self.request.user.id
)
For the permission checks you implemented, Django Rest Framework has a Permissions System that takes care of that. For you own use case, a custom permission would be sufficient.

ListCreateAPIView: How can I cache a serialized QuerySet?

I have a DRF class with a single method get_queryset(). I would like to add caching to the serialized queryset by intercepting the request before get_queryset gets called, but after custom middleware/authentication has been run. Here is a trivial example of what I'm after:
class FooList(generics.ListCreateAPIView)
permission_classes = (permissions.IsAuthenticated,)
serializer_class = FooSerializer
def intercept_for_caching(self):
user = self.request.meta_data['user']
cached_data = cache.get(f'FooStuff:{user.pk}')
if cached_data:
return Response(cached_data)
else:
new_data = ? # retrieve serialized queryset
cache.set(f'FooStuff:{user.pk}', new_data)
return Response(new_data)
def get_queryset(self):
user = self.request.meta_data['user']
return Foo.objects.filter(user=user)
Are there any methods I can hook into?
I am aware that cache_page is designed for this use case (https://www.django-rest-framework.org/api-guide/caching/), but I haven't been able to get it to work with our custom middeleware.
The source code has a function list:
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
I was able to cache the queryset by overriding list:
def list(self, request, *args, **kwargs):
user = self.request.user
cache = caches['redis']
cache_key = f'my_cache:{user.pk}'
cached_results = cache.get(cache_key)
if cached_results:
return Response(cached_results)
else:
queryset = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(queryset, many=True)
cache.set(cache_key, serializer.data)
return Response(serializer.data)

fixed error instance object is not callable

I need code for editing user details like first_name , last_name by using APIView Class based. THe serializers.py and views.py are given under but it is not making the changes according to the user details . i am passing token for user authentication. Any assistance will be appreciated.
Serializers.py
class UserEditSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
first_name = serializers.CharField(required=True)
last_name = serializers.CharField(required=True)
def update(self, validated_data, instance):
instance.first_name = validated_data.get('first_name')
instance.email = validated_data.get('email')
instance.last_name = validated_data.get('last_name')
instance.save()
return instance
Views.py
class UserEditProfile(APIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_object(self):
return self.request.user
def post(self, request):
self.object = self.get_object()
serializer = UserEditSerializer(data=request.data)
if serializer.is_valid():
self.object.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
How would the serializer know it must update a user if you don't provide it ?
serializer = UserEditSerializer(data=request.data)
should be:
serializer = UserEditSerializer(self.object, data=request.data)
Edit:
Also, remove the () after return instance
This view will work . Thanks Linovia
class UserEditProfile(APIView):
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def post(self, request):
obj = User.objects.get(id=request.user.id)
serializer = UserEditSerializer(obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

GET request in Django Rest framework is not working with filter in the response JSON object

Views.py
class UserPoints(ListAPIView):
queryset = UserAttributes.objects.all()
serializer_class = UserPointsSerializer
OR
def get(self, request, pk, format=None):
UserAttributes = self.get_object(id)
serializer = UserPointsSerializer(UserAttributes)
return Response(serializer.data)
Serializers.py
class UserPointsSerializer(serializers.ModelSerializer):
username = serializers.Field(source='User')
class Meta:
model = UserAttributes
fields = [
'points',
]
I want to get the point associated with a particular user when I send a GET Request with username as a parameter.
You need to call .is_valid() on the serializer
def get(self, request, pk, format=None):
user_attributes = UserAttribute.objects.get(id=id)
serializer = UserPointsSerializer(data=user_attributes)
if serializer.is_valid():
return Response(serializer.data)

Categories

Resources