Django Filter Backend not working in restful api in django - django-rest-framework

I am trying to use django-filters in have search queries in url using params
view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from .models import RecruiterRegister
from .serializers import RecruiterRegisterSerializer
# from rest_framework import filters
from rest_framework import generics
class RecruiterRegisterList(APIView):
queryset=RecruiterRegister.objects.all()
filter_backends = (DjangoFilterBackend,SearchFilter ,)
filter_fields = ('email','password')
search_fields = ('email','password')
def get(self, request, format=None):
recruiterRegisters = RecruiterRegister.objects.all()
# self.filter_backends = (DjangoFilterBackend,)
# self.filter_fields = ('password', )
serializer = RecruiterRegisterSerializer(recruiterRegisters, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = RecruiterRegisterSerializer(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 delete(self, request, pk, format=None):
recruiterRegisters = self.get_object()
recruiterRegisters.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
but I am not able to get filtered data. All the api data appears.
url sample
http://127.0.0.1:8000/recruiterRegister/?password=random2
edited RecruiterRegisterList class:
class RecruiterRegisterList(generics.ListAPIView):
queryset=RecruiterRegister.objects.all()
serializer_class = RecruiterRegisterSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields=('email','password')
# search_fields = ('email','password')
def list(self, request ):
queryset = self.get_queryset()
serializer = RecruiterRegisterSerializer(queryset, many=True)
return Response(serializer.data)

First question is - why would you ever want to filter or search by password? that is a very unhealthy and unsecure design. Passwords are not stored in their raw formats but hashed so the filters will never hit anyway
Now, even if you really wanted to do that, filtering using filter_backends is implemented in the GenericAPIView and not available in APIView so you may want to use the ListAPIview from rest_framework.generics instead.
Lastly, even if you used the ListAPIView, it still wouldn't work because you're overriding the get method and not calling self.filter_queryset().
Use the ListAPIView and use the already implemented list() method and it will work

I'm adding only the line bellow & working fine:
filter_backends = self.filter_queryset(queryset)
And your code like:
class RecruiterRegisterList(generics.ListAPIView):
queryset=RecruiterRegister.objects.all()
serializer_class = RecruiterRegisterSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields=('email','password')
search_fields = ('email','password')
def list(self, request ):
queryset = self.get_queryset()
filter_backends = self.filter_queryset(queryset)
serializer = RecruiterRegisterSerializer(filter_backends, many=True)
return Response(serializer.data)

Related

PUT request doesn't update - Django Rest Framework

I'm trying to build a todos app using django-rest-framework and when I send PUT request to change the content of the task, the content is still the same. It seems that the serializer.save() is not working as I expected.
Here are the code:
views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import Note
from .serializers import NoteSerializer
#api_view(['PUT'])
def updateNote(request, pk):
note = Note.objects.get(id=pk)
serializer = NoteSerializer(instance=note, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
models.py
from django.db import models
class Note(models.Model):
body = models.TextField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body[0:50]
serializers.py
from rest_framework.serializers import ModelSerializer
from .models import Note
class NoteSerializer(ModelSerializer):
class Meta:
model = Note
fields = '__all__'
I'm learning django so this is kinda new to me. I had searched for this problem but I'm kinda new to django so I don't understand these answers much. Any help would be appreciated.
#api_view(['PUT'])
def updateNote(request, self, pk):
note = get_object_or_404(Note.objects.all(), pk=pk)
serializer = NoteSerializer(instance=note, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)

Django Rest API Pagination not limiting number of objects

i followed the documentation but i still get the full list of objects not limited
views.py
from rest_framework.pagination import (LimitOffsetPagination,PageNumberPagination)
class PostView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
pagination_class = PageNumberPagination
def list(self, request, *args, **kwargs):
self.object_list = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(self.object_list, many=True)
return Response(serializer.data)
settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2
}
By implementing the list method yourself, the pagination is no longer applied. Indeed, the list method for a ListAPIView is implemented as [GitHub]:
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)
But you thus do not need to implement the list method yourself. Your view can look like:
from rest_framework.pagination import (LimitOffsetPagination,PageNumberPagination)
class PostView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
pagination_class = PageNumberPagination
# no list method

Django Rest Framework (Rest API): 'function' object has no attribute 'as_view'

I am trying to generate class based view by using Django Rest framework. customer_details is a django app name. There is an error when I am trying to call that view in urls.py is:
\customer_details\urls.py", line 15, in path('ca_number/',views.CustomerDetailView.as_view()), AttributeError: 'function' object has no attribute 'as_view'
Here is some code:
customer_details/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import CustomerDetailModel
from .serializer import CustomerDetailSerializer
class CustomerDetailView(APIView):
def get(self, request, ca_number):#get all
if request.user.has_perm('customer_details.view_customerdetail'):
data = CustomerDetailModel.get_object(ca_number)
serializer = CustomerDetailSerializer(data)
return Response(serializer.data)
else:
return Response('Denied_msg', status=status.HTTP_403_FORBIDDEN)
def get(self, request, ca_number, format=None):#get single customer
try:
return CustomerDetailModel.objects.get(pk=ca_number)
except CustomerDetailModel.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def post(self, request, format=None):
serializer = CustomerDetailSerializer(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 put(self, request, pk, format=None):
try:
data = self.get_object(pk)
serializer = CustomerDetailSerializer(data, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except CustomerDetailModel.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
def delete(self, request, pk, format=None):
try:
data = self.get_object(pk)
data.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except CustomerDetailModel.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
customer_details/urls.py:
from django.contrib import admin
from django.urls import path
from . import views
from .views import CustomerDetailView
urlpatterns = [
path('ca_number/',views.CustomerDetailView.as_view()),
]

User specific Serializers in Django Rest Framework

I am creating Serializers in my DRF and so far it's working good the problem is that it is showing data of all the users
serializers.py
from rest_framework import serializers
from .models import Quiz
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Quiz
fields = ('foo', 'bar')
How do I make my Serializers User Specific such that it only returns the data of the user who is using the app?
Views.py
class TodoView(viewsets.ModelViewSet):
serializer_class = TodoSerializer
queryset = Quiz.objects.all()
User specific filtering has nothing to do with serializers. Serializers are used to convert complex python objects to/from native python datatypes that can be rendered in JSON/XML etc. It is convenient to do your filtering in your view. Here is an example by using mixins:
# views.py
from .models import Quiz
from .serializers import TodoSerializer
from rest_framework import mixins, viewsets
from rest_framework.response import Response
class TodoListViewSet(viewsets.GenericViewSet, mixins.ListModelMixin):
queryset = models.Quiz.objects.all()
serializer_class = TodoSerializer
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# filter your todos here
queryset = queryset.filter(user=request.user)
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)

DRF: Pagination without queryset

I am trying to make use of Django Rest Framework's pagination mechanisms in my case without success.
class TransactionView(viewsets.ViewSet):
serializer_class = TransactionSerializer
def list(self, request):
# fetching data from external API...
serializer = self.serializer_class(data=list_of_json, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
class TransactionSerializer(serializers.Serializer):
# Serializer (transaction's) fields ...
def create(self, validated_data):
return APITransaction(**validated_data)
class APITransaction(object):
def __init__(self, arg1, arg2, ...):
self.arg1 = arg1
...
The problem is that registering the pagination_class (like I have done for the rest of my resources which are represented by Models), doesn't work since the data are created/fetched on the fly, thus I don't have a Model/queryset.
Any ideas on how I could use DRF's pagination mechanism?
Here's the class I wound up creating and using locally for this sort of thing. (Thanks to stelios above for the initial clues.) Of course the contents of "data" must be JSONable.
from typing import List, Any
from collections import OrderedDict
from django.core.paginator import Paginator
from django.http.response import JsonResponse
from rest_framework.request import Request
class ListPaginator:
def __init__(self, request: Request):
# Hidden HtmlRequest properties/methods found in Request.
self._url_scheme = request.scheme
self._host = request.get_host()
self._path_info = request.path_info
def paginate_list(self, data: List[Any], page_size: int, page_number: int) -> JsonResponse:
paginator = Paginator(data, page_size)
page = paginator.page(page_number)
previous_url = None
next_url = None
if self._host and self._path_info:
if page.has_previous():
previous_url = '{}://{}{}?limit={}&page={}'.format(self._url_scheme, self._host, self._path_info, page_size, page.previous_page_number())
if page.has_next():
next_url = '{}://{}{}?limit={}&page={}'.format(self._url_scheme, self._host, self._path_info, page_size, page.next_page_number())
response_dict = OrderedDict([
('count', len(data)),
('next', next_url),
('previous', previous_url),
('results', page.object_list)
])
return JsonResponse(response_dict, status=200, safe=False)
You can't reuse existing DRF's pagination because they are supposed to work with queryset.
However, you may roll your own class by inheriting BasePagination though I haven't done myself.

Resources