Django Rest_Framework (2)


When does a declared serializer need to inherit the serializer base class Serializer, and when does it inherit the model serializer class ModelSerializer?

继承序列化器类Serializer
	字段声明
	验证
	添加/保存数据功能
继承模型序列化器类ModelSerializer
	字段声明[可选,看需要]
	Meta声明
	验证
	添加/保存数据功能[可选]

See if the data is obtained from the mysql database. If so, use ModelSerializer. If not, use Serializer.

1. http request response

In addition to abbreviating the code in the data serialization part, drf also provides abbreviated operations in the view. Therefore, based on Django's original django.views.View class, drf encapsulates multiple view subclasses for us to use.

The main functions of the views provided by the Django REST framework:

  • Control the execution of the serializer (verify, save, convert data)
  • Control the execution of database queries
  • Call the request class and response class [These two classes are also extended by drf to help us extend some functional classes. ]

In order to facilitate our learning, we first create a sub-application req

python manage.py startapp req

Register sub-reference:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students',
    'sers',    # 序列化器
    "school",  # 序列化器嵌套
    'req',     # 请求与响应
]

Register route

# 子应用路由
from django.urls import path
from . import views
urlpatterns = [

]


# 总路由
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('students/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path('school/', include("school.urls")),
    path("req/", include("req.urls")),
]

1.1. Request and Response

Content negotiation: Based on the original Django, drf added a new request object and inherited it from the APIVIew view class, and implemented a subclass rest_framework.response.Response response class based on the original HttpResponse response class of Django. Both classes complete data format conversion based on content negotiation.

request->parser parsing class->identify the Content-Type in the client request header to complete the data conversion into->class dictionary (QueryDict, a subclass of the dictionary)

response->renderer rendering class->Identify the "Accept" of the client request header to extract the return data format expected by the client, -> Convert it into the client's expected format data

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-5kzAIkXK-1691197102532) (assets/image-20211020101829885.png)]

1.1.1 Request

The request object passed into the view by REST framework is no longer Django's default HttpRequest object, but an object of the Request class provided by REST framework that extends the HttpRequest class.

REST framework provides a Parser parser. After receiving a request, it will automatically parse the request data according to the request data type (such as JSON, form, etc.) specified by Content-Type, and parse it into a dictionary-like [QueryDict] object and save it to the Request object . middle.

The data of the Request object is the result of automatic parsing according to the format of the data sent by the front end.

No matter which format of data is sent by the front end, we can read the data in a uniform way.

1.1.1.1 Common attributes

1).data

request.dataReturns the parsed request body data. Similar to the standard request.POSTand request.FILESattributes in Django, but provides the following features:

  • Contains parsed file and non-file data
  • Contains the parsed data of POST, PUT, and PATCH request methods
  • Utilizing the parser parser of the REST framework, it not only supports form type data, but also supports JSON data.
2).query_params

query_params, query parameters, also called query string (query string)

request.query_paramsSame as the Django standard request.GET, just changed to a more correct name.

3)request._request

Get the Request object encapsulated by django

Basic use

View code:

from django.views import View
from django.http.response import HttpResponse
from django.http.request import HttpRequest
from django.core.handlers.wsgi import WSGIRequest
class ReqView(View):
    def get(self,request):
        print(request)
        return HttpResponse("ok")

"""
默认情况下, 编写视图类时,如果继承的是django内置的django.view.View视图基类,
则视图方法中得到的request对象,是django默认提供的django.core.handlers.wsgi.WSGIRequest
WSGIRequest这个请求处理对象,无法直接提供的关于json数据数据处理。
在编写api接口时很不方便,所以drf为了简写这块内容,在原来的HttpRequest的基础上面,新增了一个Request对象
这个Request对象是单独声明的和原来django的HttpRequest不是父子关系。
同时注意:
   要使用drf提供的Request请求处理对象,必须在编写视图类时继承drf提供的视图基类
   from rest_framework.views import APIView
   
   如果使用drf提供的视图基类APIView编写类视图,则必须使用来自drf提供的Request请求对象和Response响应对象
"""
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ReqAPIView(APIView):
    def get(self,request):
        # rest_framework.request.Request对象
        print(request) # <rest_framework.request.Request: GET '/req/req2?name=xiaoming&age=17&lve=swim&lve=code'>
        # 获取查询字符串
        print(request.query_params)
        # 没有参数情况下: <QueryDict: {}>
        # 有参数的情况下: <QueryDict: {'name': ['xiaoming'], 'age': ['17'], 'lve': ['swim', 'code']}>
        # 所以,request.query_params的返回值操作和原来在django里面是一模一样的
        print(request.query_params.get("name")) # xiaoming
        print(request.query_params.getlist("lve")) # ['swim', 'code']

        return Response("ok")

    def post(self, request):
        # 获取请求体
        print(request.data) # {'name': 'xiaoming', 'age': 16, 'lve': ['swim', 'code']}
        """直接从请求体中提取数据转
        # 客户端如果上传了json数据,直接返回字典
        {'name': '灰太狼', 'age': 20, 'sex': 1, 'classmate': '301', 'description': '我还会再回来的~'}
        # 客户端如果上传了表单数据,直接返回QueryDict
        <QueryDict: {'name': ['xiaohui'], 'age': ['18']}>
        """
        print(request.FILES) # 获取上传文件列表
        
        # 要获取django原生提供的HttpRequest对象,可以通过request._request来获取到
        print(request._request.META.get("Accept")) # 当值为None时,drf默认在响应数据时按json格式返回
        # response = Response(data="not ok", status=204, headers={"Company":"Oldboy"})
        response = Response(data="not ok", status=status.HTTP_400_BAD_REQUEST, headers={
    
    "Company":"Oldboy"})
        return response

