David Wolever
David Wolever

Reputation: 154454

Routing API Views in Django Rest Framework?

Is there any common pattern for routing APIViews (ie, not ViewSets) with Django Rest Framework?

For example, if I've got an API View that takes an optional argument:

class ReportView(APIView):
    def get(self, request, report_name=None):
         # … stuff …
         return Response(report)

Is there any standard pattern — apart from writing out a standard Django URL router — for routing that view?

Upvotes: 27

Views: 8790

Answers (2)

David Avsajanishvili
David Avsajanishvili

Reputation: 8036

Being able to add simple API views is quite useful for displaying the urls in root-api view.

Here is the simplest extension of DefaultRouter that enables registering not only viewsets but also simple API views:

from django.conf.urls import url
from rest_framework import routers, viewsets
from rest_framework.urlpatterns import format_suffix_patterns

class DefaultRouterWithSimpleViews(routers.DefaultRouter):
    """
    Extends functionality of DefaultRouter adding possibility
    to register simple API views, not just Viewsets.
    """

    def get_routes(self, viewset):
        """
        Checks if the viewset is an instance of ViewSet,
        otherwise assumes it's a simple view and does not run
        original `get_routes` code.
        """
        if issubclass(viewset, viewsets.ViewSetMixin):
            return super(DefaultRouterWithSimpleViews, self).get_routes(viewset)

        return []

    def get_urls(self):
        """
        Append non-viewset views to the urls
        generated by the original `get_urls` method.
        """    
        # URLs for simple views
        ret = []
        for prefix, viewset, basename in self.registry:

            # Skip viewsets
            if issubclass(viewset, viewsets.ViewSetMixin):
                continue

            # URL regex
            regex = '{prefix}{trailing_slash}$'.format(
                prefix=prefix,
                trailing_slash=self.trailing_slash
            )

            # The view name has to have suffix "-list" due to specifics
            # of the DefaultRouter implementation.
            ret.append(url(
                regex, viewset.as_view(),
                name='{0}-list'.format(basename)
            ))

        # Format suffixes
        ret = format_suffix_patterns(ret, allowed=['json', 'html'])

        # Prepend URLs for viewsets and return
        return super(DefaultRouterWithSimpleViews, self).get_urls() + ret

Now you can use simple Django views alongside with the rest framework ViewSets:

router = DefaultRouterWithSimpleViews()
router.register(r'users', UserViewSet, 'users')                # <- Viewset!         
router.register(r'reset-pwd', ResetPasswordView, 'reset_pwd')  # <- Simple view!
urlpatterns = router.urls

Update: Added support of format suffixes (thanks to alexander-klimenko)

Upvotes: 19

Tom Christie
Tom Christie

Reputation: 33901

Is there any standard pattern — apart from writing out a standard Django URL router — for routing that view?

ViewSets & Routers are the pattern if you want standardised routing.

If you're using views then just use a regular Django URLconf.

Upvotes: 8

Related Questions