How to get queryset value after search using Django Rest Framework - django

I using Django Rest Framework and I need queryset that filtered by using Search, This queryset send to CarSerializer. empidlong from CarSerializer will have empid for Requests JSON from specific url(192.168.10.3).
from django.shortcuts import render
# Create your views here.
from rest_framework import viewsets, filters
from .models import getData
from .serializers import CarSerializer
import requests
class CarViewSet(viewsets.ModelViewSet):
queryset = getData.objects.all()
serializer_class = CarSerializer
filter_backends = (filters.SearchFilter,)
#search_fields = ('plate_no')
__basic_fields = ('plate_no',)
search_fields = __basic_fields
def get_search_fields(self, view, request):
if request.query_params.get('khai'):
return ('plate_no',)
x= super(CarViewSet, self).get_search_fields(view, request)
serializer = CarSerializer(x)
data = serializer.data
for a in data:
empid= a['empidlong']
requests.get('http://192.168.10.3/GetEmployees/'+empid +'/Y')
return x

Use Django filter it will be ease with viewsets
views.py
from rest_framework.filters import SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
class CarViewSet(viewsets.ModelViewSet):
filter_class = getDataFilter
filter_backends = (SearchFilter, DjangoFilterBackend)
queryset = getData.objects.all()
serializer_class = CarSerializer
create a file filters.py, there you specify the fields to filter with all conditions,
import django_filters
from .models import getData
class getDataFilter(django_filters.FilterSet):
class Meta:
model = User
fields = {
'first_name': ['iexact', 'icontains', 'istartswith'],
'last_name': ['iexact', 'icontains', 'istartswith'],
}
urls format is like this,
https://localhost:8000/xxxx/?last_name__iexact=xx

Related

drf_yasg only renders filterset parameters on list view

I have defined a filterset for a DRF ViewSet. drf_yasg correctly renders all the filterset fields as parameters in Swagger for the list endpoint, but not for any other endpoints.
Any idea why?
views.py:
from rest_framework import mixins, viewsets
from django_filters import rest_framework as filters
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from my_app.models import MyModel
from my_app.serializers import MySerializer
class MyFilterSet(filters.FilterSet):
class Meta:
model = MyModel
fields = {
"status",
}
class MyViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
viewsets.GenericViewSet,
):
filter_backends = (filters.DjangoFilterBackend, )
filterset_class = MyFilterSet
queryset = MyModel.objects.all()
serializer_class = MySerializer
List is only place where filters are actually used (see here)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
...
There is nothing to filter on create/update/delete since there are no multiple results. Same goes for retrieve, you are fetching an object by id, so filtering single result doesn't make any sense.

Django rest serializer can't handle object - TypeError: Object of type Hero is not JSON serializable