1.1.2 Response

rest_framework.response.Response

REST framework provides a response class Response. When using this class to construct a response object, the specific data content of the response will be converted (renderer) into a type that meets the front-end requirements.

REST framework provides Renderera renderer to Acceptautomatically convert response data into the corresponding format based on the (received data type declaration) in the request header. If Accept is not declared in the front-end request, the response data will be processed in Content-Type mode. We can modify the default response format through configuration.

You can find all drf default configuration items in rest_framework.settings

REST_FRAMEWORK = {
    
    
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器,返回json数据
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览器API渲染器,返回调试界面
    )
}

1.1.2.1 Construction method

Response(data, status=None, template_name=None, headers=None, content_type=None)

The response processing class of drf is different from the request processing class. Response is a subclass of django's HttpResponse response processing class.

dataThe data does not need to be the data after render processing, just pass python's built-in type data, and the REST framework will use the rendererrenderer to process it data.

dataIt cannot be data with a complex structure, such as Django's model class object. For such data, we can use a Serializerserializer to serialize it (convert it to a Python dictionary type) and then pass it to datathe parameters.

Parameter Description:

  • data: Serialized data prepared for response;
  • status: status code, default 200;
  • template_name: Template name, if used HTMLRendererit needs to be specified;
  • headers: Dictionary used to store response header information;
  • content_type: Content-Type of the response data. Usually this parameter does not need to be passed. REST framework will set this parameter according to the type of data required by the front end.

1.1.2.2 Properties of response object

Use less work,

1).data

Data passed to the response object after serialization but not yet rendered.

2).status_code

Status code number

3).content

Response data after render processing

1.1.2.3 Status code

In order to facilitate the setting of status codes, REST framewrok rest_framework.statusprovides constants for commonly used http status codes in the module.

1) Information Notification - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2) Success - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3) Redirect - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4) Client Error - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5) Server error - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

In order to facilitate demonstration, we create another sub-application to display the content knowledge in the view provided by drf.

python manage.py startapp demo

Register sub-application

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students',
    'sers',    # 序列化器
    "school",  # 序列化器嵌套
    'req',     # 请求与响应
    'demo',    # 视图
]

Overall routing, code:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('students/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path('school/', include("school.urls")),
    path("req/", include("req.urls")),
    path("demo/", include("demo.urls")),
]

Sub-application routing, code:

from django.urls import path
from . import views

urlpatterns = [

]

1. View

The main functions of the views provided by the Django REST framework:

  • Control the execution of the serializer (verify, save, convert data)
  • Control the operation of database models

1.2 Normal view

REST framework provides numerous common view base classes and extension classes to simplify view writing.

1.2.1 2 view base classes

1.2.1.1 APIView basic view class

rest_framework.views.APIView

APIViewIt is the base class of all view classes provided by REST framework and inherits from Django's Viewparent class.

APIViewViewThe difference with is that:

  • What is passed into the view method is the REST framework Requestobject, not the Django HttpRequesetobject;

  • The view method can return the object of the REST framework Response, and the view will set (renderer) the response data in a format that meets the expectations of the front end;

  • Any APIExceptionexceptions will be caught and processed into a response message in a suitable format and returned to the client;

    All exceptions in django's View are displayed in HTML format

    The APIVIew or APIView subclass of drf will automatically convert the error message format according to the client's Accept.

  • A new as_view method is re-declared and before dispatch() is used for route distribution, the requesting client will be authenticated, authorized checked, and flow controlled.

In addition to inheriting the original attribute methods of View, APIView also adds new class attributes:

  • authentication_classes list or tuple, authentication class
  • permissoin_classes list or tuple, permission check class
  • throttle_classes list or ancestor, flow control class

In APIViewit, conventional class view definition methods are still used to implement get(), post() or other request methods.

Serializer, demo/serializers.py, code:

from rest_framework import serializers
from stuapi.models import Student


class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
    
    
            "age": {
    
    
                "max_value": 25,
                "error_messages": {
    
    
                    "max_value": "年龄不能超过25岁!",
                }
            }
        }

