示例#1
0
    def test_list_route_and_detail_route_with_exact_names(self):
        class BasicViewSet(viewsets.ViewSet):
            @list_route(url_path='action-one')
            def action1(self, request, *args, **kwargs):
                pass

            @detail_route(url_path='action-one')
            def action1_detail(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_list_route = self.get_dynamic_route_by_def_name(
            'action1', routes)
        action1_detail_route = self.get_dynamic_route_by_def_name(
            'action1_detail', routes)

        self.assertEqual(action1_list_route.mapping, {'get': 'action1'})
        self.assertEqual(
            action1_list_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/action-one/$'))

        self.assertEqual(action1_detail_route.mapping,
                         {'get': 'action1_detail'})
        self.assertEqual(
            action1_detail_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/{lookup}/action-one/$'))
示例#2
0
    def test_actions__for_list_and_detail_with_exact_names(self):
        class BasicViewSet(viewsets.ViewSet):
            @action(is_for_list=True, endpoint='action-one')
            def action1(self, request, *args, **kwargs):
                pass

            @action(endpoint='action-one')
            def action1_detail(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_list_route = self.get_dynamic_route_by_def_name('action1', routes)
        action1_detail_route = self.get_dynamic_route_by_def_name('action1_detail', routes)

        self.assertEqual(action1_list_route.mapping, {'post': 'action1'})
        self.assertEqual(action1_list_route.url, add_trailing_slash_if_needed(u'^{prefix}/action-one/$'))

        self.assertEqual(action1_detail_route.mapping, {'post': 'action1_detail'})
        self.assertEqual(action1_detail_route.url, add_trailing_slash_if_needed(u'^{prefix}/{lookup}/action-one/$'))
示例#3
0
    def test_action__for_list__and__with_endpoint(self):
        class BasicViewSet(viewsets.ViewSet):
            @action(is_for_list=True, endpoint='action-one')
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@action with is_for_list=True and endpoint route should map methods to "endpoint"'
        self.assertEqual(action1_route.mapping, {'post': 'action1'}, msg)

        msg = '@action with is_for_list=True and endpoint route should use url in list scope with "endpoint" value'
        self.assertEqual(action1_route.url, add_trailing_slash_if_needed(u'^{prefix}/action-one/$'), msg)
示例#4
0
    def test_link_endpoint(self):
        class BasicViewSet(viewsets.ViewSet):
            @link(endpoint='link-one')
            def link1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        link1_route = self.get_dynamic_route_by_def_name('link1', routes)

        msg = '@link with endpoint route should map methods to endpoint if it is specified'
        self.assertEqual(link1_route.mapping, {'get': 'link1'}, msg)

        msg = '@link with endpoint route should use url with detail lookup'
        self.assertEqual(link1_route.url, add_trailing_slash_if_needed(u'^{prefix}/{lookup}/link-one/$'), msg)
示例#5
0
    def test_list_route(self):
        class BasicViewSet(viewsets.ViewSet):
            @list_route()
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@list_route should map methods to def name'
        self.assertEqual(action1_route.mapping, {'get': 'action1'}, msg)

        msg = '@list_route should use url in list scope'
        self.assertEqual(action1_route.url, add_trailing_slash_if_needed(u'^{prefix}/action1/$'), msg)
示例#6
0
    def test_detail_route__with_methods__and__with_url_path(self):
        class BasicViewSet(viewsets.ViewSet):
            @detail_route(methods=['post'], url_path='action-one')
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@detail_route should map methods to "url_path"'
        self.assertEqual(action1_route.mapping, {'post': 'action1'}, msg)

        msg = '@detail_route should use url with detail lookup and "url_path" value'
        self.assertEqual(action1_route.url, add_trailing_slash_if_needed(u'^{prefix}/{lookup}/action-one/$'), msg)
示例#7
0
    def test_list_route(self):
        class BasicViewSet(viewsets.ViewSet):
            @list_route()
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@list_route should map methods to def name'
        self.assertEqual(action1_route.mapping, {'get': 'action1'}, msg)

        msg = '@list_route should use url in list scope'
        self.assertEqual(action1_route.url,
                         add_trailing_slash_if_needed(u'^{prefix}/action1/$'),
                         msg)
示例#8
0
    def test_detail_route__with_methods(self):
        class BasicViewSet(viewsets.ViewSet):
            @detail_route(methods=['post'])
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@detail_route should map methods to def name'
        self.assertEqual(action1_route.mapping, {'post': 'action1'}, msg)

        msg = '@detail_route should use url with detail lookup'
        self.assertEqual(
            action1_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/{lookup}/action1/$'), msg)
示例#9
0
    def test_list_route__with_methods__and__with_url_path(self):
        class BasicViewSet(viewsets.ViewSet):
            @list_route(methods=['post'], url_path='action-one')
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@list_route should map methods to "url_path"'
        self.assertEqual(action1_route.mapping, {'post': 'action1'}, msg)

        msg = '@list_route should use url in list scope with "url_path" value'
        self.assertEqual(
            action1_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/action-one/$'), msg)
示例#10
0
    def test_action__for_list__and__with_endpoint(self):
        class BasicViewSet(viewsets.ViewSet):
            @action(is_for_list=True, endpoint='action-one')
            def action1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        action1_route = self.get_dynamic_route_by_def_name('action1', routes)

        msg = '@action with is_for_list=True and endpoint route should map methods to "endpoint"'
        self.assertEqual(action1_route.mapping, {'post': 'action1'}, msg)

        msg = '@action with is_for_list=True and endpoint route should use url in list scope with "endpoint" value'
        self.assertEqual(
            action1_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/action-one/$'), msg)
示例#11
0
    def test_link_endpoint(self):
        class BasicViewSet(viewsets.ViewSet):
            @link(endpoint='link-one')
            def link1(self, request, *args, **kwargs):
                pass

        routes = self.router.get_routes(BasicViewSet)
        link1_route = self.get_dynamic_route_by_def_name('link1', routes)

        msg = '@link with endpoint route should map methods to endpoint if it is specified'
        self.assertEqual(link1_route.mapping, {'get': 'link1'}, msg)

        msg = '@link with endpoint route should use url with detail lookup'
        self.assertEqual(
            link1_route.url,
            add_trailing_slash_if_needed(u'^{prefix}/{lookup}/link-one/$'),
            msg)
示例#12
0
class ExtendedBulkRouter(ExtendedDefaultRouter):
    """
    Map http methods to actions defined on the bulk mixins.
    """
    routes = copy.deepcopy(ExtendedDefaultRouter.routes)
    routes[0].mapping.update({
        'put': 'bulk_update',
        'patch': 'partial_bulk_update',
        'delete': 'bulk_destroy',
    })
    routes.append(
        # Single route.
        Route(url=add_trailing_slash_if_needed(r'^{prefix}/$'),
              mapping={
                  'get': 'retrieve_single',
                  'put': 'update_single',
                  'patch': 'partial_update_single',
                  'delete': 'destroy_single'
              },
              name='{basename}-single',
              initkwargs={'suffix': 'Instance'}), )
    _routs = routes[2:4] + routes[4:5] + routes[:2]
示例#13
0
class ExtendedActionLinkRouterMixin(object):
    routes = [
        # List route.
        Route(url=add_trailing_slash_if_needed(r'^{prefix}/$'),
              mapping={
                  'get': 'list',
                  'post': 'create'
              },
              name='{basename}-list',
              initkwargs={'suffix': 'List'}),
        # Detail route.
        Route(url=add_trailing_slash_if_needed(r'^{prefix}/{lookup}/$'),
              mapping={
                  'get': 'retrieve',
                  'put': 'update',
                  'patch': 'partial_update',
                  'delete': 'destroy'
              },
              name='{basename}-detail',
              initkwargs={'suffix': 'Instance'}),
        # Dynamically generated routes.
        # Generated using @list_route or @detail_route decorators on methods of the viewset.
        # List
        Route(url=add_trailing_slash_if_needed(r'^{prefix}/{methodname}/$'),
              mapping={
                  '{httpmethod}': '{methodname}',
              },
              name='{basename}-{methodnamehyphen}-list',
              initkwargs={}),
        # Detail
        Route(url=add_trailing_slash_if_needed(
            r'^{prefix}/{lookup}/{methodname}/$'),
              mapping={
                  '{httpmethod}': '{methodname}',
              },
              name='{basename}-{methodnamehyphen}',
              initkwargs={}),
    ]
    _routs = routes[
        2:
        4] + routes[:
                    2]  # first routes should be dynamic (because of urlpatterns position matters)

    # left self.routs for backward

    def get_routes(self, viewset):
        """
        Augment `self.routes` with any dynamically generated routes.

        Returns a list of the Route namedtuple.
        """

        # Determine any `@list_route` or `@detail_route` decorated methods on the viewset
        dynamic_routes = self.get_dynamic_routes(viewset)

        ret = []
        for route in self._routs:
            if self.is_dynamic_route(route):
                # Dynamic routes (@list_route or @detail_route decorator)
                if self.is_list_dynamic_route(route):
                    ret += self.get_dynamic_routes_instances(
                        viewset, route,
                        self._filter_by_list_dynamic_routes(dynamic_routes))
                else:
                    ret += self.get_dynamic_routes_instances(
                        viewset, route,
                        self._filter_by_detail_dynamic_routes(dynamic_routes))
            else:
                # Standard route
                ret.append(route)

        return ret

    def _filter_by_list_dynamic_routes(self, dynamic_routes):
        return [i for i in dynamic_routes if i[3]]

    def _filter_by_detail_dynamic_routes(self, dynamic_routes):
        return [i for i in dynamic_routes if not i[3]]

    def get_dynamic_routes(self, viewset):
        known_actions = self.get_known_actions()
        dynamic_routes = []
        for methodname in dir(viewset):
            attr = getattr(viewset, methodname)
            httpmethods = getattr(attr, 'bind_to_methods', None)
            if httpmethods:
                endpoint = getattr(attr, 'endpoint', methodname)
                is_for_list = getattr(attr, 'is_for_list',
                                      not getattr(attr, 'detail', True))
                if endpoint in known_actions:
                    raise ImproperlyConfigured(
                        'Cannot use @detail_route or @list_route decorator on '
                        'method "%s" as %s is an existing route' %
                        (methodname, endpoint))
                httpmethods = [method.lower() for method in httpmethods]
                dynamic_routes.append(
                    (httpmethods, methodname, endpoint, is_for_list))
        return dynamic_routes

    def get_dynamic_route_viewset_method_name_by_endpoint(
            self, viewset, endpoint):
        for dynamic_route in self.get_dynamic_routes(viewset=viewset):
            if dynamic_route[2] == endpoint:
                return dynamic_route[1]

    def get_known_actions(self):
        return flatten([route.mapping.values() for route in self.routes])

    def is_dynamic_route(self, route):
        return route.mapping == {'{httpmethod}': '{methodname}'}

    def is_list_dynamic_route(self, route):
        return route.name == '{basename}-{methodnamehyphen}-list'

    def get_dynamic_routes_instances(self, viewset, route, dynamic_routes):
        dynamic_routes_instances = []
        for httpmethods, methodname, endpoint, is_for_list in dynamic_routes:
            initkwargs = route.initkwargs.copy()
            initkwargs.update(getattr(viewset, methodname).kwargs)
            url_path = initkwargs.pop('url_path', endpoint)
            dynamic_routes_instances.append(
                Route(
                    url=replace_methodname(route.url, url_path),
                    mapping=dict((httpmethod, methodname)
                                 for httpmethod in httpmethods),
                    name=replace_methodname(route.name, url_path),
                    initkwargs=initkwargs,
                ))
        return dynamic_routes_instances
示例#14
0
class ExtendedActionLinkRouterMixin:
    routes = [
        # List route.
        Route(
            url=add_trailing_slash_if_needed(r"^{prefix}/$"),
            mapping={
                "get": "list",
                "post": "create"
            },
            name="{basename}-list",
            initkwargs={"suffix": "List"},
        ),
        # Detail route.
        Route(
            url=add_trailing_slash_if_needed(r"^{prefix}/{lookup}/$"),
            mapping={
                "get": "retrieve",
                "put": "update",
                "patch": "partial_update",
                "delete": "destroy",
            },
            name="{basename}-detail",
            initkwargs={"suffix": "Instance"},
        ),
        # Dynamically generated routes.
        # Generated using @list_route or @detail_route decorators on methods
        # of the viewset.
        # List
        Route(
            url=add_trailing_slash_if_needed(r"^{prefix}/{methodname}/$"),
            mapping={
                "{httpmethod}": "{methodname}",
            },
            name="{basename}-{methodnamehyphen}-list",
            initkwargs={},
        ),
        # Detail
        Route(
            url=add_trailing_slash_if_needed(
                r"^{prefix}/{lookup}/{methodname}/$"),
            mapping={
                "{httpmethod}": "{methodname}",
            },
            name="{basename}-{methodnamehyphen}",
            initkwargs={},
        ),
    ]
    # first routes should be dynamic (because of urlpatterns position matters)
    # left self.routs for backward
    _routs = routes[2:4] + routes[:2]

    def get_routes(self, viewset):
        """
        Augment `self.routes` with any dynamically generated routes.

        Returns a list of the Route namedtuple.
        """

        # Determine any `@list_route` or `@detail_route` decorated methods on
        # the viewset
        dynamic_routes = self.get_dynamic_routes(viewset)

        ret = []
        for route in self._routs:
            if self.is_dynamic_route(route):
                # Dynamic routes (@list_route or @detail_route decorator)
                if self.is_list_dynamic_route(route):
                    ret += self.get_dynamic_routes_instances(
                        viewset,
                        route,
                        self._filter_by_list_dynamic_routes(dynamic_routes),
                    )
                else:
                    ret += self.get_dynamic_routes_instances(
                        viewset,
                        route,
                        self._filter_by_detail_dynamic_routes(dynamic_routes),
                    )
            else:
                # Standard route
                ret.append(route)

        return ret

    def _filter_by_list_dynamic_routes(self, dynamic_routes):
        return [i for i in dynamic_routes if i[3]]

    def _filter_by_detail_dynamic_routes(self, dynamic_routes):
        return [i for i in dynamic_routes if not i[3]]

    def get_dynamic_routes(self, viewset):
        known_actions = self.get_known_actions()
        dynamic_routes = []
        for methodname in dir(viewset):
            attr = getattr(viewset, methodname)
            httpmethods = getattr(attr, "bind_to_methods", None)
            if httpmethods:
                endpoint = getattr(attr, "endpoint", methodname)
                is_for_list = getattr(attr, "is_for_list",
                                      not getattr(attr, "detail", True))
                if endpoint in known_actions:
                    raise ImproperlyConfigured(
                        "Cannot use @detail_route or @list_route decorator on "
                        'method "%s" as %s is an existing route' %
                        (methodname, endpoint))
                httpmethods = [method.lower() for method in httpmethods]
                dynamic_routes.append(
                    (httpmethods, methodname, endpoint, is_for_list))
        return dynamic_routes

    def get_dynamic_route_viewset_method_name_by_endpoint(
            self, viewset, endpoint):
        for dynamic_route in self.get_dynamic_routes(viewset=viewset):
            if dynamic_route[2] == endpoint:
                return dynamic_route[1]

    def get_known_actions(self):
        return flatten([route.mapping.values() for route in self.routes])

    def is_dynamic_route(self, route):
        return route.mapping == {"{httpmethod}": "{methodname}"}

    def is_list_dynamic_route(self, route):
        return route.name == "{basename}-{methodnamehyphen}-list"

    def get_dynamic_routes_instances(self, viewset, route, dynamic_routes):
        dynamic_routes_instances = []
        for httpmethods, methodname, endpoint, is_for_list in dynamic_routes:
            initkwargs = route.initkwargs.copy()
            initkwargs.update(getattr(viewset, methodname).kwargs)
            url_path = initkwargs.pop("url_path", endpoint)
            dynamic_routes_instances.append(
                Route(
                    url=replace_methodname(route.url, url_path),
                    mapping=dict((httpmethod, methodname)
                                 for httpmethod in httpmethods),
                    name=replace_methodname(route.name, url_path),
                    initkwargs=initkwargs,
                ))
        return dynamic_routes_instances