Everything is imported, it might not be working because of get_queryset function, but i am not sure.
class ShowStats(ListAPIView):
serializer_class = StatsSerializer
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
ordering_fields = ('date', 'views', 'clicks', 'cost', 'cpc', 'cpm')
ordering = ('views',)
def get_queryset(self):
return Stats.objects.filter(date__range=[self.kwargs['from'], self.kwargs['to']])
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
response_list = serializer.data
for i in range(len(response_list)):
response_list[i]['cpc'] = response_list[i]['cost'] / response_list[i]['clicks']
response_list[i]['cpm'] = response_list[i]['cost'] / response_list[i]['views'] * 1000
return Response(data=response_list)
Change
queryset = self.get_queryset()
to
queryset = self.filter_queryset(self.get_queryset())
to apply filtering and/or ordering.
Here's what DRF's ListModelMixin looks like (for inspiration).
class ListModelMixin:
"""
List a queryset.
"""
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)
Related
Right now I'm overriding the whole retrieve and update function. I want to override only that part, it does not ask for the pk value. Thanks
View.py
class EmployeeView(generics.RetrieveUpdateAPIView):
permission_classes = [EmployeePermission]
serializer_class = EmployeeSerializers
def retrieve(self, request, *args, **kwargs):
employee = Employee.objects.get(user=self.request.user)
serializer = EmployeeSerializers(employee)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
employee_user = Employee.objects.get(user=self.request.user)
serializer = EmployeeSerializers(employee_user, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)strong text
urls.py
path('viewEmployee/', views.EmployeeView.as_view()),
what you need is to override the get_queryset method, and write your custom filtering, then django will take care of otherthings.
class EmployeeView(generics.RetrieveUpdateAPIView):
queryset = Employee.objects.all()
permission_classes = [EmployeePermission]
serializer_class = EmployeeSerializers
def get_queryset(self):
return super().get_queryset().filter(
user=self.request.user
)
I want to get query list with one key more values. For example,
http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_mother=master&hardware_model_mother=MasterModel1&hardware_model_child=SlaveModel1
Then i can get query list of device_type=1,hardware_model_child=SlaveModel1,hardware_model_mother=master
and device_type=1,hardware_model_child=SlaveModel1,hardware_model_mother=MasterModel1.
I need a list of fields that's why i didn't use the function in_bulk().
I found some filters in django-filter's doc, here's the link:
https://django-filter.readthedocs.io/en/latest/ref/filters.html
I choose MultipleChoiceFilter, it will use OR, that's what i wanted.
Here's my filter's code:
from django_filters import FilterSet, MultipleChoiceFilter
from Device_set.views.DeviceModelFilter import DeviceModelFilter
from .head import *
# one key for multiple values
class DeviceModelFilter(FilterSet):
MOTHER_CHOICES, CHILD_CHOICES = DeviceModelFilter().MyChoices()
hardware_model_mother = MultipleChoiceFilter(choices=MOTHER_CHOICES)
hardware_model_child = MultipleChoiceFilter(choices=CHILD_CHOICES)
class Meta:
model = device_model
fields = ['hardware_model_mother', 'hardware_model_child']
and my ListAPIView:
class DeviceModelListView(ListAPIView):
permission_classes = [Developer | IOTWatch | IsAdminUser]
serializer_class = DeviceModelListSerializer
queryset = device_model.objects.all()
filter_backends = (SearchFilter, DjangoFilterBackend,)
filter_class = DeviceModelFilter
search_fields = ('id', 'name')
filterset_fields = ('hardware_model_mother', 'hardware_model_child')
def list(self, request, *args, **kwargs):
dtype = self.request.query_params.get('device_type')
if dtype is not None:
queryset = self.queryset.filter(device_type__icontains=dtype)
else:
queryset = self.queryset
queryset = self.filter_queryset(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)
def get(self, request, *args, **kwargs):
return Response(Return_msg(self.list(request)))
when url is http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_mother=master&hardware_model_mother=MasterModel1
The result is right:
right response
However, when url is http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_child=SlaveModel1
It's wrong:
false
Traceback:
Traceback
It cost me about one day to solve this problem, could you please tell me how to fix it, or anther way to implement it?
I have a DRF class with a single method get_queryset(). I would like to add caching to the serialized queryset by intercepting the request before get_queryset gets called, but after custom middleware/authentication has been run. Here is a trivial example of what I'm after:
class FooList(generics.ListCreateAPIView)
permission_classes = (permissions.IsAuthenticated,)
serializer_class = FooSerializer
def intercept_for_caching(self):
user = self.request.meta_data['user']
cached_data = cache.get(f'FooStuff:{user.pk}')
if cached_data:
return Response(cached_data)
else:
new_data = ? # retrieve serialized queryset
cache.set(f'FooStuff:{user.pk}', new_data)
return Response(new_data)
def get_queryset(self):
user = self.request.meta_data['user']
return Foo.objects.filter(user=user)
Are there any methods I can hook into?
I am aware that cache_page is designed for this use case (https://www.django-rest-framework.org/api-guide/caching/), but I haven't been able to get it to work with our custom middeleware.
The source code has a function list:
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)
I was able to cache the queryset by overriding list:
def list(self, request, *args, **kwargs):
user = self.request.user
cache = caches['redis']
cache_key = f'my_cache:{user.pk}'
cached_results = cache.get(cache_key)
if cached_results:
return Response(cached_results)
else:
queryset = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(queryset, many=True)
cache.set(cache_key, serializer.data)
return Response(serializer.data)
I am trying to write API endpoint which will take ?groupby=[field] as an argument and will pass it to CSV renderer. Problem is that my code looks little bit hacky. Are there better way to do this? Using filters maybe?
class MyCSVRenderer(CSVRenderer):
header = ['logged_at', 'chain_key', 'buyer', 'seller', 'amount']
class ChainsViewset(viewsets.ModelViewSet):
serializer_class = ledger_serializers.ChainsSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = ChainFilter
def get_queryset(self):
return ledger_models.ChainLink.objects.all()
#renderer_classes((MyCSVRenderer,))
def list(self, request, *args, **kwargs):
groupby = self.request.query_params.get('groupby', None)
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)
if groupby:
queryset = queryset.values(groupby).annotate(amount=Sum('amount'))
if queryset:
MyCSVRenderer.header = queryset[0].keys()
serializer = self.get_serializer(queryset, many=True, fields=tuple(queryset[0].keys()))
else:
MyCSVRenderer.header = ['logged_at', 'chain_key', 'buyer', 'seller', 'amount']
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
renderer_classes = (BrowsableAPIRenderer, JSONRenderer, CSVRenderer)
My settings:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2
}
My pagination Class:
from rest_framework.pagination import PageNumberPagination
class CustomNumberPagination(PageNumberPagination):
page_size = 5
My Testing View Class:
from rest_framework.pagination import PageNumberPagination
from .pagination import CustomNumberPagination
class Testing(generics.GenericAPIView):
queryset = Testing.objects.all()
serializer_class = TestingSerializer
pagination_class = CustomNumberPagination
def get(self, request):
print PageNumberPagination.page_size # 2
print self.pagination_class.page_size # 5
queryset = self.get_queryset()
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
I can print out the page_size of PageNumberPagination and CustomNumberPagination in my console correctly.
However, passing page as a parameter doesn't have any effect. I couldn't get either global paginations or pagination_class in each view to work. I am not sure what went wrong, but it seems that most people did the same thing and just worked for them. I'd appreciate any suggestions for me.
Updates
Just got some inspirations from my selected answer below.
Since I will have to write a lot of customizations in my overwritten get(), I just updated my get():
from rest_framework.pagination import PageNumberPagination
from .pagination import CustomNumberPagination
class Testing(generics.GenericAPIView):
queryset = Testing.objects.all()
serializer_class = TestingSerializer
pagination_class = CustomNumberPagination
def get(self, request):
queryset = self.get_queryset()
page = self.request.query_params.get('page')
if page is not None:
paginate_queryset = self.paginate_queryset(queryset)
serializer = self.serializer_class(paginate_queryset, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
Take a look how it is done in drf itself:
class ListModelMixin(object):
"""
List a queryset.
"""
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)
Hope that this will help you - as is self-explanatory;
You used GenericAPIView - and overwrite the get - you should use the get_paginated_response method to achieve pagination.
Happy coding.