class MisagoApiRouter(DefaultRouter): routes = [ # List route. Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'}), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute(url=r'^{prefix}/{methodnamehyphen}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Detail route. Route(url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodnamehyphen}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class MetricRouter(SimpleRouter): """ A router for Metric APIs """ routes = [ Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create', }, name='{basename}-list', initkwargs={'suffix': 'List'}), DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), Route( url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ # 'get': 'retrieve', # 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class CreateDeleteRouter(SimpleRouter): """ A router for create / delete APIs """ routes = [ # Create route. Route(url=r'^{prefix}{trailing_slash}$', mapping={'post': 'create'}, name='{basename}-link', initkwargs={'suffix': 'Create'}), # Dynamically generated list routes. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Delete route Route(url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={'delete': 'destroy'}, name='{basename}-unlink', initkwargs={'suffix': 'Instance'}), # Dynamically generated detail routes. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class SearchRouter(DefaultRouter): routes = [ Route( url=r'^{prefix}$', mapping={'get': 'list'}, name='{basename}-list', initkwargs={'suffix': 'List'} ), Route( url=r'^{prefix}/{lookup}$', mapping={'get': 'retrieve'}, name='{basename}-detail', initkwargs={'suffix': 'Detail'} ), DynamicDetailRoute( url=r'^{prefix}/{methodname}/(?P<query_term>[^/.]+)/$', name='{basename}-{methodname}', initkwargs={} ), DynamicListRoute( url=r'^{prefix}/{methodname}/$', name='{basename}-{methodname}', initkwargs={} ) ]
class EndpointRouterMixin: endpoint_routes = [ # List route. Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'}), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Edit route. Route(url=r'^{prefix}/{lookup}/edit{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Endpoint route. Route(url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'endpoint_get', 'put': 'endpoint_put', 'post': 'endpoint_post', 'patch': 'endpoint_patch', 'delete': 'endpoint_delete' }, name='{basename}-endpoint', initkwargs={'suffix': 'Instance'}), ] def __init__(self, *args, **kwargs): # Save original routes so we can switch them later on without modifying logic too much. self._routes = self.routes super().__init__(*args, **kwargs) def get_routes(self, viewset): if getattr(viewset, 'as_endpoint', False): self.routes = self.endpoint_routes else: self.routes = self._routes return super().get_routes(viewset)
class JSONSchemaRouter(SimpleRouter): routes = [ DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='schema-{basename}-{methodnamehyphen}', initkwargs={}), ] def get_default_base_name(self, viewset): model_cls = viewset.schema_for.Meta.model return '{}-{}'.format(viewset.app_name, model_cls._meta.object_name.lower())
class CreateRouter(SimpleRouter): """ A router for create APIs """ routes = [ # Create route. Route(url=r'^{prefix}{trailing_slash}$', mapping={'post': 'create'}, name='{basename}-create', initkwargs={'suffix': 'Create'}), # Dynamically generated list routes. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class SingleRecordRouter(SimpleRouter): routes = [ Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'post': 'create', 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class SimpleRouter(BaseRouter): """ Custom Router that maps viewset methods to its methodnamehyphen variant. For example: Method do_some_stuff will be translated to url resource/do-some-stuff """ routes = [ # List route. Route( url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'} ), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute( url=r'^{prefix}/{methodnamehyphen}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), # Detail route. Route( url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'} ), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodnamehyphen}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), ]
class MisagoApiRouter(DefaultRouter): include_root_view = False include_format_suffixes = False routes = [ # List route. Route( url=r"^{prefix}{trailing_slash}$", mapping={ "get": "list", "post": "create" }, name="{basename}-list", initkwargs={"suffix": "List"}, ), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute( url=r"^{prefix}/{methodnamehyphen}{trailing_slash}$", name="{basename}-{methodnamehyphen}", initkwargs={}, ), # Detail route. Route( url=r"^{prefix}/{lookup}{trailing_slash}$", mapping={ "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy", }, name="{basename}-detail", initkwargs={"suffix": "Instance"}, ), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r"^{prefix}/{lookup}/{methodnamehyphen}{trailing_slash}$", name="{basename}-{methodnamehyphen}", initkwargs={}, ), ]
class TusAPIRouter(SimpleRouter): routes = [ # List route. get_list_route(), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute( url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), # Detail route. get_detail_route(), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), ]
class PostHackedRouter(DefaultRouter): """ hack post method for detail api, make post method avaliable for partial_update action """ routes = [ # List route. Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'}), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Detail route. Route( url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'post': 'partial_update', # some browser cannot patch data, use post instead 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ]
class Router(DefaultRouter): routes = [ # List route. Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'}), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{methodname}/{lookup}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Detail route. Route(url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), ] def produce_urls(self): ret = [] base_regex = '(?P<{lookup_field}>[^/]+)' for prefix, viewset, basename in self.registry: lookup = self.get_lookup_regex(viewset) routes = self.get_routes(viewset) for route in routes: # Only actions which actually exist on the viewset will be bound mapping = self.get_method_map(viewset, route.mapping) if not mapping: continue # Build the url pattern regex = route.url.format(prefix=prefix, lookup=lookup, trailing_slash=self.trailing_slash) if not route.initkwargs: function_name = mapping.get('get', None) or mapping.get( 'post', None) handler = getattr(viewset, function_name) if hasattr(handler, 'lookup'): lookup_list = [] for lp in handler.lookup: lookup_list.append( base_regex.format(lookup_field=lp)) custom_lookup = '/'.join(lookup_list) regex = route.url.format( prefix=prefix, lookup=custom_lookup, trailing_slash=self.trailing_slash if custom_lookup else '') view = viewset.as_view(mapping, **route.initkwargs) name = route.name.format(basename=basename) ret.append(url(regex, view, name=name)) return ret def get_urls(self): """ Generate the list of URL patterns, including a default root view for the API, and appending `.json` style format suffixes. """ urls = [] if self.include_root_view: root_url = url(r'^api_root$', self.get_api_root_view(), name=self.root_view_name) urls.append(root_url) #default_urls = super(DefaultRouter, self).get_urls() default_urls = self.produce_urls() urls.extend(default_urls) if self.include_format_suffixes: urls = format_suffix_patterns(urls) return urls
class APIRouter(BaseRouter): routes = [ # List route. Route(url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'get', 'post': 'post', 'options': 'post' }, name='{basename}-list', initkwargs={'suffix': 'List'}), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute(url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), # Detail route. Route(url=r'^{prefix}/{lookup}{trailing_slash}$', mapping={ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy' }, name='{basename}-detail', initkwargs={'suffix': 'Instance'}), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={}), ] def __init__(self, trailing_slash=True): self.trailing_slash = trailing_slash and '/' or '' super(APIRouter, self).__init__() def get_default_base_name(self, viewset): """ If `base_name` is not specified, attempt to automatically determine it from the viewset. """ queryset = getattr(viewset, 'queryset', None) assert queryset is not None, '`base_name` argument not specified, and could ' \ 'not automatically determine the name from the viewset, as ' \ 'it does not have a `.queryset` attribute.' return queryset.model._meta.object_name.lower() def get_routes(self, viewset): """ Augment `self.routes` with any dynamically generated routes. Returns a list of the Route namedtuple. """ known_actions = flatten([ route.mapping.values() for route in self.routes if isinstance(route, Route) ]) # Determine any `@detail_route` or `@list_route` decorated methods on the viewset detail_routes = [] list_routes = [] for methodname in dir(viewset): attr = getattr(viewset, methodname) httpmethods = getattr(attr, 'bind_to_methods', None) detail = getattr(attr, 'detail', True) if httpmethods: if methodname in known_actions: raise ImproperlyConfigured( 'Cannot use @detail_route or @list_route ' 'decorators on method "%s" ' 'as it is an existing route' % methodname) httpmethods = [method.lower() for method in httpmethods] if detail: detail_routes.append((httpmethods, methodname)) else: list_routes.append((httpmethods, methodname)) def _get_dynamic_routes(route, dynamic_routes): ret = [] for httpmethods, methodname in dynamic_routes: method_kwargs = getattr(viewset, methodname).kwargs initkwargs = route.initkwargs.copy() initkwargs.update(method_kwargs) url_path = initkwargs.pop("url_path", None) or methodname ret.append( Route( url=replace_methodname(route.url, url_path), mapping={ httpmethod: methodname for httpmethod in httpmethods }, name=replace_methodname(route.name, url_path), initkwargs=initkwargs, )) return ret ret = [] for route in self.routes: if isinstance(route, DynamicDetailRoute): # Dynamic detail routes (@detail_route decorator) ret += _get_dynamic_routes(route, detail_routes) elif isinstance(route, DynamicListRoute): # Dynamic list routes (@list_route decorator) ret += _get_dynamic_routes(route, list_routes) else: # Standard route ret.append(route) return ret def get_method_map(self, viewset, method_map): """ Given a viewset, and a mapping of http methods to actions, return a new mapping which only includes any mappings that are actually implemented by the viewset. """ bound_methods = {} for method, action in method_map.items(): if hasattr(viewset, action): bound_methods[method] = action return bound_methods def get_lookup_regex(self, viewset, lookup_prefix=''): """ Given a viewset, return the portion of URL regex that is used to match against a single instance. Note that lookup_prefix is not used directly inside REST rest_framework itself, but is required in order to nicely support nested router implementations, such as drf-nested-routers. https://github.com/alanjds/drf-nested-routers """ base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})' # Use `pk` as default field, unset set. Default regex should not # consume `.json` style suffixes and should break at '/' boundaries. lookup_field = getattr(viewset, 'lookup_field', 'pk') lookup_url_kwarg = getattr(viewset, 'lookup_url_kwarg', None) or lookup_field lookup_value = getattr(viewset, 'lookup_value_regex', '[^/.]+') return base_regex.format(lookup_prefix=lookup_prefix, lookup_url_kwarg=lookup_url_kwarg, lookup_value=lookup_value) def get_urls(self): """ Use the registered viewsets to generate a list of URL patterns. """ ret = [] for prefix, viewset, basename in self.registry: lookup = self.get_lookup_regex(viewset) routes = self.get_routes(viewset) for route in routes: # Only actions which actually exist on the viewset will be bound mapping = self.get_method_map(viewset, route.mapping) if not mapping: continue # Build the url pattern regex = route.url.format(prefix=prefix, lookup=lookup, trailing_slash=self.trailing_slash) view = viewset.as_view(mapping, **route.initkwargs) name = route.name.format(basename=basename) ret.append(url(regex, view, name=name)) return ret
class InterfacePushRouter(DefaultRouter): """ A router for interface push APIs """ routes = [ # List route. Route( url=r'^{prefix}{trailing_slash}$', mapping={ 'get': 'list', 'post': 'create' }, name='{basename}-list', initkwargs={'suffix': 'List'} ), # Dynamically generated list routes. # Generated using @list_route decorator # on methods of the viewset. DynamicListRoute( url=r'^{prefix}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), # Detail route. #Route( # url=r'^{prefix}/{lookup}{trailing_slash}$', # mapping={ # 'get': 'retrieve', # 'put': 'update', # 'patch': 'partial_update', # 'delete': 'destroy' # }, # name='{basename}-detail', # initkwargs={'suffix': 'Instance'} #), Route( url=r'^{prefix}/{lookup}/$', mapping={ 'post': 'push', 'get': 'pull' }, name='{basename}-table-detail', initkwargs={'suffix': 'Instance'} ), # Dynamically generated detail routes. # Generated using @detail_route decorator on methods of the viewset. DynamicDetailRoute( url=r'^{prefix}/{lookup}/{methodname}{trailing_slash}$', name='{basename}-{methodnamehyphen}', initkwargs={} ), ] def get_api_root_view(self): """ Return a view to use as the API root. """ api_root_dict = OrderedDict() list_name = self.routes[0].name interface_entrys = InterfaceEntry.objects.all() for prefix, viewset, basename in self.registry: api_root_dict[prefix] = list_name.format(basename=basename) class APIRoot(views.APIView): _ignore_model_permissions = True def get(self, request, *args, **kwargs): ret = OrderedDict() namespace = get_resolver_match(request).namespace for key, url_name in api_root_dict.items(): if namespace: url_name = namespace + ':' + url_name try: ret[key] = reverse( url_name, request=request, format=kwargs.get('format', None) ) except NoReverseMatch: # Don't bail out if eg. no list routes exist, only detail routes. continue for entry in interface_entrys: absolute_url = '/' + key + '/' + entry.tname + '/' url = request.build_absolute_uri(absolute_url) ret['interface-%s' % entry.tname] = url return Response(ret) return APIRoot.as_view()