DRF view and routing

View of DRF

APIView

When we write CBV in django, we inherit View and rest_ The framework inherits APIView, so what's the difference between them~~~

urlpatterns = [     url(r'^book$', BookView.as_view()),     url(r'^book/(?P<id>\d+)$', BookEditView.as_view()), ]

We can see that both view and APIView call as at the beginning_ View () method ~ ~ let's go into the source code and have a look~~

We can see that APIView inherits view and executes as in view_ View () method, and finally return the view, using csrf_ The exempt () method removes the csrf authentication after wrapping.

Let's look at as in View_ What does the View () method do~

We see ~ as in view_ The view method returns the view function, which executes self Dispatch () method ~ ~ but the dispatch method here should be in our APIView~~

Let's go initialize_ In request, see what is assigned to request and self Request, that is, the request we use in the view What is XXX~~

We see that this method returns the instance object of the request class ~ ~ let's notice that the first parameter request in the request class is the original request when we left django~

As we can see, this request class assigns the original request to self_ Request, which means later_ Request is our old request, and the new request is our request class~~

Where are the requested data after we inherit APIView~~

We used rest_ After the framework, our request is a re encapsulated request class~

request.query_params stores the parameters of our get request

request.data stores all our data, including post requests, put and patch requests~~~

Compared with the original django request, our current request is more concise and clear~~~

Now we know some differences between APIView and View ~ ~ of course ~ ~ we'll talk about it later~~

The view we write may add, delete, modify and query multiple tables, resulting in a lot of duplicate code in our view~~

So let's try to encapsulate it~~

First packaging

class BookView(APIView):
    def get(self, request):
        book_queryset = models.Book.objects.all()
        # Serialize with serializer
        ser_obj = BookSerializers(book_queryset, many=True)  # many=True You can put more than one
        return Response(ser_obj.data)

    def post(self, request):
        book_obj = request.data
        ser_obj = BookSerializers(data=book_obj)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)

class BookEditView(APIView):
    
    def get(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # ser_obj = BookSerializer(book_obj)
        # return Response(ser_obj.data)
       
    
    def put(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
        # if ser_obj.is_valid():
        #     ser_obj.save()
        #     return Response(ser_obj.validated_data)
        # return Response(ser_obj.errors)
        

    def delete(self, request, id):
        # book_obj = Book.objects.filter(id=id).first()
        # if not book_obj:
        #     return Response("The deleted object does not exist")
        # book_obj.delete()
        # return Response("")
        
class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class ListModelMixin(object):
    def list(self, request, *args, **kwargs):
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class CreateModelMixin(object):
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)


class RetrieveModelMixin(object):
    def retrieve(self, request, id, *args, **kwargs):
        book_obj = self.get_queryset().filter(pk=id).first()
        book_ser = self.get_serializer(book_obj)
        return Response(book_ser.data)


class UpdateModelMixin(object):
    def update(self, request, id, *args, **kwargs):
        book_obj = self.get_queryset().filter(pk=id).first()
        book_ser = self.get_serializer(book_obj, data=request.data, partial=True)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.validated_data)
        else:
            return Response(book_ser.errors)


class DestroyModelMixin(object):
    def destroy(self, request, id, *args, **kwargs):
        queryset = self.get_queryset()
        try:
            queryset.get(pk=id).delete()
            return Response("")
        except Exception as e:
            return Response("Incorrect information")
# We take out the public part, so that no matter how many tables are written, the addition, deletion, modification and query will become very simple
# After such encapsulation, our view will become like this

class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    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 BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

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

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

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

First packaging

The GenericAPIView we encapsulated, including the classes that encapsulate each method, is actually encapsulated by the framework~~

We can directly inherit these classes ~ ~ to implement the above view ~ ~ but is there a simpler method ~ let's encapsulate it again~~

Second packaging

from django.shortcuts import render
from app01 import models
from rest_framework.views import APIView
from .serializers import BookSerializers
from rest_framework.response import Response
from rest_framework.viewsets import ViewSetMixin
from rest_framework import viewsets


class CreateModelMIxin(object):
    # New method of separate extraction post
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)


class ListModelMixin(object):
    # Separate and query all get methods
    def list(self, request):
        quertset = self.get_queryset()
        ser_obj = self.get_serializer(quertset, many=True)
        return Response(ser_obj.data)


class GenericAPIView(APIView):
    queryset = None
    serializer_class = None

    def get_queryset(self):
        return self.queryset.all()

    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)


class ListCreateAPIView(GenericAPIView, CreateModelMIxin, ListModelMixin):
    pass


class BookView(ListCreateAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializers

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

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


class RetrieveModelMixin(object):
    # get method of extracting and querying a single item separately
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)


class UpdateModelMixin(object):
    # Separate extraction method
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)


class DestroyModelMixin(object):
    # Separate extract delete method
    def destroy(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        if not book_obj:
            return Response('Deleted object does not exist')
        book_obj.delete()
        return Response("")


class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass

class BookEditView(RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializers

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

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

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

This time we just made inheritance a little easier. It seems that there is no big progress~~

Can we combine these two views into one view ~ ~ ~ the framework provides us with a method of routing parameters~~

Let's take a look at ViewSetMixin

The default parameter of actions is actually that we can transfer parameters through the route~~~

The following loop ~ can be seen ~ the parameter we want to pass is a field ~ key should be our request method, and value should correspond to the method we process~

In this way, we don't have to write functions in each view ~ because they correspond to the functions implemented internally~

Third packaging

urlpatterns = [
    # path('book_list/', views.BookView.as_view()),
    # re_path(r'book_list/(?P<id>\d+)', views.BookEditView.as_view()),
    re_path(r'^book_list/', views.BookModelView.as_view({"get": "list", "post": "create"})),
    re_path(r'^book_list/(?P<pk>\d+)',
            views.BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),

]
from rest_framework.viewsets import ViewSetMixin


# class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
#     queryset = Book.objects.all()
#     serializer_class = BookSerializer
    
    
# If we define another class
class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    pass


class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

Third packaging

 

We only need to write two lines for the current view~~~

In fact, all the view ~ frameworks we wrote have been encapsulated for us~

Note that ~ ~ the view encapsulated by the framework ~ the keyword parameter on our url should be pk ~ ~ the system default~~

Give a picture to see our succession order~~~

DRF routing

We have a lot of routing parameters written above ~ ~ the framework has also been encapsulated for us~

from django.urls import path, include, re_path
from SerDemo import views
# Help us generate routes with parameters
from rest_framework.routers import DefaultRouter

# Instantiate DefaultRouter()
router = DefaultRouter()
# Register our routes and views
# router.register('book_list', views.BookModelView)

urlpatterns += router.urls

 

We can see that ~ ~ through the framework, we can make the routing view very simple~~

But when we need to customize, we still need to write it with APIView ~ ~ when we don't need so many routes ~ don't register with this route~~

In short ~ ~ use everything according to business needs ~ ~ ~

Tags: Django

Posted by matfish on Tue, 10 May 2022 01:53:42 +0300