View code:

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from stuapi.models import Student
from .serializers import StudentModelSerializer
"""
GET  /demo/students/   获取所有学生信息    
POST /demo/students/   添加一个学生信息    

GET  /demo/students/<pk>   获取一个学生信息    
PUT  /demo/students/<pk>   更新一个学生信息    
DELETE  /demo/students/<pk>   删除一个学生信息    
"""


# Create your views here.
class StudentAPIView(APIView):
    def get(self,request):
        """获取所有学生信息"""
        # 1. 从数据库中读取学生列表信息
        student_list = Student.objects.all()
        # 2. 实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(instance=student_list, many=True)

        # 3. 转换数据并返回给客户端
        return Response(serializer.data)

    def post(self,request):
        """添加一条数据"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(data=request.data)

        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 3. 返回新增的模型数据给客户单
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class StudentInfoAPIView(APIView):
    def get(self,request, pk):
        """获取一条数据"""
        # 1. 使用pk作为条件获取模型对象
        try:
            student = Student.objects.get(pk=pk)
        except Student.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # 2. 序列化
        serializer = StudentModelSerializer(instance=student)

        # 3. 返回结果
        return Response(serializer.data)

    def put(self,request,pk):
        """更新数据"""
        # 1. 使用pk作为条件获取模型对象
        try:
            student = Student.objects.get(pk=pk)
        except Student.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        # 2. 获取客户端提交的数据
        serializer = StudentModelSerializer(instance=student, data=request.data)

        # 3. 反序列化[验证数据和数据保存]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4. 返回结果
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self,request,pk):
        """删除数据"""
        # 1. 根据PK值获取要删除的数据并删除
        try:
            Student.objects.get(pk=pk).delete()
        except Student.DoesNotExist:
            pass

        # 2. 返回结果
        return Response(status=status.HTTP_204_NO_CONTENT)

Routing code:

from django.urls import path, re_path
from . import views

urlpatterns = [
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),
]

1.2.1.2 GenericAPIView [generic view class]

The main function of the general view class is to extract the unique code in the view , making the code in the view method more general, and conveniently abbreviating the general code.

rest_framework.generics.GenericAPIView

Inherited from APIView, it mainly adds methods for operating serializers and database queries. Its function is to provide method support for the execution of the Mixin extension class below. Usually when used, it can be paired with one or more Mixin extension classes.

Properties and methods provided by the serializer

  • Attributes:

    • serializer_class specifies the serializer class used by the view
  • method:

    • get_serializer_class(self)

      When multiple serializers are called in a view class, the view method can execute different serializer objects by returning different serializer class names in the get_serializer_class method through conditional judgment.

      Returns the serializer class, which is returned by default serializer_classand can be overridden, for example:

      class Student2GenericAPIView(GenericAPIView):
          # 整个视图类只使用一个序列化器的情况
          # serializer_class = StudentModelSerializert
          # 整个视图类中使用多个序列化器的情况
          def get_serializer_class(self):
            if self.request.method.lower() == "put":
                  return StudentModelSerializer
            else:
                  return Student2ModelSerializer
      
          queryset = Student.objects
      
          def get(self, request, pk):
              """获取一个模型信息"""
              serializer = self.get_serializer(instance=self.get_object())
              return Response(serializer.data)
      
          def put(self, request, pk):
              """更新一个模型信息"""
              serializer = self.get_serializer(instance=self.get_object(), data=request.data)
              serializer.is_valid(raise_exception=True)
              serializer.save()
              return Response(serializer.data)
      
    • get_serializer(self, *args, **kwargs)

      Returns the serializer object, which is mainly used by Mixin extension classes. If we want to obtain the serializer object in the view, we can also call this method directly.

      Note that when this method provides the serializer object, it will add three data to the context attribute of the serializer object: request, format, and view. These three data objects can be used when defining the serializer.

      • request the request object of the current view
      • viewThe view-like object currently requested
      • format The data format expected to be returned by the current request

Provided properties and methods for database queries

  • Attributes:

    • queryset specifies the data query set used
  • method:

    • get_queryset(self)

      The query set used by the return view is mainly used by the Mixin extension class and is the basis for obtaining data for the list view and the detail view. The default return querysetattribute can be overridden, for example:

      def get_queryset(self):
          user = self.request.user
          return user.accounts.all()
      
    • get_object(self)

      Returns the model class data object required for the detail view, which is mainly used by Mixin extension classes.

      This method can be called in the view to obtain the model class object with detailed information.

      If the model class object accessed by details does not exist, 404 will be returned.

      This method will use the check_object_permissions method provided by APIView by default to check whether the current object has permission to be accessed.

      Example:

      # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
      class BookDetailView(GenericAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
      
          def get(self, request, pk):
              book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
              serializer = self.get_serializer(book)
              return Response(serializer.data)
      

Other properties that can be set

  • pagination_class specifies the pagination control class
  • filter_backends indicates the data filtering control backend

View, code:

"""
APIView中的api接口代码,除了部分涉及到调用模型和序列化器的代码以外,其他代码几乎都是固定写法。
所以,当我们将来针对增删查改的通用api接口编写时,完全可以基于原有的代码进行复用,
那么,drf也考虑到了这个问题,所以提供了一个GenericAPIView(通用视图类),让我们可以把接口中独特的代码单独提取出来作为属性存在。
rest_framework.generics.GenericAPIView是APIView的子类,在APIView的基础上进行属性扩展提供了2个属性,4个方法,方便我们针对通用接口进行编写。
"""
"""GenericAPIView 通用视图类"""
from rest_framework.generics import GenericAPIView


class StudentGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def get(self,request):
        """获取所有数据"""
        # 1. 从数据库中读取模型列表信息
        queryset = self.get_queryset()  # GenericAPIView提供的get_queryset
        # 2. 序列化
        serializer = self.get_serializer(instance=queryset, many=True)

        # 3. 转换数据并返回给客户端
        return Response(serializer.data)

    def post(self,request):
        """添加一个数据"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = self.get_serializer(data=request.data)

        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 3. 返回新增的模型数据给客户单
        return Response(serializer.data, status=status.HTTP_201_CREATED)


class StudentInfoGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def get(self,request,pk):
        """获取一个数据"""
        # 1. 使用pk作为条件获取模型对象
        instance = self.get_object()

        # 2.序列化
        serializer = self.get_serializer(instance=instance)

        # 3. 返回结果
        return Response(serializer.data)

    def put(self, request, pk):
        """更新一个数据"""
        # 1. 使用pk作为条件获取模型对象
        instance = self.get_object()

        # 2. 获取客户端提交的数据
        serializer = self.get_serializer(instance=instance, data=request.data)

        # 3. 反序列化[验证数据和数据保存]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4. 返回结果
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self,request,pk):
        """删除一个数据"""
        # 1. 根据PK值获取要删除的数据并删除
        self.get_object().delete()

        # 2. 返回结果
        return Response(status=status.HTTP_204_NO_CONTENT)

Serializer class:

from rest_framework import serializers
from stuapi.models import Student


class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
    
    
            "age": {
    
    
                "max_value": 25,
                "error_messages": {
    
    
                    "max_value": "年龄不能超过25岁!",
                }
            }
        }

Routing code:

from django.urls import path, re_path
from . import views

urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students2/", views.StudentGenericAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),
]

1.2.2 5 view extension classes

Also called mix-ins.

effect:

Provides the implementation of several back-end view (add, delete, modify and query data resources) processing processes. If the view to be written belongs to these five types, the view can reuse the code by inheriting the corresponding extension class, reducing the code written by oneself. quantity.

These five extension classes need to be paired with the GenericAPIView universal view base 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 returns a 200 status code.

The Mixin's list method will filter and page the data.

source code:

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        # 过滤
        queryset = self.filter_queryset(self.get_queryset())
        # 分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        # 序列化
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Example:

from rest_framework.mixins import ListModelMixin,CreateModelMixin
class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects
    def get(self,request,*args,**kwargs):
        """获取所有模型信息"""
        return self.list(request,*args,**kwargs)

2)CreateModelMixin

Create a view extension class, provide create(request, *args, **kwargs)a method to quickly create a resource view, and return a 201 status code on success.

If the serializer fails to verify the data sent by the front end, a 400 error is returned.

source code:

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        # 获取序列化器
        serializer = self.get_serializer(data=request.data)
        # 验证
        serializer.is_valid(raise_exception=True)
        # 保存
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

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

    def get_success_headers(self, data):
        try:
            return {
    
    'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {
    
    }

View code:

from rest_framework.mixins import ListModelMixin,CreateModelMixin
class StudentMixinAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects
    def get(self,request,*args,**kwargs):
        """获取所有模型信息"""
        return self.list(request,*args,**kwargs)

    def post(self,request):
        """添加一个模型信息"""
        return self.create(request)

3)RetrieveModelMixin

The detail view extends the class and provides retrieve(request, *args, **kwargs)methods to quickly return an existing data object.

If it exists, return 200, otherwise return 404.

source code:

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        # 获取对象,会检查对象的权限
        instance = self.get_object()
        # 序列化
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

View code:

from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects
    def get(self,request,pk):
        """获取一个模型信息"""
        return self.retrieve(request,pk)

4)UpdateModelMixin

The update view extension class provides update(request, *args, **kwargs)methods to quickly update an existing data object.

It also provides partial_update(request, *args, **kwargs)methods to implement local updates.

200 is returned successfully. When the serializer fails to verify the data, a 400 error is returned.

source code:

class UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {
    
    }

        return Response(serializer.data)

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

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

View code:

from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects
    def get(self,request,pk):
        """获取一个模型信息"""
        return self.retrieve(request,pk)

    def put(self,request,pk):
        """更新一个模型信息"""
        return self.update(request,pk)

5)DestroyModelMixin

The delete view extension class provides destroy(request, *args, **kwargs)methods to quickly delete an existing data object.

Returns 204 if successful, 404 if not present.

source code:

class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

View code:

from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student1MixinAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects
    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)

