Buckets:
ktongue/docker_container / simsite /venv /lib /python3.14 /site-packages /rest_framework /viewsets.py
| """ | |
| ViewSets are essentially just a type of class based view, that doesn't provide | |
| any method handlers, such as `get()`, `post()`, etc... but instead has actions, | |
| such as `list()`, `retrieve()`, `create()`, etc... | |
| Actions are only bound to methods at the point of instantiating the views. | |
| user_list = UserViewSet.as_view({'get': 'list'}) | |
| user_detail = UserViewSet.as_view({'get': 'retrieve'}) | |
| Typically, rather than instantiate views from viewsets directly, you'll | |
| register the viewset with a router and let the URL conf be determined | |
| automatically. | |
| router = DefaultRouter() | |
| router.register(r'users', UserViewSet, 'user') | |
| urlpatterns = router.urls | |
| """ | |
| from functools import update_wrapper | |
| from inspect import getmembers | |
| from django import VERSION as DJANGO_VERSION | |
| from django.urls import NoReverseMatch | |
| from django.utils.decorators import classonlymethod | |
| from django.views.decorators.csrf import csrf_exempt | |
| from rest_framework import generics, mixins, views | |
| from rest_framework.decorators import MethodMapper | |
| from rest_framework.reverse import reverse | |
| def _is_extra_action(attr): | |
| return hasattr(attr, 'mapping') and isinstance(attr.mapping, MethodMapper) | |
| def _check_attr_name(func, name): | |
| assert func.__name__ == name, ( | |
| 'Expected function (`{func.__name__}`) to match its attribute name ' | |
| '(`{name}`). If using a decorator, ensure the inner function is ' | |
| 'decorated with `functools.wraps`, or that `{func.__name__}.__name__` ' | |
| 'is otherwise set to `{name}`.').format(func=func, name=name) | |
| return func | |
| class ViewSetMixin: | |
| """ | |
| This is the magic. | |
| Overrides `.as_view()` so that it takes an `actions` keyword that performs | |
| the binding of HTTP methods to actions on the Resource. | |
| For example, to create a concrete view binding the 'GET' and 'POST' methods | |
| to the 'list' and 'create' actions... | |
| view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) | |
| """ | |
| def as_view(cls, actions=None, **initkwargs): | |
| """ | |
| Because of the way class based views create a closure around the | |
| instantiated view, we need to totally reimplement `.as_view`, | |
| and slightly modify the view function that is created and returned. | |
| """ | |
| # The name and description initkwargs may be explicitly overridden for | |
| # certain route configurations. eg, names of extra actions. | |
| cls.name = None | |
| cls.description = None | |
| # The suffix initkwarg is reserved for displaying the viewset type. | |
| # This initkwarg should have no effect if the name is provided. | |
| # eg. 'List' or 'Instance'. | |
| cls.suffix = None | |
| # The detail initkwarg is reserved for introspecting the viewset type. | |
| cls.detail = None | |
| # Setting a basename allows a view to reverse its action urls. This | |
| # value is provided by the router through the initkwargs. | |
| cls.basename = None | |
| # actions must not be empty | |
| if not actions: | |
| raise TypeError("The `actions` argument must be provided when " | |
| "calling `.as_view()` on a ViewSet. For example " | |
| "`.as_view({'get': 'list'})`") | |
| # sanitize keyword arguments | |
| for key in initkwargs: | |
| if key in cls.http_method_names: | |
| raise TypeError("You tried to pass in the %s method name as a " | |
| "keyword argument to %s(). Don't do that." | |
| % (key, cls.__name__)) | |
| if not hasattr(cls, key): | |
| raise TypeError("%s() received an invalid keyword %r" % ( | |
| cls.__name__, key)) | |
| # name and suffix are mutually exclusive | |
| if 'name' in initkwargs and 'suffix' in initkwargs: | |
| raise TypeError("%s() received both `name` and `suffix`, which are " | |
| "mutually exclusive arguments." % (cls.__name__)) | |
| def view(request, *args, **kwargs): | |
| self = cls(**initkwargs) | |
| if 'get' in actions and 'head' not in actions: | |
| actions['head'] = actions['get'] | |
| # We also store the mapping of request methods to actions, | |
| # so that we can later set the action attribute. | |
| # eg. `self.action = 'list'` on an incoming GET request. | |
| self.action_map = actions | |
| # Bind methods to actions | |
| # This is the bit that's different to a standard view | |
| for method, action in actions.items(): | |
| handler = getattr(self, action) | |
| setattr(self, method, handler) | |
| self.request = request | |
| self.args = args | |
| self.kwargs = kwargs | |
| # And continue as usual | |
| return self.dispatch(request, *args, **kwargs) | |
| # take name and docstring from class | |
| update_wrapper(view, cls, updated=()) | |
| # and possible attributes set by decorators | |
| # like csrf_exempt from dispatch | |
| update_wrapper(view, cls.dispatch, assigned=()) | |
| # We need to set these on the view function, so that breadcrumb | |
| # generation can pick out these bits of information from a | |
| # resolved URL. | |
| view.cls = cls | |
| view.initkwargs = initkwargs | |
| view.actions = actions | |
| # Exempt from Django's LoginRequiredMiddleware. Users should set | |
| # DEFAULT_PERMISSION_CLASSES to 'rest_framework.permissions.IsAuthenticated' instead | |
| if DJANGO_VERSION >= (5, 1): | |
| view.login_required = False | |
| return csrf_exempt(view) | |
| def initialize_request(self, request, *args, **kwargs): | |
| """ | |
| Set the `.action` attribute on the view, depending on the request method. | |
| """ | |
| request = super().initialize_request(request, *args, **kwargs) | |
| method = request.method.lower() | |
| if method == 'options': | |
| # This is a special case as we always provide handling for the | |
| # options method in the base `View` class. | |
| # Unlike the other explicitly defined actions, 'metadata' is implicit. | |
| self.action = 'metadata' | |
| else: | |
| self.action = self.action_map.get(method) | |
| return request | |
| def reverse_action(self, url_name, *args, **kwargs): | |
| """ | |
| Reverse the action for the given `url_name`. | |
| """ | |
| url_name = '%s-%s' % (self.basename, url_name) | |
| namespace = None | |
| if self.request and self.request.resolver_match: | |
| namespace = self.request.resolver_match.namespace | |
| if namespace: | |
| url_name = namespace + ':' + url_name | |
| kwargs.setdefault('request', self.request) | |
| return reverse(url_name, *args, **kwargs) | |
| def get_extra_actions(cls): | |
| """ | |
| Get the methods that are marked as an extra ViewSet `@action`. | |
| """ | |
| return [_check_attr_name(method, name) | |
| for name, method | |
| in getmembers(cls, _is_extra_action)] | |
| def get_extra_action_url_map(self): | |
| """ | |
| Build a map of {names: urls} for the extra actions. | |
| This method will noop if `detail` was not provided as a view initkwarg. | |
| """ | |
| action_urls = {} | |
| # exit early if `detail` has not been provided | |
| if self.detail is None: | |
| return action_urls | |
| # filter for the relevant extra actions | |
| actions = [ | |
| action for action in self.get_extra_actions() | |
| if action.detail == self.detail | |
| ] | |
| for action in actions: | |
| try: | |
| url_name = '%s-%s' % (self.basename, action.url_name) | |
| namespace = self.request.resolver_match.namespace | |
| if namespace: | |
| url_name = '%s:%s' % (namespace, url_name) | |
| url = reverse(url_name, self.args, self.kwargs, request=self.request) | |
| view = self.__class__(**action.kwargs) | |
| action_urls[view.get_view_name()] = url | |
| except NoReverseMatch: | |
| pass # URL requires additional arguments, ignore | |
| return action_urls | |
| class ViewSet(ViewSetMixin, views.APIView): | |
| """ | |
| The base ViewSet class does not provide any actions by default. | |
| """ | |
| pass | |
| class GenericViewSet(ViewSetMixin, generics.GenericAPIView): | |
| """ | |
| The GenericViewSet class does not provide any actions by default, | |
| but does include the base set of generic view behavior, such as | |
| the `get_object` and `get_queryset` methods. | |
| """ | |
| pass | |
| class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, | |
| mixins.ListModelMixin, | |
| GenericViewSet): | |
| """ | |
| A viewset that provides default `list()` and `retrieve()` actions. | |
| """ | |
| pass | |
| class ModelViewSet(mixins.CreateModelMixin, | |
| mixins.RetrieveModelMixin, | |
| mixins.UpdateModelMixin, | |
| mixins.DestroyModelMixin, | |
| mixins.ListModelMixin, | |
| GenericViewSet): | |
| """ | |
| A viewset that provides default `create()`, `retrieve()`, `update()`, | |
| `partial_update()`, `destroy()` and `list()` actions. | |
| """ | |
| pass | |
Xet Storage Details
- Size:
- 9.29 kB
- Xet hash:
- 755ea9c18691f9eaae7552923c6c272d9285304637fe8b96b7e64f4cff99d0a2
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.