DRF defines views and routes

1, Request and Response in DRF

2, APIView

APIView is the base class of all views provided by DRF, which inherits from Django's View. The difference is:

  • The incoming view method objects are different: DRF is Request and DJango is HTTPRequest
  • The DRF view method can return the Response object, and the view will render the Response data in accordance with the format of the front end
  • APIException exceptions are captured and processed as appropriate response information
  • Before dispatch() distribution, identity authentication, permission check, flow control, etc. will be performed on the request
  • API view still uses the conventional class view definition to implement the get, post and other request methods
from rest_framework import serializers
from book.models import Book,Publish

# class Publish(serializers.ModelSerializer):
#     class Meta:
#         model = Publish
#         fields = ['publish',]


class BookModelSerializer(serializers.ModelSerializer):
    # publish = Publish()
    class Meta:
        model = Book
        fields = '__all__'
# views.py
'''
List view:
    GET /books/ Provide all records
    POST /books/ Add a new record
 Detail view:
    GET /books/<str:pk>/ Provide a record
    PUT /books/<str:pk>/ Modify a record
    DELETE /books/<str:pk>/ Delete a record
    APIView + ModelSerializer
'''

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from book.models import Book
from book.serializers import BookModelSerializer

class BookListAPIView(APIView):
    """ List view """
    def get(self,request):
        '''Query all'''
        # Check all the books
        books = Book.objects.all()
        # Serialize data
        serializer = BookModelSerializer(books,many=True)
        print(serializer.data)
        res = Response(serializer.data)
        # 1) . data passed to the response object after serialization, but not yet processed by render
        print(res.data)
        # 2).status_code the number of the status code
        print(res.status_code)
        # 3) . content response data after render processing
        # print(res.content)
        # The default status code is 200
        return Response(serializer.data)
    def post(self,request):
        '''Add a new one'''
        # Get the request body data passed from the front end
        data = request.data
        # Create serializer for deserialization
        serializer = BookModelSerializer(data=data)
        # Is calling serializer_ Verify with the valid () method
        serializer.is_valid(raise_exception=True)
        # Call the save method of the serializer to execute the create method
        serializer.save()
        # response
        return Response(data=serializer.data,status=status.HTTP_201_CREATED)
class BookDetailAPIView(APIView):
    """ Detail view """
    def get(self,request,pk):
        # Query as pk model object
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            # Serialization using serializer classes
            serializer = BookModelSerializer(instance=book)
            return Response(serializer.data)
    def put(self,request,pk):
        # Model object modified to pk
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            data = request.data
            serializer = BookModelSerializer(instance=book,data=data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
    def delete(self,request,pk):
        # Model object modified to pk
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            book.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py
from django.contrib import admin
from django.urls import path
from book.views import BookListAPIView,BookDetailAPIView
from rest_framework.routers import DefaultRouter

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',BookListAPIView.as_view()),
    path('books/<str:pk>/',BookDetailAPIView.as_view())
]lo9 

# # Specify DRF modelview route
# router = DefaultRouter()
# router.register(r'api/books',BookView)
# urlpatterns += router.urls

When adding or modifying, if there is a foreign key, you need to put the associated part of the foreign key into it to add it.

3, GenericAPIView

Inherited from APIView, it mainly adds methods for operating serializers and database queries to support the execution of the following Mixin extension classes. It is often used with one or more Mixin extension classes. In addition to inheriting the three functions of APIView identity authentication, permission check and flow control, paging and filtering are also added.

3.1 GenericAPIView used alone

  • List view: self.get_queryset()
  • Detail view: self.get_object(), plus pk or other parameters
"""
Later, when facing other serialization classes and data sources, you only need to replace them step1 and step2 that will do
"""
class BookListGenericView(GenericAPIView):
    """ List view """
    # step1 specifies the serializer class
    serializer_class = BookModelSerializer
    # Step 2 specifies the query set, that is, to specify the data source
    queryset = Book.objects.all()
    # Step 3 defines the request method function
    def get(self,request):
        qs = self.get_queryset()
        serializer = self.get_serializer(qs,many=True)
        return Response(serializer.data)
    # The rest is the same as post
    
''' For the detail view, you only need to specify the of the query later pk that will do 
lookup_field = 'pk'
If you need to change the query pk Modifiable lookup_field Name the field you want to query
'''
class BookDetailGenericView(GenericAPIView):
    """ List view """
    # step1 specifies the serializer class
    serializer_class = BookModelSerializer
    # Step 2 specifies the query set, that is, to specify the data source
    queryset = Book.objects.all()
    # Step 3 defines the request method function
    def get(self,request,pk):
        book = self.get_object()
        serializer = self.get_serializer(book)
        return Response(serializer.data)
    # The rest are the same as put delete
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('books/',BookListAPIView.as_view()),
    # path('books/<str:pk>/',BookDetailAPIView.as_view()),
    path('books/',BookListGenericView.as_view()),
    path('books/<str:pk>/',BookDetailGenericView.as_view())
]