The overall code uses GenericAPIView combined with the view extension class to implement 5 basic api interfaces. View code:

"""
使用drf内置的模型扩展类[混入类]结合GenericAPIView实现通用视图方法的简写操作
from rest_framework.mixins import ListModelMixin   获取多条数据,返回响应结果    list
from rest_framework.mixins import CreateModelMixin 添加一条数据,返回响应结果    create
from rest_framework.mixins import RetrieveModelMixin 获取一条数据,返回响应结果  retrieve
from rest_framework.mixins import UpdateModelMixin 更新一条数据,返回响应结果    update(更新全部字段)和partial_update(更新单个或部分字段,例如修改密码,修改头像)
from rest_framework.mixins import DestroyModelMixin 删除一条数据,返回响应结果   destroy
"""
from rest_framework.mixins import ListModelMixin, CreateModelMixin


class StudentMixinView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def get(self,request):
        """获取所有数据"""
        return self.list(request)

    def post(self,request):
        """添加一条数据"""
        return self.create(request)


from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin

class StudentInfoMixinView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

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

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

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

Serializer, code:

from rest_framework import serializers
from stuapi.models import Student


class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
    
    
            "age": {
    
    
                "max_value": 25,
                "error_messages": {
    
    
                    "max_value": "年龄不能超过25岁!",
                }
            }
        }

Routing code:

from django.urls import path, re_path
from . import views

urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students2/", views.StudentGenericAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + mixins
    path("students3/", views.StudentMixinView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StudentInfoMixinView.as_view()),
]

1.2.3 9 view subclasses

1)CreateAPIView

The post method is provided and the create method is called internally.

Inherited from: GenericAPIView, CreateModelMixin

2)ListAPIView

The get method is provided and the list method is called internally

Inherited from: GenericAPIView, ListModelMixin

3)RetrieveAPIView

The get method is provided and the retrieve method is called internally

Inherited from: GenericAPIView, RetrieveModelMixin

4)DestoryAPIView

The delete method is provided and the destroy method is called internally.

Inherited from: GenericAPIView, DestoryModelMixin

5)UpdateAPIView

Provides put and patch methods, and calls update and partial_update methods internally

Inherited from: GenericAPIView, UpdateModelMixin

6)ListCreateAPIView

Provides get and post methods, and calls list and create methods internally

Inherited from: GenericAPIView, ListModelMixin, CreateModelMixin

7)RetrieveUpdateAPIView

Provides get, put, and patch methods

Inherited from: GenericAPIView, RetrieveModelMixin, UpdateModelMixin

8)RetrieveDestoryAPIView

Provide get and delete methods

Inherited from: GenericAPIView, RetrieveModelMixin, DestoryModelMixin

9)RetrieveUpdateDestoryAPIView

Provides get, put, patch, delete methods

继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

View code:


"""
上面的接口代码还可以继续更加的精简,drf在使用GenericAPIView和Mixins进行组合以后,还提供了视图子类。
视图子类,提供了各种的视图方法调用mixins操作

    ListAPIView = GenericAPIView + ListModelMixin         获取多条数据的视图方法
    CreateAPIView = GenericAPIView + CreateModelMixin     添加一条数据的视图方法
    RetrieveAPIView = GenericAPIView + RetrieveModelMixin 获取一条数据的视图方法
    UpdateAPIView = GenericAPIView + UpdateModelMixin     更新一条数据的视图方法
    DestroyAPIView = GenericAPIView + DestroyModelMixin   删除一条数据的视图方法
组合视图子类
    ListCreateAPIView = ListAPIView + CreateAPIView
    RetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIView
    RetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIView
    RetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView
"""
# from rest_framework.generics import ListAPIView, CreateAPIView
from rest_framework.generics import ListCreateAPIView
class StudentListAPIView(ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer


# from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView
# from rest_framework.generics import RetrieveUpdateAPIView, DestroyAPIView
# from rest_framework.generics import RetrieveDestroyAPIView, UpdateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView # 四行代码一样意思
class StudentInfoAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

Serializer, code:

from rest_framework import serializers
from school.models import Student
class  StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"

Routing, code:

from django.urls import path
from . import views

urlpatterns = [
    path("s1/", views.StudentList1APIView.as_view()),
    path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),
    path("s2/", views.StudentList2GenericAPIView.as_view()),
    path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),
    path("s3/", views.StudentList3GenericAPIView.as_view()),
    path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),
    path("s4/", views.StudentListAPIView.as_view()),
    path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
]

1.3 ViewSet

Using ViewSet, a series of view-related code logic and related http request actions can be encapsulated into a class:

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

The ViewSet view set class no longer limits view method names to only allow get(), post(), etc., but allows developers to define custom method names according to their own needs, such as list(), create(), etc. , and then use http and these view method names in the routing to make binding calls.

The viewset will only match the action to the specific request method when using the as_view() method . like:

