27

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?

2 Answers 2

19

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)

Sign up to request clarification or add additional context in comments.

11 Comments

Just little notice. This router will produce urls without suffix (*.json, *.jsonp) support. You have to call format_suffix_patterns for extra patterns.
@AlexanderKlimenko thanks! I've updated the answer - please double-check if it's correct.
Maybe to make this example code easier to understand, you could also include a short example of how it would be used?
@М.Б. it might be a typo in your code. Perhaps you missed the first line where router instance is created?
@DavidAvsajanishvili i did it finally! I found a way. I will link git repo here when get project done.
|
8

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.

1 Comment

How can I add to the browsable API the views that use the regular Django URLconf?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.