              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
 
</s> remove                 # Standard route
                ret.append(route)
 </s> add                 routes.append(route) </s> remove 
        # 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:
                # checking method names against the known actions list
                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
                url_path = escape_curly_brackets(url_path)
                url_name = initkwargs.pop("url_name", None) or url_path
                ret.append(Route(
                    url=replace_methodname(route.url, url_path),
                    mapping={httpmethod: methodname for httpmethod in httpmethods},
                    name=replace_methodname(route.name, url_name),
                    initkwargs=initkwargs,
                ))

            return ret

        ret = []
 </s> add         extra_actions = viewset.get_extra_actions()

        # checking action names against the known actions list
        not_allowed = [
            action.__name__ for action in extra_actions
            if action.__name__ in known_actions
        ]
        if not_allowed:
            msg = ('Cannot use the @action decorator on the following '
                   'methods, as they are existing routes: %s')
            raise ImproperlyConfigured(msg % ', '.join(not_allowed))

        # partition detail and list actions
        detail_actions = [action for action in extra_actions if action.detail]
        list_actions = [action for action in extra_actions if not action.detail]

        routes = [] </s> remove         return ret
 </s> add         return routes

    def _get_dynamic_route(self, route, action):
        initkwargs = route.initkwargs.copy()
        initkwargs.update(action.kwargs)

        url_path = escape_curly_brackets(action.url_path)

        return Route(
            url=route.url.replace('{url_path}', url_path),
            mapping={http_method: action.__name__
                     for http_method in action.bind_to_methods},
            name=route.name.replace('{url_name}', action.url_name),
            detail=route.detail,
            initkwargs=initkwargs,
        ) </s> remove def replace_methodname(format_string, methodname):
    """
    Partially format a format_string, swapping out any
    '{methodname}' or '{methodnamehyphen}' components.
    """
    methodnamehyphen = methodname.replace('_', '-')
    ret = format_string
    ret = ret.replace('{methodname}', methodname)
    ret = ret.replace('{methodnamehyphen}', methodnamehyphen)
    return ret


 </s> add 
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
              return ret
  
          ret = []
          for route in self.routes:
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
              else:
                  # Standard route
                  ret.append(route)
  
          return ret
keep keep keep keep replace replace replace replace replace replace keep keep keep keep keep
 Rework dynamic list/detail actions (#5705)

* Merge list/detail route decorators into 'action'

* Merge dynamic routes, add 'detail' attribute

* Add 'ViewSet.get_extra_actions()'

* Refactor dynamic route checking & collection

* Refactor dynamic route generation

* Add 'ViewSet.detail' initkwarg

* Fixup schema test

* Add release notes for dynamic action changes

* Replace list/detail route decorators in tests

* Convert tabs to spaces in router docs

* Update docs

* Make 'detail' a required argument of 'action'

* Improve router docs 
rest_framework/routers.py