Use of importlib, 9 view subclasses, viewset, drf route, drf request response review, GenericViewSet related flow chart

A review of drf request response

# 1 drf request
-Request object: data, query_params, others are the same as before, FILES
    -Default: supports three encodings
    -Local configuration: in view class
        -from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
        -parser_classes=[JSONParser]
            
        -Global configuration:
        REST_FRAMEWORK = {<!-- -->
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser'
        ],
}
        
        - Use it globally, change it locally---》Just change the view class
        
# 2 drf response
-Response ---》Must inherit django’s native HTTPResponse
      -data: dictionary, list, string, assign empty value to it---》http response body
      -status:http response status code from rest_framework import status
      -headers: response headers
         res=HttpResponse() res=render() res=redirect() res=JsonResponse() One of the four-piece set
            res['name']='lin' #Put it in the response header
            return res
     -Response encoding format---》Generally does not move

# 3 Two view base classes
-APIView---》Write 5 interfaces
    -GenericAPIView inherits from APIView---》Use it when dealing with the database and serializing in the future.
    ### Important attributes###
    -queryset: Put all the data queried from a certain table in the future
        -serializer_class: the class to be serialized
        
        ### Important methods###
        -get_queryset: all data to be serialized, qs object
        -get_serializer: serialization class
        -get_object: modify, query, delete a single item
        
        
# 4 5 view extension classes
    RetrieveModelMixin,
    CreateModelMixin,
    DestroyModelMixin,
    ListModelMixin,
    UpdateModelMixin

Two 9 view subclasses

from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView
from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView

# If you want to write one, some, or all of the five interfaces in the future, you only need to choose to inherit from different classes. You only need to configure two class attributes in the class.
queryset = Publish.objects.all()
    serializer_class = PublishSerializer

1 View class

