I am trying to implement filtering and pagination in an rest api developed with Django and python. I need to choose when to use filtering, pagination, both or none of them in my endpoints. To do this, I have thought of combining a template pattern with a decorator pattern.
This is my designed solution, when ModelViewSet is an abstract class provided by Django Rest Framework, DummyViewSet is my endpoint, and FilteringViewSetDecorator and PaginationViewSetDecorator are my decorators.
This is my source code:
class CustomView(viewsets.ModelViewSet):
__metaclass__ = ABCMeta
@abstractmethod
def get_queryset(self, request, **kwargs):
pass
def serialize_queryset(self, queryset):
print("CustomView: _serialize_queryset")
serializer = self.get_serializer(queryset, many=True)
return JsonResponse(serializer.data, safe=False)
def list(self, request, **kwargs):
print("CustomView: list")
queryset = self.get_queryset(request, **kwargs)
return self.serialize_queryset(queryset)
class ViewSetDecorator(CustomView):
__metaclass__ = ABCMeta
def __init__(self, viewset):
print("ViewSetDecorator: __init__")
self._viewset = viewset
def get_queryset(self, request, **kwargs):
print("ViewSetDecorator: _get_queryset")
return self._viewset.get_queryset(request, **kwargs)
class FilteringViewSet(ViewSetDecorator):
@staticmethod
def __build_filters(params):
filters = []
for key, value in params.items():
if key != 'limit' and key != 'offset' and value is not None and value != '':
query_filter = {key: value}
filters.append(query_filter)
return filters
def get_queryset(self, request, **kwargs):
print("FilteringViewSet: _get_queryset")
queryset = super(FilteringViewSet, self).get_queryset(request, **kwargs)
filters = self.__build_filters(request.GET)
for query_filter in filters:
queryset = queryset.filter(**query_filter)
return queryset
class PaginationViewSet(ViewSetDecorator):
def get_queryset(self, request, **kwargs):
print("PaginationViewSet: _get_queryset")
queryset = super(PaginationViewSet, self).get_queryset(request, **kwargs)
limited = request.query_params.get('limit')
if limited is not None:
return self.paginate_queryset(queryset)
return queryset
def serialize_queryset(self, queryset):
print("PaginationViewSet: _serialize_queryset")
serializer = self.get_serializer(queryset, many=True)
return self.get_paginated_response(serializer.data)
class DummyViewSet(CustomView):
queryset = []
serializer_class = DummySerializer
permission_classes = (IsAuthenticated, DummyPermission)
def get_queryset(self, request, **kwargs):
dummy_objects = list_dummy_objects()
return dummy_objects
def list(self, request, **kwargs):
pagination_viewset = PaginationViewSet(self)
return pagination_viewset.list(request, **kwargs)
The problem is that decorator functions need to use attributes from the ModelViewSet superclass that are initialized at the endpoint but are not in the decorator, such as "self.request". Is there any way for the decorator to access this data or am I using design patterns incorrectly?
Thank you.
Error trace:
File "####################################/viewsets/decorators.py", line 21, in list
queryset = self.get_queryset(request, **kwargs)
File "####################################/viewsets/decorators.py", line 64, in get_queryset
return self.paginate_queryset(queryset)
File "##################################/local/lib/python2.7/site-packages/rest_framework/generics.py", line 173, in paginate_queryset
return self.paginator.paginate_queryset(queryset, self.request, view=self)
AttributeError: 'PaginationViewSet' object has no attribute 'request'

Aucun commentaire:
Enregistrer un commentaire