Class-Based Views

Also included are some mixins for working with Django’s Class-Based Generic Views. As they follow the existing CBV interfaces, they are compatible with existing decorators and other utilities.

At their core is the MapperMixin, which extends the :class:JsonMixin <nap.utils.JsonMixin>. This provides ways to get the mapper to use for the request, and utility functions for returning empty, single object, and multiple object responses.

Additionally it provides wrappers for these to use specific response codes, which can be configured on the class also.

Base Classes

class MapperMixin

All of the following classes are based on this.

response_class

The class to construct responses from.

Default: nap.http.JsonResponse

content_type

The default content type for responses.

Default: ‘application/json’

mapper_class

You must set this to the Mapper to use when processing requests and responses.

ok_status

Default: nap.http.STATUS.ACCEPTED

accepted_status

Default: nap.http.STATUS.CREATED

created_status

Default: nap.http.STATUS.NO_CONTENT

error_status

Default: nap.http.STATUS.BAD_REQUEST

HTTP Status codes to use for different response types.

get_mapper(obj=None)

Returns an instance of mapper_class

empty_response(**kwargs)

Returns an instance of response_class with no content.

single_response(**kwargs)

Return a response with a single object.

Will use self.object if object is not passed, or call self.get_object if self.object does not exist.

Will use self.mapper if mapper is not passed, or call self.get_mapper if self.mapper does not exist.

multiple_response(**kwargs)

Return a response with a list of objects.

Will use self.object_list if object_list is not passed, or call self.get_queryset() if self.object_list does not exist.

Will use self.mapper if mapper is not passed, or call self.get_mapper() if self.mapper does not exist.

Will apply pagination if self.paginate_by is set or self.include_meta is True.

get_meta(page)

Returns pagination metadata for paginated lists.

accepted_response(**kwargs)

Returns an empty response with self.accepted_status

created_response(**kwargs)

Returns a single response with self.created_status.

deleted_response(**kwargs)

Returns an empty response with self.deleted_status.

error_response(error)

Passes the supplied error dict through nap.utils.flatten_errors, and returns it with status=self.error_status

List Classes

class ListMixin(MapperMixin, MultipleObjectMixin)

Base list mixin, extends Django’s MultipleObjectMixin.

ok_response(**kwargs)

Calls self.list_response(status=self.ok_response)

class ListGetMixin

Provides get() for lists.

class ListPostMixin

Provides post() for lists.

post_invalid(errors)
post_valid(**kwargs)
class ListBaseView(ListMixin, View)

Single Object Classes

class ObjectMixin(MapperMixin, SingleObjectMixin)

Base single object mixin, extends Django’s SingleObjectMixin.

ok_response(**kwargs)

Calls self.single_response(status=self.ok_status)

class ObjectGetMixin

Provides get() for single objects.

class ObjectPutMixin

Provides put() for single objects.

put_valid(**kwargs)
put_invalid(errors)
class ObjectPatchMixin

Provides patch() for single objects.

patch_valid(**kwargs)
patch_invalid(errors)
class ObjectDeleteMixin

Provides delete() for single objects.

delete_valid(**kwargs)
class ObjectBaseView(ObjectMixin, View)

Example

Sample views.py that provides GET, PUT, PATCH, and DELETE methods for the Poll model:

from nap.mapper import ModelMapper
from nap.rest.views import (
    ObjectGetMixin, ObjectPutMixin, ObjectPatchMixin, ObjectDeleteMixin,
    ObjectBaseView,
)

from .models import Poll


class PollMapper(ModelMapper):
    class Meta:
        model = Poll
        fields = ['question', 'pub_date']


class PollDetailView(ObjectGetMixin,
                     ObjectPutMixin,
                     ObjectPatchMixin,
                     ObjectDeleteMixin,
                     ObjectBaseView):
    model = Poll
    mapper_class = PollMapper

Example: Updating two objects

Here’s an example of updating two related objects in a single PATCH call.

class UserDetailView(ObjectGetMixin, ObjectBaseView):
     model = User
     mapper_class = UserMapper

     def patch(self, request, *args, **kwargs):
         data = self.get_request_data({})

         self.object = user = self.get_object()

         errors = {}

         mapper = self.get_mapper(user)
         try:
             data >> mapper  # This is shorthand for _patch
         except ValidationError as e:
             errors.update(dict(e))

         profile_mapper = ProfileMapper(user.profile)
         try:
             data >> profile_mapper  # This is shorthand for _patch
         except ValidationError as e:
             errors.update(dict(e))

         if errors:
             return self.patch_invalid(errors)

         user.save()
         user.profile.save()

         return self.ok_response(object=user, mapper=mapper)

Example: Customising GET

Here’s an example of customising a GET call based on a querystring:

class QuestionListView(ListGetMixin, ListBaseView):
     model = Question
     mapper_class = QuestionMapper

     def get(self, request, *args, **kwargs):
         qset = self.get_queryset()

         # Apply filtering to get only questions for a particular poll
         poll_id = request.GET.get('poll_id')
         if poll_id:
             qset = qset.filter(poll_id=poll_id)

         self.object_list = qset
         return self.ok_response(object_list=qset)