"""
针对视图子类这种写法写法虽然已经省略了http请求,但是在开发通用5个api接口时,还是会出现需要2个类来实现5个接口的情况。
这主要的原因是2点:
1. 获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2. 部分接口需要pk值作为url地址。

drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet  # ViewSet是APIView的子类,是所有drf中的视图集的父类
"""
from rest_framework.viewsets import ViewSet
class StudentViewSet(ViewSet):
    # ViewSet不再需要我们使用http请求作为视图方法了。当然,如果你还希望使用http作为视图方法也可以。
    def get_all(self,request):
        queryset = Student.objects.all()
        # 实例化序列化器对象
        serializer = StudentModelSerializer(instance=queryset, many=True)
        # 返回序列化后的数据列表
        return Response(serializer.data)

    def create(self,request):
        """添加一条数据"""
        # 接收客户端提交的数据
        # 1. 实例化序列化器对象,获取来自客户端的请求数据作为参数
        serializer = StudentModelSerializer(data=request.data)
        # 2. 反序列化, 调用is_valid进行数据校验
        serializer.is_valid(raise_exception=True)
        # 3. 反序列化, 调用save保存数据
        serializer.save()
        # 4. 序列化,把新增后的模型对象返回给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def get_one(self,request,pk):
        try:
            # 模型操作,根据pk值获取指定数据
            instance = Student.objects.get(pk=pk)
            # 实例化序列化器对象
            serializer = StudentModelSerializer(instance=instance)
            # 返回序列化后的数据
            return Response(serializer.data)
        except Student.DoesNotExist:
            return Response({
    
    "msg":"当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)


    def put(self,request,pk):
        """更新一条数据"""
        try:
            # 获取要更新的模型对象
            instance = Student.objects.get(pk=pk)
            # 实例化序列化器对象,参数分别是本次更新的模型对象以及接受来自客户端提交的更新数据
            serializer = StudentModelSerializer(instance=instance, data=request.data)
            # 反序列化,验证数据
            serializer.is_valid(raise_exception=True)
            # 反序列化器,保存数据
            serializer.save()
            # 序列化,返回更新后的数据
            return Response(serializer.data)

        except Student.DoesNotExist:
            return Response({
    
    "msg": "当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)


    def delete(self,request,pk):
        """删除一条数据"""
        try:
            # 获取要更新的模型对象
            student = Student.objects.get(pk=pk)
            student.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except Student.DoesNotExist:
            return Response({
    
    "msg": "当前学生不存在!"}, status=status.HTTP_404_NOT_FOUND)

When setting up routing, we can do the following

from django.urls import path
from . import views

urlpatterns = [
    path("s1/", views.StudentList1APIView.as_view()),
    path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),
    path("s2/", views.StudentList2GenericAPIView.as_view()),
    path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),
    path("s3/", views.StudentList3GenericAPIView.as_view()),
    path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),
    path("s4/", views.StudentListAPIView.as_view()),
    path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
    path("s5/", views.StudentViewSet.as_view(actions={
    
    "get":"get_all","post":"create"})),
    path("s5/<int:pk>/", views.StudentViewSet.as_view({
    
    "get":"get_one","put":"put","delete":"delete"})),
]

1.3.1 common view set parent class

1) ViewSet

Inherited from APIViewand ViewSetMixin, its function is basically similar to APIView, providing identity authentication, permission verification, traffic management, etc.

ViewSet mainly implements the mapping processing of the dictionary {"http request":"view method"} passed in when calling as_view(), such as {'get':'list'}, by inheriting ViewSetMixin.

In ViewSet, no action method is provided, and we need to implement the action method ourselves.

2)GenericViewSet

Inherited from GenericAPIView and ViewSetMixin, it makes the view code of the view set more general and extracts the unique code as an attribute of the view class.

It is usually inconvenient to use ViewSet, because the list, retrieve, create, update, destroy and other methods need to be written by yourself, and these methods have the same names as the methods provided by the Mixin extension class mentioned earlier, so we can duplicate them by inheriting the Mixin extension class. Use these methods without writing your own. But the Mixin extension class depends on and GenericAPIView, so it still needs to be inherited GenericAPIView.

GenericViewSet helps us complete such inheritance work. It inherits from GenericAPIViewand ViewSetMixinwhile implementing the mapping processing of the dictionary (such as) passed in when calling as_view() {'get':'list'}, it also provides GenericAPIViewbasic methods that can be directly used with Mixin extension classes use.

View code:


from rest_framework.viewsets import GenericViewSet