I have the below simple rest api set up in Django. Calling the url http://127.0.0.1:8000/listheros/ returns
TypeError: Object of type Hero is not JSON serializable
for a reason I can't seem to figure out.
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import HeroSerializer
from .models import Hero
class ListHeros(APIView):
def get(self, request, format=None):
"""
Return a list of all users.
"""
queryset = Hero.objects.all().order_by('name')
serializer_class = HeroSerializer
print('get')
return Response(queryset)
# urls.py
from django.urls import include, path
from applications.api.views import ListHeros
urlpatterns = [
path('listheros/', ListHeros.as_view()),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
# serializers.py
from rest_framework import serializers
from .models import Hero
class HeroSerializer(serializers.ModelSerializer):
class Meta:
model = Hero
fields = ('name', 'alias')
# models.py
from django.db import models
class Hero(models.Model):
name = models.CharField(max_length=60)
alias = models.CharField(max_length=60)
def __str__(self):
return self.name
You don't serialize your queryset of heroes. Your ListHeroes api view should looks like below:
class ListHeros(APIView):
def get(self, request, format=None):
"""
Return a list of all users.
"""
queryset = Hero.objects.all().order_by('name')
serializer = HeroSerializer(queryset, many=True)
return Response(serializer.data)
You can also use generics ListApiView instead of APIView:
from rest_framework.generics import ListAPIView
class ListHeros(ListAPIView):
queryset = Hero.objects.all().order_by('name')
serializer_class = HeroSerializer

How I can show http 404 with djangofilterbackend?

django rest framework is showing http 202 ok when I set a wrong value and I want to show http 404 on the api django rest framework, when set a wrong value in djangofilterbackend but I don't know how to implement it.
my views.py:
from rest_framework import viewsets
from .models import Producto
from .serializers import ProductoSerializer
from django_filters.rest_framework import DjangoFilterBackend
class ProductoViewSet(viewsets.ModelViewSet):
filter_backends = [DjangoFilterBackend]
filterset_fields = ['Codigo_Producto']
queryset = Producto.objects.all()
serializer_class = ProductoSerializer
my serializers.py:
from .models import Producto
from rest_framework import serializers, viewsets
class ProductoSerializer(serializers.ModelSerializer):
Nombre_Producto = serializers.SerializerMethodField
class Meta:
model = Producto
fields = [
'id',
'Nombre_Producto',
'Codigo_Producto',
'Precio_sugerido',
'stock',
]
def get_Producto_name(self,obj:Producto):
return obj.Producto.get_full_name()
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
from rest_framework import routers
from GestionadorApp.views import ProductoViewSet
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register('Producto', ProductoViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('api/', include(router.urls)),
path('admin/', admin.site.urls),
]
The way I found is overriding the filter backend to ensure that the parameters are what I want else raise a error Http404.
to show a solution I had to take part of code from Django Filter Backend
from rest_framework import filters
from django.http import Http404
class ObjektFilterBackend(filters.BaseFilterBackend):
allowed_fields = ['username', 'email']
def filter_queryset(self, request, queryset, view):
flt = {}
for param in request.query_params:
#put your logic here
if request.query_params[param] is None:
raise Http404
for fld in self.allowed_fields:
if param.startswith(fld):
flt[param] = request.query_params[param]
return queryset.filter(**flt)
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [ObjektFilterBackend]
search_fields = ['username', 'email']
In another hand you may override the get_queryset method to ensure data too.
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [DjangoFilterBackend]
search_fields = ['username', 'email']
def get_queryset(self):
username = self.request.query_params.get('username', None)
if username is None:
raise http404
return self.queryset
django rest framework filtering

Pagination In Django With Postman

I am using Django version 2.1 and I am testing my project using Postman.
This is my views.py file :-
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
from rest_framework.permissions import AllowAny
# Add + List
# Retrieve Update Destroy
# List: Pagination
class ShowAddaView(ListCreateAPIView):
from .serializers import AddAddaSerializer
from .models import Adda
permission_classes = (AllowAny, )
serializer_class = AddAddaSerializer
queryset = Adda.objects.all()
class RetrieveAddaView(RetrieveUpdateDestroyAPIView):
from .serializers import AddAddaSerializer
from .models import Adda
permission_classes = (AllowAny,)
serializer_class = AddAddaSerializer
queryset = Adda.objects.all()
I am applying GET and POST method in postman. My serializer file looks like this :
class AddAddaSerializer(serializers.ModelSerializer):
class Meta:
from .models import Adda
model = Adda
fields = '__all__'
class UpdateAddaSerializer(serializers.ModelSerializer):
mobile = serializers.CharField(required=False)
class Meta:
from .models import Adda
model = Adda
fields = '__all__'
Now I need to access my data using the GET method in Postman with pagination.
Can anyone tell me what changes I need to do to achieve it.
Add this settings to your settings.py file,
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10 # Change this value according to your need
}
or You could add pagination class in View level by pagination_class as
from rest_framework.pagination import PageNumberPagination
class ShowAddaView(ListCreateAPIView):
# your code
pagination_class = PageNumberPagination
class RetrieveAddaView(RetrieveUpdateDestroyAPIView):
# your code
pagination_class = PageNumberPagination
For more details, refer Pagination in DRF

How to filter query with comma separated parameters in Django (DRF Filtering)