3.2 genericapiview & mixin implementation interface

It provides the implementation of the processing flow of several back-end views (deleted, modified and queried data resources). If the views to be written belong to these five kinds, the views can reuse the code by inheriting the corresponding extension classes to reduce the amount of code they write. These five extension classes need to be matched with the GenericAPIView parent class, because the implementation of the five extension classes needs to call the serializer and database query methods provided by GenericAPIView.

1)ListModelMixin

The list view extension class provides list(request, *args, **kwargs) methods to quickly implement the list view and return 200 status codes. The list method of Mixin will filter and page the data.

2)CreateModelMixin

Create the view extension class, provide the create(request, *args, **kwargs) method to quickly create the view of resources, and successfully return the 201 status code.
If the serializer fails to verify the data sent by the front end, a 400 error is returned.

3)RetrieveModelMixin

The detail view extension class provides the retrieve(request, *args, **kwargs) method, which can quickly return an existing data object. If it exists, it returns 200, otherwise it returns 404.

4)UpdateModelMixin

Update the view extension class and provide the update(request, *args, **kwargs) method, which can quickly update an existing data object. Partial is also provided_ update(request, *args, **kwargs) method can realize local update. 200 is returned successfully, and 400 error is returned when the serializer fails to verify the data.

5)DestroyModelMixin

Delete the view extension class and provide the destroy(request, *args, **kwargs) method, which can quickly delete an existing data object. 204 is returned successfully, and 404 is returned if it does not exist.

class BookListMixinGenericView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # Specifies the serializer class
    serializer_class = BookModelSerializer
    # Specify data source
    queryset = Book.objects.all()

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookDetailMixinGenericView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
    # Specifies the serializer class
    serializer_class = BookModelSerializer
    # Specify data source
    queryset = Book.objects.all()

    def get(self, request, pk):
        return self.retrieve(request, pk)

    def put(self, request, pk):
        return self.update(request, pk)

    def delete(self, request, pk):
        return self.destroy(request, pk)

3.3 ListAPIView & CreateAPIView & ListCreateAPIView ...

1)CreateAPIView

Provide post method

Inherited from: GenericAPIView, CreateModelMixin

2)ListAPIView

Provide get method

Inherited from: GenericAPIView, ListModelMixin

3)RetrieveAPIView

Provide get method

Inherited from: GenericAPIView, RetrieveModelMixin

4)DestoryAPIView

Provide delete method

Inherited from: GenericAPIView, DestoryModelMixin

5)UpdateAPIView

Provide put and patch methods

Inherited from: GenericAPIView, UpdateModelMixin

6)RetrieveUpdateAPIView

Provide get, put and patch methods

Inherited from: GenericAPIView, RetrieveModelMixin, UpdateModelMixin

7)RetrieveUpdateDestoryAPIView

Provide get, put, patch and delete methods

Inherited from: GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestoryModelMixin

class BookListMixinGenericView(ListModelMixin, CreateModelMixin, GenericAPIView):
    # Specifies the serializer class
    serializer_class = BookModelSerializer
    # Specify data source
    queryset = Book.objects.all()

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookListMixinGenericView(ListAPIView,CreateAPIView):
    # Specifies the serializer class
    serializer_class = BookModelSerializer
    # Specify data source
    queryset = Book.objects.all()

class BookListMixinGenericView(ListCreateAPIView):
    # Specifies the serializer class
    serializer_class = BookModelSerializer
    # Specify data source
    queryset = Book.objects.all()

4, View set

View set: previously, the detail view and list view were written separately, because there are two get requests (query all and single), and the view set is to unify these interfaces, write the two views to the same view class, and customize other methods

4.1 ViewSet

Using the view set ViewSet, you can put a series of logically related actions into one class:

  • list() provides a set of data
  • retrieve() provides a single piece of data
  • create() creates data
  • update() saves the data
  • Destroy() delete data

The ViewSet view set class no longer implements methods such as get() and post(), but implements action s such as list(), create().

The view set is only used in_ When using the view () method, the action action is mapped to the specific request method. For example:

