A hierarchy
GenericViewSet(ViewSetMixin, generics.GenericAPIView) ---DRF GenericAPIView(views.APIView) ---DRF APIView(View) ---DRF View ---Django
The first step:
# 第一阶: ViewSetMixin ViewSet(ViewSetMixin, views.APIView) GenericViewSet(ViewSetMixin, generics.GenericAPIView) ModelViewSet(mixins.{C/R/U/D/L}ModelMixin, GenericViewSet) ReadOnlyModelViewSet(mixins.{R/L}ModelMixin, GenericViewSet)
In fact, in addition to ViewSetMixin, the remaining four classes of the same order contents are empty (only PASS), ViewSetMixin increase what behavior, subsequent re-interpretation.
The second stage:
# 第二阶: GenericAPIView(views.APIView) CreateAPIView ListAPIView RetrieveAPIView DestroyAPIView UpdateAPIView ListCreateAPIView RetrieveUpdateAPIView RetrieveDestroyAPIView RetrieveUpdateDestroyAPIView
Except GenericAPIView, remaining the same order category, and substantially GenericAPIView as mixins. {CRUDL} ModelMixin composition inheritance.
In class, by overriding the appropriate HTTP method (get, put, delete, etc.), call mixis. {CRUDL} ModelView the create, list, retrieve the like.
# Concrete view classes that provide method handlers # by composing the mixin classes with the base view. class CreateAPIView(mixins.CreateModelMixin, GenericAPIView): """ Concrete view for creating a model instance. """ def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) # 以上为CreateAPIView源代码
The third stage:
# Third-order APIView (View)
APIView (View) is only the first order, a very unique position.
Fourth stage:
# 第四阶 ContextMixin View TemplateResponseMixin TemplateView(TemplateResponseMixin, ContextMixin, View) RedirectView(View)
The fourth stage is provided by Django, the more the bottom, rarely to pay attention and use, do not expand here to do a detailed analysis.
Second, the difference View, APIView, GenericAPIView, GenericViewSet of
1. Django View
If you use the built-in Django View, get a list of courses, the code looks something like this:
import json from django.views.generic.base import View from django.core import serializers from django.http import JsonResponse from .models import Course class CourseListView(View): def get(self, request): """ 通过Django的View实现课程列表页 """ courses = Course.objects.all()[:10] json_data = serializers.serialize('json', Courses) json_data =json.loads (json_data) return jsonResponse (json_data, Safe = False) # The code above uses Django own module, returns the application / json data may return the HttpResponse, which may be a subclass jsonResponse # in Django also serializers, different in the DRF serializers, it is only the basic types JSON serialization, deserialization
This is a common CBV, Django by as_view and dispatch function, the request passes the request to get (self, request) method, returning a response.
Details about this part, reference view based on the class
2. APIView
If APIView to achieve, the code looks like this:
from rest_framework.views Import APIView from rest_framework.response Import the Response from .serializers Import CourseSerializer class CourseListView (APIView): DEF GET (Self, Request, format = None): "" " implemented by APIView courses list page " "" courses = Course, .objects.all () serializer = CourseSerializer (courses, MANY = True) return the Response (serializer.data) # in APIView this case, call the drf own serializer and Response.
APIView and View differs in that:
- Request and return the DRF used
Request、
Response,
instead of DjangoHttpRequest、
HttpResponse;
- Any APIException exceptions are captured, and information into appropriate response;
- Performing dispatch () prior to distribution, will request authentication, authorization check, flow control .
Support defined attributes:
- authentication_classes lists or tuples, authentication type
- permissoin_classes list or tuple, check the permissions class
- throttle_classes lists or tuples based flow control
3. GenericAPIView
If GenericAPIView achieved, the code looks like this:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()), class BookDetailView(GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request, pk): book = self.get_object() serializer = self.get_serializer(book) return Response(serializer.data)
Because of mixins. {CRUDL} ModelMixin existence, we tend to be so written,
from rest_framework Import mixins from rest_framework Import generics class CourseListView (mixins.ListModelMixin, generics.GenericAPIView): "" " Course List " "" QuerySet = Course.objects.all () serialize_class = CourseSerializer DEF GET (Self, Request, * args , ** kwargs): # List method is present in the mixins, empathy, create, and so also, GenericAPIView none of these methods! return self.list (Request, * args, ** kwargs)
# If we are the direct successor ListAPIView (mixins.ListModelMixin, GenericAPIView), then def get (...) method can not write class CourseListView(ListAPIView): """ 课程列表页 """ queryset = Course.objects.all() serialize_class = CourseSerializer
Support defined attributes:
- queryset designated queryset
- serializer_class 指定serializer
- pagination_class specify paging class
- Filter class specified filter_backends
- Field conditions used when lookup_field query a single database object, the default is 'pk'
- The URL parameter key names, the same default with a single query data look_field when lookup_url_kwarg
The method provides:
- get_queryset(self)
- By accessing self.queryset, get queryset, both generally choose between the two;
def get_queryset(self): """ Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using `self.queryset`. This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests. You may want to override this if you need to provide different querysets depending on the incoming request. (Eg. return a list of items that is specific to the user) """ assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ ) queryset = self.queryset if isinstance(queryset, QuerySet): # Ensure queryset is re-evaluated on each request. queryset = queryset.all() return queryset
- get_serializer_class(self)
- By accessing self.serializer_class, get serializer_class, both generally choose between the two;
def get_serializer_class(self): """ Return the class to use for the serializer. Defaults to using `self.serializer_class`. You may want to override this if you need to provide different serializations depending on the incoming request. (Eg. admins get full serialization, others get basic serialization) """ assert self.serializer_class is not None, ( "'%s' should either include a `serializer_class` attribute, " "or override the `get_serializer_class()` method." % self.__class__.__name__ ) return self.serializer_class
- get_serializer(self, args, *kwargs)
- If we are in View, you want to get serializer instance, you can call this method directly.
- get_serializer_context(self)
- Create request, format, view data object is three, when a context attribute serializer instantiation;
def get_serializer(self, *args, **kwargs): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. """ serializer_class = self.get_serializer_class() kwargs['context'] = self.get_serializer_context() return serializer_class(*args, **kwargs) def get_serializer_context(self): """ Extra context provided to the serializer class. """ return { 'request': self.request, 'format': self.format_kwarg, 'view': self }
- get_object(self)
- The method queryset filtering operation, the return obj view for display. If you need non-standard filter operation, you can override this method;
def get_object(self): """ Returns the object the view is displaying. You may want to override this if you need to provide non-standard queryset lookups. Eg if objects are referenced using multiple keyword arguments in the url conf. """ queryset = self.filter_queryset(self.get_queryset()) # Perform the lookup filtering. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field assert lookup_url_kwarg in self.kwargs, ( 'Expected view %s to be called with a URL keyword argument ' 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 'attribute on the view correctly.' % (self.__class__.__name__, lookup_url_kwarg) ) filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} obj = get_object_or_404(queryset, **filter_kwargs) # May raise a permission denied self.check_object_permissions(self.request, obj) return obj
- filter_queryset()
- The filter filter_backends classes, applied to the QuerySet;
def filter_queryset(self, queryset): """ Given a queryset, filter it with whichever filter backend is in use. You are unlikely to want to override this method, although you may need to call it either from a list view, or from a custom `get_object` method if you want to apply the configured filtering backend to the default queryset. """ for backend in list(self.filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) return queryset
4. GenericViewSet
GenericViewSet (ViewSetMixin, generics.GenericAPIView), in fact, equal
ViewSetMixin + GenericAPIView
, but the main work ViewSetMixin, is to rewrite as_view method.
class ViewSetMixin(object): """ This is the magic. Overrides `.as_view()` so that it takes an `actions` keyword that performs the binding of HTTP methods to actions on the Resource. For example, to create a concrete view binding the 'GET' and 'POST' methods to the 'list' and 'create' actions... view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) """
We look back, these different views in an web request, as_view CBV and methods (get, put, post, etc.) of the work are different ways:
View:
- URL mapping to the CBV as_view method by calling the dispatch method, is responsible for mapping between the HTTP request and CBV methods (POST to post, GET to get, PUT to put);
APIView:
- Ditto
GenericAPIView:
- Supra, except that by mixin. {CRUDL} ModelMixin introduced the concept of the action, can be manually or automatically in the get / put / post or the like call list / create / retrieve like action
GenericViewSet
- As_view rewrite method, supports similar MyViewSet.as_view ({ 'get': ' list', 'post': 'create'}) the dynamic binding function, or registered by the router.register;
how to choose:
- If you use a URL request router.register be registered with the binding recommended GenericViewSet, the most efficient, standardized and reasonable;
- If you need to reconstruct the original FBV, we recommended GenericAPIView, small changes, small changes;