class StudentGenericViewSet(GenericViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    def list(self,request):
        """获取多条数据"""
        # 获取模型对象列表,实例化序列化器对象
        serializer = self.get_serializer(instance=self.get_queryset(), many=True)
        # 返回序列化后的数据列表
        return Response(serializer.data)

    def post(self,request):
        """添加一条数据"""
        serializer = self.get_serializer(data=request.data)
        # 2. 反序列化, 调用is_valid进行数据校验
        serializer.is_valid(raise_exception=True)
        # 3. 反序列化, 调用save保存数据
        serializer.save()
        # 4. 序列化,把新增后的模型对象返回给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk):
        """获取一条数据"""
        # 模型操作,根据pk值获取指定数据
        instance = self.get_object() # 上面代码的简写,而且对错误进行格式处理
        # 实例化序列化器对象
        serializer = self.get_serializer(instance=instance)
        # 返回序列化后的数据列表
        return Response(serializer.data)

    def update(self, request, pk):
        """更新一条数据"""
        instance = self.get_object() # 不要漏了pk参数
        serializer = self.get_serializer(instance=instance, data=request.data)
        # 反序列化,验证数据
        serializer.is_valid(raise_exception=True)
        # 反序列化器,保存数据
        serializer.save()
        # 序列化,返回更新后的数据
        return Response(serializer.data)

    def delete(self, request, pk):
        instance = self.get_object()
        instance.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Routing code:

from django.urls import path
from . import views

urlpatterns = [
    path("s1/", views.StudentList1APIView.as_view()),
    path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),
    path("s2/", views.StudentList2GenericAPIView.as_view()),
    path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),
    path("s3/", views.StudentList3GenericAPIView.as_view()),
    path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),
    path("s4/", views.StudentListAPIView.as_view()),
    path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
    # path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),
    path("s5/", views.StudentViewSet.as_view({
    
    "get":"get_all","post":"create"})),
    path("s5/<int:pk>/", views.StudentViewSet.as_view({
    
    "get":"get_one","put":"put","delete":"delete"})),
    path("s6/", views.StudentGenericViewSet.as_view({
    
    "get":"list","post":"post"})),
    path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({
    
    "get":"retrieve","put":"update","delete":"delete"})),
]

Collect the model extension classes we learned above to implement abbreviated operations, views, and code:

"""
GenericViewSet结合Mixins的混入类,直接视图接口,这次连视图子类都不需要了。
ViewSet
GenericViewSet
ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin + UpdateModelMixin + RetrieveModelMixin + DestroyModelMixin
ReadOnlyModelViewSet = GenericViewSet + ListModelMixin + RetrieveModelMixin
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
class StudentMixinViewSet(GenericViewSet, ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

Routing, code:

from django.urls import path
from . import views

urlpatterns = [
    path("s1/", views.StudentList1APIView.as_view()),
    path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),
    path("s2/", views.StudentList2GenericAPIView.as_view()),
    path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),
    path("s3/", views.StudentList3GenericAPIView.as_view()),
    path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),
    path("s4/", views.StudentListAPIView.as_view()),
    path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
    # path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),
    path("s5/", views.StudentViewSet.as_view({
    
    "get":"get_all","post":"create"})),
    path("s5/<int:pk>/", views.StudentViewSet.as_view({
    
    "get":"get_one","put":"put","delete":"delete"})),
    path("s6/", views.StudentGenericViewSet.as_view({
    
    "get":"list","post":"post"})),
    path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({
    
    "get":"retrieve","put":"update","delete":"delete"})),
    path("s7/", views.StudentMixinViewSet.as_view({
    
    "get":"list","post":"create"})),
    path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({
    
    "get":"retrieve","put":"update","delete":"destroy"})),
]

3)ModelViewSet

Inherited from GenericViewSet, also includes ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestoryModelMixin.

4)ReadOnlyModelViewSet

Inherited from GenericViewSet, including ListModelMixin and RetrieveModelMixin.

View code:

"""
GenericViewSet结合Mixins的混入类,直接视图接口,这次连视图子类都不需要了。
ViewSet
GenericViewSet
ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin + UpdateModelMixin + RetrieveModelMixin + DestroyModelMixin
ReadOnlyModelViewSet = GenericViewSet + ListModelMixin + RetrieveModelMixin
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from rest_framework.viewsets import ModelViewSet # 万能视图集,5个接口的简写
from rest_framework.viewsets import ReadOnlyModelViewSet # 只读视图集,2个接口的简写
class StudentMixinViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

Routing code:

from django.urls import path
from . import views

urlpatterns = [
    path("s1/", views.StudentList1APIView.as_view()),
    path("s1/<int:pk>/", views.StudentInfo1APIView.as_view()),
    path("s2/", views.StudentList2GenericAPIView.as_view()),
    path("s2/<int:pk>/", views.StudentInfo2GenericAPIView.as_view()),
    path("s3/", views.StudentList3GenericAPIView.as_view()),
    path("s3/<int:pk>/", views.StudentInfo3GenericAPIView.as_view()),
    path("s4/", views.StudentListAPIView.as_view()),
    path("s4/<int:pk>/", views.StudentInfoAPIView.as_view()),
    # path("url地址/", views.StudentViewSet.as_view({"http请求方法名":"视图方法名","http请求方法名":"视图方法名",....})),
    path("s5/", views.StudentViewSet.as_view({
    
    "get":"get_all","post":"create"})),
    path("s5/<int:pk>/", views.StudentViewSet.as_view({
    
    "get":"get_one","put":"put","delete":"delete"})),
    path("s6/", views.StudentGenericViewSet.as_view({
    
    "get":"list","post":"post"})),
    path("s6/<int:pk>/", views.StudentGenericViewSet.as_view({
    
    "get":"retrieve","put":"update","delete":"delete"})),
    path("s7/", views.StudentMixinViewSet.as_view({
    
    "get":"list","post":"create"})),
    path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({
    
    "get":"retrieve","put":"update","delete":"destroy"})),
]