Please my question is not a duplicated, i have already search for it but with no consistent result.
So i'm building a restfull api with djangorestframework
I want this query like
http://localhost:8000/api/products/?category_name_fr=shirt,shoes
to find all products where category_name_fr contains shirt or shoes
In order to do this after some googling i wrote a custom django filter class (MultiValueCharFilter) but the filter does not actually behave like i want.
When i make a query like the above, it returns me all the product in ProductTable. But when i make a query like the bellow, the filtering is done properly
http://localhost:8000/api/products/?category_name_fr=shirt
Here is the source code of my filters.py file, the product class is ProductList
from django_filters import rest_framework as filters
from .models import ProductList
from django_filters import Filter
from django_filters.fields import Lookup
class MultiValueCharFilter(filters.BaseCSVFilter, filters.CharFilter):
def filter(self, qs, value):
# value is either a list or an 'empty' value
values = value or []
print(values)
for value in values:
qs = super(MultiValueCharFilter, self).filter(qs, value) | qs
return qs
class ProductListFilter(filters.FilterSet):
min_price = filters.NumberFilter(name="price", lookup_expr='gte')
max_price = filters.NumberFilter(name="price", lookup_expr='lte')
category_name_fr = MultiValueCharFilter(name="category_name_fr", lookup_expr='icontains')
category_name_en = MultiValueCharFilter(name="category_name_en", lookup_expr='icontains')
collection_name_fr = MultiValueCharFilter(name="collection_name_fr", lookup_expr='icontains')
collection_name_en = MultiValueCharFilter(name="collection_name_en", lookup_expr='icontains')
name_en = MultiValueCharFilter(name="name_en", lookup_expr='icontains')
name_fr = MultiValueCharFilter(name="name_fr", lookup_expr='icontains')
class Meta:
model = ProductList
fields = ['sale', 'sold', 'min_price', 'max_price', 'category_name_fr', 'name_en', 'name_fr',
'category_name_en', 'collection_name_fr', 'collection_name_en']
For more infos this is the code of the view ListAPIView
from rest_framework import viewsets, generics, filters as rf_filters
from ..models import Product, Collection, ProductList
from ..serializers import ProductSerializer, CollectionSerializer, ProductListSerializer
from django_filters import rest_framework as filters
from ..filters import ProductFilter, ProductListFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from rest_framework.response import Response
class StandardResultsSetPagination(PageNumberPagination):
page_size = 4
page_size_query_param = 'page_size'
max_page_size = 15
class ProductList(generics.ListAPIView):
queryset = ProductList.objects.all()
serializer_class = ProductListSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = ProductListFilter
serializer_class = ProductListSerializer
ordering_fields = ('price', 'created_at')
pagination_class = StandardResultsSetPagination
You need to write a custom filter & filterset class like below
filterset.py
from django_filters import Filter, FilterSet
from django_filters.constants import EMPTY_VALUES
class ListFilter(filters.Filter):
def filter(self, qs, value):
if value in EMPTY_VALUES:
return qs
value_list = value.split(",")
qs = super().filter(qs, value_list)
return qs
class ProductListFilter(filters.FilterSet):
category_name_fr = ListFilter(field_name="category_name_fr", lookup_expr="in")
# other fields
views.py
from django_filters.rest_framework import DjangoFilterBackend
class ProductList(generics.ListAPIView):
filter_backends = (DjangoFilterBackend,)
filterset_class = ProductListFilter
# other attr settings
Ref: https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html#adding-a-filterset-with-filterset-class
Views.py
class ApplicationListAPIView(generics.ListAPIView):
.......
filter_backends = (DjangoFilterBackend,)
filter_class = ApplicationFilters
......etc
filters.py
from django_filters import FilterSet
from .models import Application
class ApplicationFilters(FilterSet):
class Meta:
model = Application
fields = {
'evaluation_type':["in"],
'purpose':["in"],
'board':["in"]
}
Now,url should be like:
http://127.0.0.1:8000/api/application?purpose__in=1,2,3
http://127.0.0.1:8000/api/application?evaluation_type__in=type1,type2
http://127.0.0.1:8000/api/application?board__in=board1,board2,board3,board4