Skip to content

Instantly share code, notes, and snippets.

@Atorich
Last active December 3, 2019 08:52
Show Gist options
  • Save Atorich/8e3ca27808c9f64615663ff2d1ee0bba to your computer and use it in GitHub Desktop.
Save Atorich/8e3ca27808c9f64615663ff2d1ee0bba to your computer and use it in GitHub Desktop.
def viewset_factory(*, name: str, method_mapping: Mapping, viewset_class=viewsets.GenericViewSet, **attrs):
"""Returns ViewSet class with views' methods got from `method_mapping`
Example:
Suppose, we have 2 views:
FooListView(generics.ListAPIView):
def list(request):
# impl.
pass
FooCreateView(generics.CreateAPIView):
def create(request:
# impl.
pass
And we want to combine them into one viewset to make possible
passsing it to the `rest_framework` router
FooViewSet = viewset_factory(
name='FooViewSet',
method_mapping={
'list': FooListView,
'create': FooCreateView,
}
)
This is roughly equivalent to:
class FooViewSet(viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
view_class = FooListView(request=request)
view_class.args = args
view_class.kwargs = kwargs
view_class.initial(request)
return view_class.list(request)
def create(self, request):
view_class = FooCreateView(request=request)
view_class.args = args
view_class.kwargs = kwargs
view_class.initial(request)
return view_class.create(request)
"""
def _create_viewset_method(view_class, method):
def _method(cls, request, *args, **kwargs):
view = view_class(request=request)
view.args = args
view.kwargs = kwargs
view.initial(request)
m = getattr(view, method)
return m(request, *args, **kwargs)
return _method
def _get_serializer_class(viewset):
requested_class = method_mapping[viewset.action]
return requested_class.serializer_class
viewset_class_name, viewset_class_attrs = name, {}
for method, view_class in method_mapping.items():
view_method = _create_viewset_method(view_class, method)
viewset_class_attrs[method] = view_method
# stubs for api-docs
attrs.setdefault('queryset', QuerySet().none())
attrs.setdefault('get_serializer_class', _get_serializer_class)
viewset_class_attrs.update(attrs)
viewset = type(viewset_class)(viewset_class_name, (viewset_class,), viewset_class_attrs)
return viewset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment