The main role of the views provided by Django REST framwork:
1. Control the execution of the serializer (check, save, transform data)
2. Control the execution of database queries
One, two view base classes
Conclusion first:
APIView: if followed by models No relationship (no database related operations), just inherit it GenericAPIView: For database operations, queryset and serializer_class
1.APIView
Inheriting the View of native Django, we need to write the code corresponding to the request method ourselves, such as
class BookAPIView(APIView): def get(self, request): book_list = models.Book.objects.all() ser = serializer.BookModelSerializer(book_list, many=True) return Response(ser.data) def post(self, request): ser = serializer.BookModelSerializer(data=request.data) if ser.is_valid(): ser.save() return Response(ser.data) return Response(ser.error) class BookDetailAPIView(APIView): def get(self, request, pk): book = models.Book.objects.get(id=pk) ser = serializer.BookModelSerializer(book) return Response(ser.data) def put(self, request, pk): book = models.Book.objects.get(id=pk) ser = serializer.BookModelSerializer(book, data=request.data) if ser.is_valid(): ser.save() return Response('Successfully modified') def delete(self, request, pk): models.Book.objects.filter(id=pk).delete() return Response('successfully deleted')
2.GenericAPIView
Inheriting APIView, considering that when using APIView, when we write multiple classes, the only changed code is the called myserializers class and its own table model, so the variables are extracted.
queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer get_queryset: get configured queryset get_object: Used when querying a single record, the grouping field in the route must be pk get_serializer: Get the serialization class of the configuration
class BookGenericView(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer def get(self, request, *args, **kwargs): obj = self.get_queryset() ser = self.get_serializer(obj, many=True) return Response(ser.data) def post(self, request, *args, **kwargs): ser=self.get_serializer(data=request.data) if ser.is_valid(): ser.save() return Response('success') class BookDetailGenericAPIView(GenericAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer def get(self, request, *args, **kwargs): obj = self.get_object() ser = self.get_serializer(obj) return Response(ser.data) def put(self, request, *args, **kwargs): obj = self.get_object() ser = self.get_serializer(obj, data=request.data) if ser.is_valid(): ser.save() return Response('Successfully modified') def delete(self, request, *args, **kwargs): # self.get_object().delete() or the method below self.queryset.filter(id=kwargs.get('pk')).delete() return Response('successfully deleted')
Two, five view extension classes
When we use the GenericAPIView class to extract the variables, we will find that we actually have the same internal code for different interfaces, so we encapsulate it, that is, extract each request method and encapsulate it into a separate class.
from rest_framework.mixins import ... CreateModelMixin: create method to create a DestroyModelMixin: destory method to delete ListModelMixin: list method to get all RetrieveModelMixin: retrieve get one UpdateModelMixin: update modify one
class BookGenericView(GenericAPIView,ListModelMixin,CreateModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) class BookDetailGenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs): return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs)
Three, nine subclass views
The subclass view is a further encapsulation of the extension class, because we still have repeated code in the previous part. Since these request methods come in, the execution logic is the same, so I will further encapsulate it.
Five extension classes, divided into group get, post, single get, put, delete. In our common classes, there are generally one class for group get, one class for post, and one class for the other three methods, so they are combined together, there are exactly nine sub-class views, namely 2+1, 3+2+1, and there are nine combinations in total.
#9 subclassed views (rest_framework.generics) CreateAPIView:inherit CreateModelMixin,GenericAPIView,Have post method, add data DestroyAPIView: inherit DestroyModelMixin,GenericAPIView,Have delete method, delete data ListAPIView: inherit ListModelMixin,GenericAPIView,Have get method to get all UpdateAPIView: inherit UpdateModelMixin,GenericAPIView,Have put and patch method, modify data RetrieveAPIView: inherit RetrieveModelMixin,GenericAPIView,Have get method to get a ListCreateAPIView: inherit ListModelMixin,CreateModelMixin,GenericAPIView,Have get get all, post method added RetrieveDestroyAPIView: inherit RetrieveModelMixin,DestroyModelMixin,GenericAPIView,Have get method to get one, delete method delete RetrieveUpdateAPIView: inherit RetrieveModelMixin,UpdateModelMixin,GenericAPIView,Have get get one, put,patch Revise RetrieveUpdateDestroyAPIView: inherit RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,Have get get one, put,patch Revise, delete delete
The following is the most complete way. The nine subclass views are more flexible and can be combined arbitrarily.
from rest_framework.generics import ListCreateAPIView from rest_framework.generics import RetrieveUpdateDestroyAPIView class BookGenericView(ListCreateAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer class BookDetailGenericAPIView(RetrieveUpdateDestroyAPIView): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer
Fourth, the view set
When we have encapsulated the subclass view, we will find that the repetition of the code has appeared again. The two classes we wrote above actually have the same code, so they have been encapsulated again. In general, we use ModelViewSet or ReadOnlyModelViewSet, but the view set contains more than these two.
from rest_framework.viewsets import ModelViewSet # Contains five request methods from rest_framework.viewsets import ReadOnlyModelViewSet # Only query, single record query and group query class BookSetView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer
1. ViewSet
Inherited from APIView and ViewSetMixin, the function is basically similar to APIView, providing identity authentication, permission verification, traffic management, etc.
ViewSet mainly implements the mapping processing of incoming dictionaries (such as {'get':'list'}) when calling as_view() by inheriting ViewSetMixin.
In ViewSet, no action method is provided, and we need to implement the action method ourselves.
2.GenericViewSet
It is usually inconvenient to use ViewSet, because methods such as list, retrieve, create, update, and destroy all need to be written by yourself, and these methods have the same name as the methods provided by the Mixin extension class mentioned above, so we can duplicate the method by inheriting the Mixin extension class. Use these methods without writing your own. But the Mixin extension class depends on GenericAPIView, so it also needs to inherit GenericAPIView.
GenericViewSet helps us complete such inheritance work. It inherits from GenericAPIView and ViewSetMixin. While implementing the mapping processing of incoming dictionaries (such as {'get':'list'}) when calling as_view(), it also provides The basic methods provided by GenericAPIView can be used directly with the Mixin extension class.
Example:
from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer
definition of url
urlpatterns = [ path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})), re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})), ]
3.ModelViewSet
Inherited from GenericViewSet, including ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestoryModelMixin.
4.ReadOnlyModelViewSet
Inherited from GenericViewSet, including ListModelMixin and RetrieveModelMixin.
5. Source code analysis
The ViewSet view set class no longer implements get(), post() and other methods, but implements action s such as list(), create() and so on. Because we have now encapsulated all actions, there will be problems when single get and group get requests, because both are get requests, and the requests are sent to the same class. Here, the framework author uses it very cleverly. method to solve this problem. The solution is to match the corresponding method in the routing. code show as below
path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'})), re_path('^books_set/(?P<pk>\d+)', views.BookSetView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
The as_view method in the native class definitely does not support this approach, so the ModelViewSet must override the as_view() method
Five, the use of routing
Generally, if the view class of drf is used, it will be used together with the routing component, because the routing component can help us automatically generate the routing path
1. Simple use of routing components
# Automatically generate routes, the following two are used more SimpleRouter and DefaultRouter # The view class that inherits ViewSetMixin, and writes routing later, can be automatically generated and written in urls.py from rest_framework import routers # instantiate an object router = routers.SimpleRouter() # Register into the route router.register('books', views.BookSetView) # Configure the automatically generated route to urlpatterns -urlpatterns += router.urls # or the following way -re_path(r'v1/', include(router.urls)) # The v1 here refers to adding the v1 path before the generated path, such as the original login, now it becomes v1/login
2. How to configure routing
# three ways 1.most primitive -path('books/', views.BookAPIView.as_view()), 2.ViewSetMixin view class -path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'})) 3.ViewSetMixin view class -Automatically generated, as mentioned above
3.action
-When the route is automatically generated, because there are other methods in the view class, the route cannot be automatically generated. -add action Decorator: -methods: What request method will trigger the execution of the decorated function -detail: Yes True is based on the belt id generated by the route, if it is False,is based on not having id generated by the route -@action(methods=['get'], detail=True)