DRF principle of APIView, GenericAPIView, GenericViewSet analysis

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:

  1. If you use a URL request router.register be registered with the binding recommended GenericViewSet, the most efficient, standardized and reasonable;
  2. If you need to reconstruct the original FBV, we recommended GenericAPIView, small changes, small changes;

 PS:

 

Guess you like

Origin www.cnblogs.com/echo1937/p/11387753.html