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
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.
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
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
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
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