# Buggy code
def as_view(cls, actions=None, **initkwargs):
    """
    Because of the way class based views create a closure around the
    instantiated view, we need to totally reimplement `.as_view`,
    and slightly modify the view function that is created and returned.
    """
    # The suffix initkwarg is reserved for identifying the viewset type
    # eg. 'List' or 'Instance'.
    cls.suffix = None

    # actions must not be empty
    if not actions:
        raise TypeError(
            "The `actions` argument must be provided when "
            "calling `.as_view()` on a ViewSet. For example "
            "`.as_view({'get': 'list'})`"
        )

    # sanitize keyword arguments
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError(
                "You tried to pass in the %s method name as a "
                "keyword argument to %s(). Don't do that." % (key, cls.__name__)
            )
        if not hasattr(cls, key):
            raise TypeError("%s() received an invalid keyword %r" % (cls.__name__, key))

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        # We also store the mapping of request methods to actions,
        # so that we can later set the action attribute.
        # eg. `self.action = 'list'` on an incoming GET request.
        self.action_map = actions

        # Bind methods to actions
        # This is the bit that's different to a standard view
        for method, action in actions.items():
            handler = getattr(self, action)
            setattr(self, method, handler)

        # And continue as usual
        return self.dispatch(request, *args, **kwargs)

    # take name and docstring from class
    update_wrapper(view, cls, updated=())

    # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())

    # We need to set these on the view function, so that breadcrumb
    # generation can pick out these bits of information from a
    # resolved URL.
    view.cls = cls
    view.initkwargs = initkwargs
    view.suffix = initkwargs.get("suffix", None)
    view.actions = actions
    return csrf_exempt(view)


# Traceback (AssertionError)
pip show djangorestframework
---
Name: djangorestframework
Version: 3.5.3
Location: /home/matwey/temp/venv/lib/python3.4/site-packages
Requires:
(venv)matwey@epsilon:~/temp/drf_test> python runtests.py
Creating test database for alias 'default' ('file:memorydb_default?mode=memory&amp;cache=shared')...
Operations to perform:
Synchronize unmigrated apps: rest_framework, theapp
Apply all migrations: auth, authtoken, contenttypes
Synchronizing apps without migrations:
Creating tables...
Creating table theapp_model
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying authtoken.0001_initial... OK
Applying authtoken.0002_auto_20160226_1747... OK
test_model_head1 (tests.test.ModelTest) ... FAIL

======================================================================
FAIL: test_model_head1 (tests.test.ModelTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/matwey/temp/drf_test/tests/test.py", line 18, in test_model_head1
self.assertEqual(response.status_code, status.HTTP_200_OK)
AssertionError: 405 != 200

----------------------------------------------------------------------
Ran 1 test in 0.083s

FAILED (failures=1)
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&amp;cache=shared')...

# Fixed code
def as_view(cls, actions=None, **initkwargs):
    """
    Because of the way class based views create a closure around the
    instantiated view, we need to totally reimplement `.as_view`,
    and slightly modify the view function that is created and returned.
    """
    # The suffix initkwarg is reserved for identifying the viewset type
    # eg. 'List' or 'Instance'.
    cls.suffix = None

    # actions must not be empty
    if not actions:
        raise TypeError(
            "The `actions` argument must be provided when "
            "calling `.as_view()` on a ViewSet. For example "
            "`.as_view({'get': 'list'})`"
        )

    # sanitize keyword arguments
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError(
                "You tried to pass in the %s method name as a "
                "keyword argument to %s(). Don't do that." % (key, cls.__name__)
            )
        if not hasattr(cls, key):
            raise TypeError("%s() received an invalid keyword %r" % (cls.__name__, key))

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        # We also store the mapping of request methods to actions,
        # so that we can later set the action attribute.
        # eg. `self.action = 'list'` on an incoming GET request.
        self.action_map = actions

        # Bind methods to actions
        # This is the bit that's different to a standard view
        for method, action in actions.items():
            handler = getattr(self, action)
            setattr(self, method, handler)

        if hasattr(self, "get") and not hasattr(self, "head"):
            self.head = self.get

        # And continue as usual
        return self.dispatch(request, *args, **kwargs)

    # take name and docstring from class
    update_wrapper(view, cls, updated=())

    # and possible attributes set by decorators
    # like csrf_exempt from dispatch
    update_wrapper(view, cls.dispatch, assigned=())

    # We need to set these on the view function, so that breadcrumb
    # generation can pick out these bits of information from a
    # resolved URL.
    view.cls = cls
    view.initkwargs = initkwargs
    view.suffix = initkwargs.get("suffix", None)
    view.actions = actions
    return csrf_exempt(view)