drf’s view subclasses, viewsets, and routing

1 9 view subclasses

The 9 view subclasses are a combination of GenericAPIView and 5 view extension classes

Import through from rest_framework.generics import , and when writing a view class, you only need to inherit the view subclass

  1. ListAPIView, only used to display all
  2. CreateAPIView, add a
  3. ListCreateAPIView, display all and add one
  4. RetrieveAPIView, displays a
  5. DestroyAPIView, delete an item
  6. UpdateAPIView, modify one item
  7. RetrieveUpdateDestroyAPIView, display, modify and delete an item
  8. RetrieveDestroyAPIView, display one item and delete one item
  9. RetrieveUpdateAPIView, display one item and modify one item

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.

1.1 View class

I want to write publish: an interface to query all, query a single item, modify an item, add an item, and delete an item.

class PublishView(ListCreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer


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

1.2 Routing

The routing has not changed

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

2 Viewset

Integrate views using the same library and serialization classes

2.1 ModelViewSet

View function
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialize
Routing
path('publish/', PublishView.as_view({<!-- -->'get':'list','post':'create'})),
path('publish/<int:pk>', PublishView.as_view({<!-- -->'get':'retrieve','put':'update','delete':'destroy'})) ,

2.1.1 ModelViewSet source code analysis

  1. There are query interfaces for all
    get–list—-》Get all data, serialize–return

  2. Add a new item
    post-create-》The new code we wrote before is the same

2.2 ViewSetMixin

ModelViewSet inherits five view extension classes and GenericViewSet. GenericViewSe inherits ViewSetMixin, which overrides as_view()

ViewSetMixin has been decided, and the way to write routes will change in the future.

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)
Summary

The routing is configured like this: PublishView.as_view({'get':'list','post':'create'})
In the future, when a get request comes in, what is essentially executed is the list method in the view class.

2.2.1 Write custom methods in the view class

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

from rest_framework.viewsets import ViewSetMixin,ViewSet

The inherited class is: as long as you inherit ViewSetMixin, you can name the methods in the view class arbitrarily and change the routing writing

  1. ViewSetMixin + APIView = ViewSet
    If there is no table related, just use ViewSet
  2. GenericViewSet + ViewSetMixin = ModelViewSet
    If it is related to tables, use ModelViewSet
View class
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

    def book(self, request):
        return Response('from book')
Routing
path('book/', UserView.as_view({<!-- -->'post': 'login'}))
Access address

2.3 ReadOnlyModelViewSet

from rest_framework.viewsets import ReadOnlyModelViewSet

The interfaces written in the future only want to get a single item and get all, so inherit it.

2.4 Summary of classes in the view layer

1 Two view base classes

APIView and GenericAPIView

  1. Execution process of APIView:
    Wrapping new ones, processing csrfrequeset, performing three major authentications, and handling global exceptions
  2. GenericAPIView
    If you want to do serialization and deal with the database, just inherit it directly.
    1. Class attributes queryset, serializer_class
    2. Methods get_object, get_queryset, get_serializer
2 5 view extension classes (not view classes)

Requires GenericAPIView to use

  1. RetrieveModelMixin
    To query an item, I wrote a method retrieve. The code is the same as the content of the get method we wrote before.
  2. CreateModelMixin
    To add a new post, write a method create. The code is the same as the content of the new post method we wrote before.
  3. DestroyModelMixin
    To delete an item, a method destroy is written. The code is the same as the delete method we wrote before to delete an item.
  4. ListModelMixin
    A method list is written to query all. The code is the same as the content of the get method we wrote before to query all
  5. UpdateModelMixin
    Modify one and write a method update. The code is the same as the content of the put method we wrote and modified before.
3 9 view subclasses

A combination of inheriting GenericAPIView + 5 view extension classes
Reference 1

ViewSet
  1. ModelViewSet:
    ViewSetMixin + GenericAPIView + 5 view extension classes
    GenericViewSet + 5 view extension classes

  2. 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

3 Routing

It may be a bit troublesome to write and map the previous routes, so drf helped us encapsulate two routing classes -” which can help us quickly generate the mapping relationships we wrote before

Condition: Must inherit ViewSetMixin + APIView and its subclasses to automatically generate

Automatically generate routes: Automatic mapping is as follows:

{get’: list’, post’: create’}
{get’: retrieve’, put’: update’, delete’: destroy’}

3.1 How to use

Major premise: the view class must inherit ViewSetMixin + APIView and its subclasses to be automatically generated

Steps for usage

#### 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('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, in urlpatterns
#Add prefix to route
path('api/v1/', include(router.urls)),
# http://127.0.0.1:8008/api/v1/user/register/--->post

3.2 SimpleRouter, DefaultRouter

The difference between SimpleRouter and DefaultRouter

  1. The path generated by DefaultRouter has one more root path api-root
  2. 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

3.3 action decorator

Write a custom method in the view class, roughly implemented as 2.2.1
The routing does not need to change, define it in the view class and use the action decorator

How to use
from rest_framework.decorators import action
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

@action(methods=['POST'], detail=False)
def register(self, request):
back_dic = {<!-- -->'code': 200, 'msg': "Registration successful"}
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(back_dic)
else:
return Response({<!-- -->'code': 200, 'msg': ser.errors})
Access address

The register method can be used through a specific access address and the post method.
where user is the address using this class

action parameters
  1. methods: Request method, you can write multiple
  2. 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

3.4 Rewriting method

In the future, if you inherit ModelViewSet, you may also override many methods.

Rewrite list
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

# In the future, we may rewrite the list and make our own customizations.
    def list(self, request, *args, **kwargs):
        res = super().list(request, *args, **kwargs)
        return Response({<!-- -->'code': 200, 'msg': 'View all users successfully', 'result': res.data})
Rewrite get_serializer_class

It is a method in the GenericAPIView class. Whatever it returns, the serialization class will be used to continue the operation in the future.

class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

    def get_serializer_class(self, *args, **kwargs):
        if self.action == 'login':
            return LoginSerializer
        else:
            return self.serializer_class
    
    @action(methods=['POST'], detail=False)
    def login(self, request):
        back_dic = {<!-- -->'code': 200, 'msg': "Login successful"}
        
        # Use serialization class
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            for i in self.get_queryset():
                if i.username == ser.data.get('username') and i.password == ser.data.get('password'):
                    return Response(back_dic)

            back_dic['code'] = 1002
            back_dic['msg'] = "User password is wrong"
            return Response(back_dic)
        else:
            return Response({<!-- -->'code': 200, 'msg': ser.errors})

Rewrite perform_create

Before saving the data, do some operations, such as writing logs

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

3.4 Action parameter print(self.action) in the object of the view class

There is an action attribute in the object of the view class – it is a string of method names executed in a single request

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