Ordering (sorting) from URL in django-rest-framework-filters with ComplexFilterBackend - django-rest-framework

Are there ability to Ordering result with djangorestframework-filters ComplexFilterBackend from URL?
DRF OrderingFilter is not worked with standart examples for djangorestframework-filters v.1.0.0.dev2.
My code with default order_by in query_set:
Filter class:
from models import Template
class TemplateFilter(filters.FilterSet):
class Meta:
model = Template
fields = {
'id': '__all__',
'status': '__all__',
'name' : '__all__',
'parent_id' : '__all__',
}
View:
from serializers import TemplateListSerializer
from models import Template
from filters import TemplateFilter
class TemplateListView(ListCreateAPIView):
filter_class = TemplateFilter
def get(self, request, *args, **kwargs):
self.queryset = Template.objects.all().order_by('-created')
self.serializer_class = TemplateListSerializer
return self.list(request, *args, **kwargs)
How I can to change this code for ordering (sort) response from URL Request?
I want to see record with parent_id=guid first.
My input url for Django:
GET /api/templates/?filters=(parent_id__isnull%3DTrue)%7C(parent_id%3Dguid)%26(ordering%3Dparent_id)&page=1
Decoded:
/api/templates/?filters=(parent_id__isnull=True)|(parent_id=guid)&(ordering=parent_id)&page=1

Answer - mandatory set two backend filters:
First - for search, ComplexFilterBackend
Second - for ordering, OrderingFilter
from serializers import TemplateListSerializer
from models import Template
from filters import TemplateFilter
from rest_framework import filters
from rest_framework_filters.backends import ComplexFilterBackend
class TemplateListView(ListCreateAPIView):
filter_class = TemplateFilter
def get(self, request, *args, **kwargs):
self.queryset = Template.objects.all()
self.serializer_class = TemplateListSerializer
self.filter_backends = [ComplexFilterBackend, filters.OrderingFilter]
self.ordering_fields = ['parent_id', 'name']
self.ordering = ['parent_id']
return self.list(request, *args, **kwargs)

Related

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()),
]

How to update records in a Postgres table with Django rest framework

I have basic django app that returns data from Postgres tables in an AWS RDS instance.
I have a few endpoint which relate to few tables in the RDS.
What I want to do is update records in table. If the record exists it should be updated, if it does not exist then nothing should happen Orit should throw an error.
This is my models.py file -
from django.db import models
class Campaigns(models.Model):
id_campaign = models.CharField(max_length=250, blank=True, null=True)
status = models.CharField(max_length=250, blank=True, null=True)
id_taste_cluster = models.CharField(max_length=250, blank=True, null=True)
I want to update the status field in this table where status = ' '.
This is my serialiser file -
from rest_framework import serializers
from .models import Campaigns
class Campaigns_1_Serializer(serializers.ModelSerializer):
class Meta:
model = Campaigns
fields = ('id_campaign', 'status', 'id_taste_cluster')
This is my views file -
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import generics
from .models import Campaigns
from .serializers import Campaigns_1_Serializer
class UpdateView(viewsets.ModelViewSet):
def update(self, request, *args, **kwargs):
data = request.DATA
queryset = Campaigns.objects.filter(status='')
serializer = Campaigns_1_Serializer(queryset, data=data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
I want to give the users the option to update only those campaigns for which the status is ' '(blank).
How can I do that ?
You need to change your update method :
#your imports
from rest_framework import serializers
class YourModelViewset(ModelViewSet):
#your code
def update(self, request, *args, **kwargs):
instance = self.get_object()
# checks if the object staus is empty
If object.status == "" or object.status is None :
raise serializers.ValidationError("your error message")
return super(YourModelViewset, self).update(request, *args, **kwargs)

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)

How to create view from External http request json and Internal Database using Django Rest Framework

I need to combine external json using request and Internal Database, But the condition is when someone call API we need to get empidlong from Model for call external API from specific URL, Then external API will return JSON and i need to merge this JSON with my json that create by Django REST API Framework
Here is my code
models.py :
from django.db import models
import requests
from django.core.files import File
from urllib import request
import os
# Create your models here.
class getData(models.Model):
company = models.CharField(max_length=150)
description = models.CharField(max_length=150)
period = models.CharField(max_length=150)
plate_no = models.CharField(max_length=150, primary_key=True)
project_code = models.CharField(max_length=150)
costcenter = models.CharField(max_length=150)
empidlong = models.CharField(max_length=150)
class Meta:
db_table = 'car_information'
serializers.py
from rest_framework import serializers
from .models import getData
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = getData
fields = "__all__"
views.py
from django.shortcuts import render
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
serializer = CarSerializer(queryset, many=True)
data = serializer.data
for a in data:
empid= a['empidlong']
r = requests.get('http://192.168.10.32/Employees/'+empid)
def get_queryset(self):
queryset = getData.objects.all()
emp = self.request.query_params.get('emp', None)
if emp is not None:
queryset = queryset.filter(empidlong=emp)
return queryset
I have no idea how to do it. I stuck this for week.
Thank in advance.
Where are you expecting the json from? if from a user, you can access the json from the request. Then you can use it in your orm query. You CarViewSet seem to be doing way more than it should be. What is your goal exactly?

Django Filter Backend not working in restful api in django

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)

Resources