How to modify get_queryset result value - django

I am trying to modify my get_queryset result
Here is my my filter, view and serializer
view.py
class AccountDetailFilter(filters.FilterSet):
product_key = filters.CharFilter(name='product__product_name')
account_name = filters.AllValuesFilter(name='account__account_key')
service_provider_name = filters.CharFilter(name='product__service_provider__service_provider_name', )
allocation_key = filters.CharFilter(name='account__account_allocation__allocation_key')
class Meta:
model = BillingLine
fields = ('product_key', 'account_name', 'service_provider_name', 'allocation_key')
class AccountDetailList(generics.ListAPIView):
serializer_class = BillingSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = AccountDetailFilter
def get_queryset(self):
now = datetime.datetime.now()
start_date = self.kwargs.get('start_date_time', now)
end_date = self.kwargs.get('end_date_time', now)
serializer = BillingSerializer(data={'start_date': start_date, 'end_date': end_date})
serializer.is_valid(raise_exception=True)
queryset = BillingLine.objects.select_related().filter(start_date__gte=start_date, end_date__lte=end_date)
queryset = queryset.order_by('-id')
print(queryset.count())
return queryset
Serializers.py
class BillingSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
start_date = serializers.DateTimeField()
end_date = serializers.DateTimeField()
account_key = serializers.CharField(source='account_id',required=False)
product_key = serializers.CharField(source='product_id',required=False)
total_amount = serializers.FloatField(required=False)
After retrieving the result(ie get_queryset), I need to modify/add the data in the result . Is there any way to do this .
Also can we get the other field values to serializers from the result queryset. Because the queryset = BillingLine.objects.select_related().filter(start_date__gte=start_date, end_date__lte=end_date) is returning the almost all the data (sepecifally product name which is from products table)

Overriding get_queryset() method would serve your purpose perfectly.
For Example:
in your views.py :
class AccountDetailList(generics.ListAPIView):
serializer_class = BillingSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = AccountDetailFilter
def get_queryset(self):
qs = YourModel.objects.filter(**filter_parameter)
return qs
def list(self):
try:
queryset = self.get_queryset()
serialize_value = YourSerializers(queryset,many=True,context={'request': self.request}).data
#Here in "serialize_value" you can append your data as much as you wish
return_val = {
'modified_serialize_value': serialize_value
}
return Response(return_val, status=status.HTTP_200_OK, content_type='application/json')
except Exception as E:
return Response({'error': str(E)}, status=status.HTTP_408_REQUEST_TIMEOUT, content_type='application/json')
I hope this will help.

Related

How to pass a query parameter to SerializerMethodField in django rest framework?

I want to filter out some instance based on the query parameter I get in the GET call.
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True)
class Meta:
model = Revision
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
# filter this on the incoming data from the GET call
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
This is my serializer and I will be passing one date and based on that date I want to filter my serializermethodfield. How can I achieve this?
You can pass parameters to a Serializer using its context:
# views.py
class RevisionView(GenericAPIView):
serializer_class = RevisionSerializer
def get_serializer_context(self):
return {'revision_id': self.request.GET.get('revision_id')}
# serializers.py
class RevisionSerializer(serializers.ModelSerializer):
def get_batch_config(self, obj):
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=self.context.get('revision_id'))
Thanks to #ThomasGth. I did it like this.
SERIALIZER
class RevisionSerializer(serializers.ModelSerializer):
slot_info = serializers.SerializerMethodField(required=False, read_only=True)
batch_config = serializers.SerializerMethodField(required=False, read_only=True,
)
class Meta:
model = Revision
# fields = '__all__'
fields = ['id', 'status', 'revision_id', 'instructor', 'number_of_classes', 'start_date',
'slot', 'slot_info', 'tinyurl', 'zoom_link', 'batch_config']
read_only_fields = ['revision_id']
def get_batch_config(self, obj):
calendar_date = self.context.get('calendar_date')
related_batches = CompensationClass.objects.select_related('style', 'instructor').filter(
compensation_class_id=obj.revision_id)
if calendar_date:
related_batches = related_batches.filter(calendar_date)
batch_config_values = related_batches.values('batch_id', 'age_group', 'level', 'course_version', 'style__name',
'class_number')
return batch_config_values
VIEWSET
class RevisionViewset(viewsets.ModelViewSet):
queryset = Revision.objects.all().order_by('-modified_at').select_related('instructor', 'slot')
serializer_class = RevisionSerializer
pagination_class = LimitOffsetPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_class = RevisionFilter
def get_serializer_context(self):
context = {'request': self.request}
calendar_date = self.request.GET.get('calendar_date')
if calendar_date:
context['calendar_date'] = calendar_date
return context

my pagination seems not to be working - DRF problem