2. Routers

For ViewSet, in addition to manually specifying the correspondence between the request method and the action, we can also use Routers to help us quickly implement routing information. If it is a non-view set, there is no need to use routing set routers.

REST framework provides two routers, which are used in the same way. The result is just a problem of one more or one less root directory URL address.

  • SimpleRouter
  • DefaultRouter

2.1 How to use

1) Create a router object and register the viewset, for example

from django.urls import path
from . import views

urlpatterns = [
    # 省略....
    # path("s7/", views.StudentMixinViewSet.as_view({"get":"list","post":"create"})),
    # path("s7/<int:pk>/", views.StudentMixinViewSet.as_view({"get":"retrieve","put":"update","delete":"destroy"})),
]

# 路由集的操作
from rest_framework.routers import DefaultRouter,SimpleRouter
router = DefaultRouter()
# 注册视图(访问前缀,视图集类,调用别名)
router.register("s7", views.StudentMixinViewSet, "s7")
# 把路由对象生成的视图集路由列表合并追加路由列表中
print(router.urls)
urlpatterns += router.urls

register(prefix, viewset, basename)

  • prefix The routing prefix for this view set
  • viewset viewset
  • basename prefix of routing alias

The route formed by the above code is as follows:

url: ^s7/$                  basename: s7-list
url: ^s7/(?P<pk>[^/.]+)/$   basename: s7-detail

2) There are two ways to add the route list of the viewset generated by the routing object to the Django route:

urlpatterns = [
    ...
]

urlpatterns += router.urls

or

from django.urls import include,re_path
urlpatterns = [
    ...
    re_path('^', include(router.urls))
]

2.2 Declaration of additional actions in the view set

In the view set, if you want Router to automatically help us generate routing information for custom actions, you need to use a rest_framework.decorators.actiondecorator.

The method name decorated with the action decorator will be used as the action name, which is equivalent to list and retrieve.

The action decorator can receive two parameters:

  • methods : declare the request method corresponding to the action, passed in a list

  • detail : declares whether the path of the action corresponds to a single resource

    路由前缀/<pk>/action方法名/
    
    • True means the path format isxxx/<pk>/action方法名/
    • False means the path format isxxx/action方法名/
  • url_path: declares the routing suffix of the action.

Example:

from rest_framework.viewsets import ModelViewSet # 万能视图集,5个接口的简写
from rest_framework.viewsets import ReadOnlyModelViewSet # 只读视图集,2个接口的简写
from rest_framework.decorators import action
class StudentMixinViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    # 路由对象给视图集生成路由信息时,只会生成5个基本api接口,这主要是router只识别5个混入类的原因,
    # 而针对我们开发者自定义的视图方法,路由对象不会自动生成路由信息,
    # 所以下面这个login,如果希望被外界访问到,则必须通过action装饰器告诉路由对象要给它生成一个路由信息。
    @action(methods=["get","post"], detail=False, url_path="login")
    # action的参数
    # methods, 列表,指定允许哪些http请求方法可以访问当前视图方法
    # detail, 布尔值,告诉路由对象在生成路由信息时,是否要自动生成pk值,True表示需要,False表示不需要。
    # url_path,字符串,访问视图的url地址,如果不设置,则默认采用视图方法名作为访问后缀
    # http://127.0.0.1:8000/demo/s7/login/
    def login(self, request):
        """登录视图"""
        return Response({
    
    "msg":"登录成功"})

    @action(methods=["get"], detail=True, url_path="login/log")
    # http://127.0.0.1:8000/demo/s7/23/login/log/
    def login_log(self,request,pk):
        """用户登录历史记录"""
        # 视图集类中
        # 可以通过self.method获取本次客户端的http请求
        # 可以通过self.action获取本次客户端请求的视图方法名[ViewSet提供的]
        print(self.action) # login_log
        return Response({
    
    "msg": "用户登录历史记录"})

The route formed by the router automatically customizing the action method for this view set will be as follows:

url: ^s7/login/$                      basename: s7-login
url: ^s7/(?P<pk>[^/.]+)/login/log/$   basename: s7-login-log

2.3 The way router forms URL

1) SimpleRouter (prefix="routing prefix", viewset=viewset class, basename="routing alias")

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-gbax9nAn-1691197102533) (assets/SimpleRouter.png)]

2)DefaultRouter

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-tRdBSVn1-1691197102534) (assets/DefaultRouter.png)]

The difference between DefaultRouter and SimpleRouter is that DefaultRouter will come with a default API root view and return a hyperlink response data containing all list views.

Guess you like

Origin blog.csdn.net/weixin_53909748/article/details/132115507