class BookViewSet(ViewSet):
    """ View set: previously, the detail view and list view were written separately,
    Because there are two get Request (query all and individual), and the view set is to unify these interfaces,
    The two views are written to the same view class, and other methods can be customized """
    def list(self,request):
        # Query all
        books = Book.objects.all()
        # Query set to add many=True
        serializer = BookModelSerializer(books,many=True)
        return Response(serializer.data)
    def create(self,request):
        serializer = BookModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)
    def retrieve(self,request,pk):
        # Query objects with pk
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            serializer = BookModelSerializer(book)
            return Response(serializer.data)
    def update(self,request,pk):
        # Query objects with pk
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            # json data from the data front end
            serializer = BookModelSerializer(book, data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
    def destroy(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        if not book:
            return Response(status=status.HTTP_404_NOT_FOUND)
        else:
            book.delete()
            return Response(status.HTTP_204_NO_CONTENT)
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('books/',BookListAPIView.as_view()),
    # path('books/<str:pk>/',BookDetailAPIView.as_view()),
    # path('books/',BookListGenericView.as_view()),
    # path('books/<str:pk>/',BookDetailGenericView.as_view()),
    path('books/',BookViewSet.as_view({'get':'list','post':'create'})),
    path('books/<str:pk>/',BookViewSet.as_view({'get':'retrieve','put':'update','delete':'destory'}))
]

4.2 GenericViewSet

It is usually inconvenient to use ViewSet, because the list, retrieve, create, update, destroy and other methods need to be written by ourselves, and these methods have the same name as the methods provided by the Mixin extension class mentioned above, so we can reuse these methods by inheriting the Mixin extension class without writing by ourselves. However, the Mixin extension class depends on GenericAPIView, so it also needs to inherit GenericAPIView.

GenericViewSet helps us to complete such inheritance. It inherits from GenericAPIView and ViewSetMixin, and calls as_view() is used to transfer in the dictionary (such as {'get':'list '}). At the same time, it also provides the basic methods provided by GenericAPIView, which can be used directly with the Mixin extension class.

ModelViewSet

It inherits from GenericViewSet and includes ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin and DestoryModelMixin

ReadOnlyModelViewSet

It inherits from GenericViewSet and includes ListModelMixin and RetrieveModelMixin

class BookViewSet(ListModelMixin,RetrieveModelMixin,GenericViewSet):
# class BookViewSet(ModelViewSet):
    """ View set: previously, the detail view and list view were written separately,
    Because there are two get Request (query all and individual), and the view set is to unify these interfaces,
    The two views are written to the same view class, and other methods can be customized """
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer

class BookViewSet(ReadOnlyModelViewSet):
# class BookViewSet(ModelViewSet):
    """
        ReadOnlyModelViewSet: books/ & books/1/  get request
        ModelViewSet: books/ & books/1/  get request put delete
    """
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    """ Additional definitions none pk """
    # For the behaviors defined outside the normal addition, deletion, modification and query, a separate route should be defined for them
    # If pk is not required for this behavior, it is a list view,
    # But the list view only has list create
    # URL: path(r'books/latest/',BookViewSet.as_view({'get':'latest'}))
    """action Detailed explanation of decorator parameters
    methods: Response to this operation HTTP List of method names. Default only GET. 
    detail: Required parameters. Determines whether this action applies to the instance/Detail request or collection/List request. detail=False Not a detail view; detail=TRUE Detail view
    url_path:Define the for this operation URL Paragraph. The default is the name of the decorated method.
    url_name:Define an internal for this action(' reverse ') URL name. The default is the method name, with underscores instead of dashes.
    """
    @action(methods="get",detail=False)
    def latest(self,request):
        pass
    """ Additional definitions are pk """
    # Yes pk is the detail view
    # The details view includes: get put delete
    # URL: path(r'books/<int:pk>/latest/',BookViewSet.as_view({'get':'read'}))
    @action(methods='get',detail=True)
    def title(self, request,pk):
        book = self.get_object()
        book.title = request.data['title']
        book.save()
        # return Response(self.get_serializer(book).data)
        pass

4.3 route definition

General definition

""" Additional definitions none pk """
    # For the behaviors defined outside the normal addition, deletion, modification and query, a separate route should be defined for them
    # If pk is not required for this behavior, it is a list view,
    # But the list view only has list create
    # URL: path(r'books/latest/',BookViewSet.as_view({'get':'latest'}))

""" Additional definitions are pk """
    # Yes pk is the detail view
    # The details view includes: get put delete
    # URL: path(r'books/<int:pk>/latest/',BookViewSet.as_view({'get':'read'}))

Defaultrouter & simplerouter definition

# # Specify DRF modelview route
# This method is only suitable for use in the view set, and can only generate the five basic routes of standard addition, deletion, modification and query
# If you want the custom behavior to generate routes, you need to use the action behavior in the custom behavior and specify the corresponding request method
    """action Detailed explanation of decorator parameters
    methods: Response to this operation HTTP List of method names. Default only GET. 
    detail: Required parameters. Determines whether this action applies to the instance/Detail request or collection/List request. detail=False Not a detail view; detail=TRUE Detail view
    url_path:Define the for this operation URL Paragraph. The default is the name of the decorated method.
    url_name:Define an internal for this action(' reverse ') URL name. The default is the method name, with underscores instead of dashes.
    """
# The only difference between DefaultRouter and SimpleRouter is that DefaultRouter will generate a root route by default and SimpleRouter will not
# router = DefaultRouter()
# router.register(r'api/books',BookViewSet)
# urlpatterns += router.urls

Tags: Python Django RESTful

Posted on Sun, 10 Oct 2021 23:45:29 -0400 by pentinat