I am trying to create an endpoint that returns a list of posts. I want lets say 2 posts per page (for testing only! I know its not that big of a number to cause problem!).
here is my
views.py
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = pagination.CustomPagination
def list(self, request):
data = request.data
uid = data['uid']
context = {"user": uid}
blogs = Posts.objects.all()
serializer = PostSerializer(blogs, many= True, context= context)
return Response(serializer.data)
here is my
serializers.py
class PostSerializer(ModelSerializer):
isLiked = serializers.SerializerMethodField(method_name='check_react')
totalLikes = serializers.SerializerMethodField(method_name='get_likes')
totalComments = serializers.SerializerMethodField(method_name='get_comments')
def check_react(self, post):
userObj = Users.objects.get(userID = self.context['user'])
#print(type(userObj))
if Likes.objects.filter(postID = post, userID = userObj).exists():
isLiked = Likes.objects.get(postID = post, userID = userObj)
likeObj = LikeSerializer(isLiked)
#print('isLiked: ', likeObj.data['isLiked'])
return (likeObj.data['isLiked'])
return(False)
#print(isLiked)
def get_likes(self, post):
count = Likes.objects.filter(postID = post).count()
return count
def get_comments(self, post):
count = PostsComments.objects.filter(postID = post).count()
return count
class Meta:
model = Posts
fields = '__all__'
and, here is my
pagination.py,
from rest_framework import pagination
class CustomPagination(pagination.PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size'
max_page_size = 3
page_query_param = 'p'
I am importing this class on views.py and it works as expected when I try to retrieve a list of users via userMVS
class userMVS(ModelViewSet):
queryset = Users.objects.all()
serializer_class = UserSerializer
pagination_class = pagination.CustomPagination
You must write your list function of views as -
def list(self, request, *args, **kwargs):
queryset = Posts.objects.all()
paginatedResult = self.paginate_queryset(queryset)
serializer = self.get_serializer(paginatedResult, many=True)
return Response(serializer.data)
Edits -
Suppose this is my pagination class -
class CustomPagination(PageNumberPagination):
page_size = 8
page_query_param = "pageNumber"
and used in this way at class level and mentioned above at list function -
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = CustomPagination
then this is the url that should work
http://localhost:8000/urlofpostviewset/?pageNumber=passThePageNumber
Do read from the documents all the properties you use at CustomPagination class.

How to sort and search a time field in 12 format? DRF

I have two fields of type time in postgresql, which saves these values ​​in 24 format (03:30 PM would save 15:30:00).
How can I run a search with a time in format 12 and match it with its equivalent in format 24?
How can I order these fields in 12 format?
the fields are 'ho_inicio' and 'ho_fin'.
My Viewset (I override the list method to search regardless of accents):
class HorasEscolaresViewSet(ListModelPagination, viewsets.ModelViewSet):
queryset = TbledcHora.objects.all()
serializer_class = HorasEscolaresSerializer
filter_backends = [DjangoFilterBackend, AliasedOrderingFilter]
filterset_class = HorasEscolaresFilter
search_fields = ['id_nivel_academico__nb_nivel_academico', 'nu_hora']
filterset_fields = ['id_nivel_academico', 'in_status']
ordering_fields=('id_nivel_academico', 'nu_hora', 'ho_inicio', 'ho_fin')
ordering= 'id_nivel_academico'
renderer_classes = (EmberJSONRenderer, )
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if "search" in request.GET:
if request.GET['search'] != '':
q_list = []
q_list.append(Q(id_nivel_academico__nb_nivel_academico__unaccent__icontains=request.GET['search']))
queryset = queryset.filter(reduce(operator.or_, q_list))
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)
My serializer:
class HorasEscolaresSerializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
ho_inicio = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
ho_fin = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
class Meta:
model = TbledcHora
fields = '__all__'
depth = 1

Filtering query in django with multiple params

Is it someway to filter querysets with multiple optional parameters in Django more efficiently?
For ex. I have product list and user can filter it by using multiple GET params. 6 params in this case. Thanks.
class ProductList(ListAPIView):
permission_classes = (IsAdminUser,)
serializer_class = ProductSerializer
def get_queryset(self):
queryset = Product.objects.order_by('-created_at')
category_id = self.request.GET.get('category_id')
color = self.request.GET.get('color')
size = self.request.GET.get('size')
status = self.request.GET.get('status')
date_from = self.request.GET.get('date_from')
date_to = self.request.GET.get('date_to')
if category_id:
queryset = queryset.filter(category_id=category_id)
if color:
queryset = queryset.filter(color=color)
if size:
queryset = queryset.filter(size=size)
if status:
queryset = queryset.filter(status=sistatusze)
if date_from:
queryset = queryset.filter(created_at__gte=date_from)
if date_to:
queryset = queryset.filter(created_at__lte=date_to)
return queryset
You can make a utility function that will not filter the conditions where the value is None:
def filter_if_not_none(qs, **kwargs):
return qs.filter(**{k: v for k, v in kwargs.items() if v is not None})
then we can use this utility as:
class ProductList(ListAPIView):
permission_classes = (IsAdminUser,)
serializer_class = ProblemSerializer
def get_queryset(self):
queryset = Product.objects.order_by('-created_at')
return filter_qs_if_not_none(
queryset,
category_id=self.request.GET.get('category_id')
color=self.request.GET.get('color')
size=self.request.GET.get('size')
status=self.request.GET.get('status')
created_at__gte=self.request.GET.get('date_from')
created_at__lte=self.request.GET.get('date_to')
)

Use Django Filters in ModelViewSet which return serializer data

I want to combine 2 models: City and Country in order to have a filter like this: http://localhost:8000/api/v1/geo/location-search/?name=Santa+Fe
I have a ModelViewSet which return serializer data like this:
class LocationSearchAPI(ModelViewSet):
queryset = City.objects.all().order_by('name')
permission_classes = [AllowAny]
serializer_class = CityListSerializer
filter_backends = (DjangoFilterBackend, SearchFilter)
filter_class = LocationFilter
def get_location_list(self, request):
city_qs = City.objects.all().order_by('name')
country_qs = Country.objects.all().order_by('name')
result_qs = list(chain(country_qs, city_qs))
sorted_list = sorted(result_qs, key=lambda instance: -instance.id)
results = list()
for item in sorted_list:
item_type = item.__class__.__name__.lower()
if isinstance(item, City):
serializer = CityLocaliaztionSrl(item)
if isinstance(item, Country):
serializer = CountryLocaliaztionSrl(item)
results.append({'type': item_type, 'data': serializer.data})
return Response(results, status=200)
and this Filter's not work:
class LocationFilter(FilterSet):
class Meta:
model = City
fields = ('type', 'data__name')
How can I use Django Filters in ModelViewSet which return serializer data, hope your guys help me.