#1 I want to write publish: query all, query a single item, modify an item, add an item, delete an item interface
class PublishView(ListCreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer


class PublishDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

#2 Want to write publish: Query a single item, add one, the interface ---> use 9 view subclasses to write
class PublishView(CreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer


class PublishDetailView(RetrieveAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

#3 Want to write publish: Query a single item, add one, the interface ---> use 5 view extension classes + GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def post(self,request,*args,**kwargs):
        return self.create(request,*args,**kwargs)
class PublishDetailView(GenericAPIView,RetrieveModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def get(self,request,*args,**kwargs):
        return self.retrieve(request,*args,**kwargs)

2 Routing

path('publish/', PublishView.as_view()),
path('publish/<int:pk>', PublishView.as_view()),

Three views

1 ModelViewSet

# 1 As long as the view class inherits it and changes the routing method, 5 interfaces will be available.
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    
    
path('publish/', PublishView.as_view({<!-- -->'get':'list','post':'create'})),
path('publish/<int:pk>', PublishView.as_view({<!-- -->'get':'retrieve','put':'update','delete':'destroy'})) ,

1.1 ModelViewSet source code analysis

# Query all interfaces
-get--list----》Get all data, serialize--return
    
# Add a new item
-post---create---》The new code we wrote before is the same
    
    
    
# Why does get become a list?
# Why post becomes create

2 ViewSetMixin

# Never seen
# ViewSetMixin has been decided, and the way to write routes will change in the future.
-path('publish/', PublishView.as_view({<!-- -->'get':'list','post':'create'}))
    -path('publish/', PublishView.as_view({<!-- -->'get':'lqz'}))
    
# Source code analysis
-class GenericViewSet(ViewSetMixin, generics.GenericAPIView): ViewSetMixin must be placed in front--" Ensure that the executed as_view is ViewSetMixin
        
    -The request comes and the route is matched successfully---》Execute view(request) in as_view of ViewSetMixin
        def view(request, *args, **kwargs):
            self = cls(**initkwargs) # Get the object from class instantiation--"Whose object is self?" PublishView
            self.action_map = actions # {'get':'list','post':'create'}
            # method:get
            # action: list
            for method, action in actions.items():
                # list method
                handler = getattr(self, action) #Reflection list in PublishView object, got it
                # Reflection setting value
                #setattr (object of PublishView view class, get, list methods)
                # There will be a get method in the object of the PublishView view class, which is list
                setattr(self, method, handler)
            return self.dispatch(request, *args, **kwargs)
# Summarize:
-Configure like this in routing: PublishView.as_view({<!-- -->'get':'list','post':'create'})
    -After the get request comes in, what is essentially executed is the list method in the view class.

2.1 In the future, the method names in the view class can be named arbitrarily, as long as the routing is properly mapped

# The inherited class is: as long as you inherit ViewSetMixin, you can name the methods in the view class arbitrarily, and the routing writing method can be changed.

3 ReadOnlyModelViewSet

# The interface to be written in the future only wants to get a single item and get all, inherit it.

4 Summary of classes in the view layer

# 1 Two view base classes
-APIView and GenericAPIView
    -APIView execution process: wraps new, handles csrfrequeset, performs three major authentications, and handles global exceptions
    -GenericAPIView: If you want to serialize and deal with the database, just inherit it directly.
    -queryset
        -serializer_class
        
        -get_object
        -get_queryset
        -get_serializer
        
        
# 2 5 view extension classes (not view classes), which require GenericAPIView to be used
-Quickly use 5 interfaces
    - Certain interfaces: Query a single item, add one, interface ---> use 5 view extension classes + GenericAPIView
    class PublishView(GenericAPIView,CreateModelMixin)
        queryset=Publish.objects.all()
        serializer_class=Serializer class
            def post(self,request)
            return self.create(request)
        class PublishDetailView(GenericAPIView,RetrieveModelMixin)
        queryset=Publish.objects.all()
        serializer_class=Serializer class
            def get(self,request)
            return self.retrieve(request)
            
            
# 3 9 view subclasses (a combination of inheriting GenericAPIView + 5 view extension classes)
ListAPIView, CreateAPIView
    ListCreateAPIView
    
RetrieveAPIView, DestroyAPIView, UpdateAPIView
RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
    
    
#4 Viewset
-ModelViewSet:
    -ViewSetMixin + GenericAPIView + 5 view extension classes
        -GenericViewSet + 5 view extension classes
        
    -ViewSetMixin source code: Routing mapping configuration, the methods in the view class can be named casually in the future
    -Viewset: ViewSetMixin + APIView---》No need for serialization, the routing writing method has changed
    -GenericViewSet: ViewSetMixin + GenericAPIView--》Needs serialization, needs to use database, routing writing method changes
    -ReadOnlyModelViewSet: list and retrieve

Four drf reasons

#Previous routing writing method:
path('books/', BookView.as_view())
    
# Once you inherit ViewSetMixin in the future, it will become path('publish/', PublishView.as_view({'get': 'list', 'post': 'create'}))

# It may be a bit troublesome to write and map like this, so drf helps us encapsulate two routing classes ---" can help us quickly generate the mapping relationship we wrote before


###### Must inherit ViewSetMixin + APIView and its subclasses to automatically generate SimpleRouter DefaultRouter

## Automatically generate routes: automatic mapping is as follows:
{<!-- -->'get': 'list', 'post': 'create'}
{<!-- -->'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}


## Others-->There are other methods in the view class. If we want to map, we need to use a decorator.

How to use

# Major premise: You must inherit ViewSetMixin + APIView and its subclasses to automatically generate
####Steps for usage
# urls.py
#### 1 Import routing class
from rest_framework.routers import SimpleRouter, DefaultRouter
#### 2 Class instantiation to get the object
router = SimpleRouter()
#### 3 Automatically generate routes, call a certain method of the object, complete the corresponding relationship with the view class, and map the route
router.register('publish', PublishView, 'publish')
# router.register('books', BookView, 'books') # You can register more later
router.register('user',UserView,'user')
##### 4 Add the automatically generated route to the total route
urlpatterns = urlpatterns + router.urls # Add the two lists directly

### The fourth step can be written like this
path('api/v1/', include(router.urls)), # http://127.0.0.1:8008/api/v1/user/register/--->post

1 SimpleRouter, DefaultRouter

The difference between SimpleRouter and DefaultRouter
The path generated by -DefaultRouter has one more root path api-root
    -DefaultRouter will come with a default API root view and return a hyperlink response data containing all list views.
Use it from now on: SimpleRouter will do

2 action decorator

# Function: Map paths for methods in view classes
-These methods need to exclude 5: create, list, destroy, update, retrieve
    
# Usage
    @action(methods=['POST'],detail=False)
    def register(self, request):
        return Response('register')
# Automatic generated:
http://127.0.0.1:8008/user/register/---->post--->will execute register
# action parameters
-methods request method, you can write multiple
    -detail: Whether there is an ID number in the path
    http://127.0.0.1:8008/user/register/ # detail=False
        http://127.0.0.1:8008/user/4/register/ # detail=True



************************* Code display************************ **********
-1.Routing
from django.contrib import admin
from django.urls import path
from app01.views import UserView

# 1. Import routing class
from rest_framework.routers import SimpleRouter, DefaultRouter
# 2. Class instantiation to obtain the object
router = SimpleRouter()
# 3. Automatically generate routes, call a certain method of the object, complete the corresponding relationship with the view class, and map the route
router.register('user', UserView, 'user')

urlpatterns = [
    path('admin/', admin.site.urls),
    # Access login/path post request will execute the register method in UserView
    path('register/', UserView.as_view({<!-- -->'post': 'register'})),

]

urlpatterns + = router.urls



-2.View function
from rest_framework.decorators import action


class UserView(GenericViewSet):
    # http://127.0.0.1:8000/user/register/ ----> post -----> is to execute register
    # url_path is the name after the path. If not written, the method name will be used as the path.

    # @action(methods=['POST'], detail=False, url_path='reg')
    # methods request method
    # detail whether to include id

    # @action(methods=['POST'], detail=False)
    @action(methods=['POST'], detail=True)
    # def register(self, request):
    # http://127.0.0.1:8000/user/2/register/
    def register(self, request, pk):
        print(pk)
        # self.get_queryset()
        return Response('register')

3 In the future, inheriting ModelViewSet may also override many methods

#### Rewrite list
class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def list(self, request, *args, **kwargs): # We may rewrite the list in the future and make our own customizations
        res=super().list(request, *args, **kwargs)

        return Response({<!-- -->'code':100,'msg':'success','result':res.data})
    
    
### Override get_serializer_class
def get_serializer_class(self): # It is a method in the GenericAPIView class. Whatever is returned, the serialization class will be used to continue the operation in the future.
    print(self.action)
    if self.request.method=='POST':
        return WritePublishSerializer
    else:
        return self.serializer_class

    
### Override perform_create
def perform_create(self, serializer):
    serializer.save()


### Use PublishSerializer for serialization and WritePublishSerializer for deserialization.

4 Action parameters in the object of the view class

print(self.action)
# There is an action attribute in the object of the view class---》It is the string of the method name executed by the current request.

# Through action, you can limit which serialization class is used by a method in the view class.

Usage of importlib

`importlib` is a module in the Python standard library. It provides a way to dynamically import modules and obtain module information.
Allows you to load, import, and use Python modules at runtime. This is useful for writing scalable, flexible code and plugin systems.

Here are some common usage examples of the `importlib` module:

1. **Dynamic import module**:
   import importlib

   # Dynamically import modules
   module_name = "my_module"
   my_module = importlib.import_module(module_name)

   # Use dynamically imported modules
   result = my_module.my_function()

2. **Import objects from modules**:
   import importlib

   # Dynamically import modules
   module_name = "my_module"
   my_module = importlib.import_module(module_name)

   #Import objects from modules
   my_function = getattr(my_module, "my_function")

   # Use imported objects
   result = my_function()

3. **Reload module**:
   import importlib

   # Dynamically import modules
   module_name = "my_module"
   my_module = importlib.import_module(module_name)

   # Reload module
   my_module = importlib.reload(my_module)

4. **Get the file path of the module**:
   import importlib

   # Dynamically import modules
   module_name = "my_module"
   my_module = importlib.import_module(module_name)

   # Get the file path of the module
   module_path = my_module.__file__


These examples demonstrate how to use `importlib` to dynamically import modules, import objects from modules,
Reload the module and get the module's file path.
These features can be used for building plug-in systems, modular applications, and dynamically loaded modules.

5. GenericViewSet related flow chart

1.GenericViewSet inheritance flow chart

2.minix and GenericViewSet flow chart

3.Flow chart of the relationship between minix and GenericViewSet

6. rest_framework map