Using modelviewset + modelserializer

Time:2021-5-2

1. DRF initialization

  • Eight core functions of DRF framework

1. Authentication (user login to verify whether the user name, password or token are legal)
2. Permissions (different tables can be operated according to different user roles)
3. Current limiting (limiting interface access speed)
4. Serialization (return JSON)
5. Pagination
6. Version (interface version number, V1 / V2 / V3)
    #Api.example.com/v1/login # login only with user name and password
    #Api.example.com/v2/login # mobile number, wechat login
7. Filtering (user name = Zhangsan)
8. Ordering = - ID
  • Related packages

1. Serialization related
serializer
ModelSerializer
'''2. DRF view function inheritance'
APIView
ModelViewSet

1.1 install djangorestframework

pip install djangorestframework==3.11.1
PIP install Django filter = = 2.3.0 # filter
pip install markdown                         # Markdown support for the browsable API.

1.2 register in settings.py

INSTALLED_APPS = [
    'django_filters',
    'rest_framework',
]

1.3 settings.py configure DRF (global)

Using modelviewset + modelserializerUsing modelviewset + modelserializer

REST_FRAMEWORK = {
    #Document error: attributeerror: 'autoschema' object has no attribute 'get'_ link’
    #This can be solved with the following settings
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
    #The default setting is:
    # 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema',

    #Exception handler
    # 'EXCEPTION_HANDLER': 'user.utils.exception_handler',

    # Base API policies
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ],
    #1. authenticator (global): user login to verify whether the user name password or token is legal
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_ framework_ JWT. Authentication. Jsonwebtoken authentication '; configure JWT authentication in DRF
        # 'rest_ Framework. Authentication. Sessionauthentication '; authenticator when using session
        # 'rest_ Framework. Authentication. Basicaauthentication '? Authenticator when submitting a form
    ],
    #2. Permission configuration (global): strict order (different tables can be operated according to different user roles)
    'DEFAULT_PERMISSION_CLASSES': [
        # 'rest_ Framework. Permissions. Isadminuser '; administrators can access
        # 'rest_ Framework. Permissions. Isauthenticated ', #authenticated users can access
        # 'rest_ Framework. Permissions. Isauthenticatedorreadonly ', # authenticated users can access, otherwise they can only read
        # 'rest_ Framework. Permissions. Allowany '; all users can access it
        #'user. Utils. Vippermission', # custom permissions
    ],
    #3. Current limiting (anti crawler)
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle',
    ],
    #3.1 current limiting strategy
    # 'DEFAULT_THROTTLE_RATES': {
    #'user':'100 / hour '# authenticated user 100 times per hour
    #'anon':'10 / day '; unauthorized users can visit three times a day
    # },

    'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
    'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
    'DEFAULT_VERSIONING_CLASS': None,

    #4. Paging (global): Global pager, such as data Custom pager in provincial and urban areas, does not need paging
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    #Quantity returned per page
    # 'PAGE_ Size ': 3, # default none

    #5. Back end of filter
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        # 'django_ filters.rest_ Framework. Backends. Djangofilterbackend ', package path changed
        'rest_framework.filters.OrderingFilter',
    ],

    #5.1 filtering sort (global): filtering sort
    # 'SEARCH_PARAM': 'search',
    # 'ORDERING_PARAM': 'ordering',
    #
    # 'NUM_PROXIES': None,

    #6. Version control: versioning interface version control
    'DEFAULT_VERSION': None,
    'ALLOWED_VERSIONS': None,
    'VERSION_PARAM': 'version',

    #Authentication authentication
    #The user type used by an unauthorized user
    'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
    #Token value used by unauthorized users
    'UNAUTHENTICATED_TOKEN': None,

    # View configuration
    'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name',
    'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description',

    'NON_FIELD_ERRORS_KEY': 'non_field_errors',

    # Testing
    'TEST_REQUEST_RENDERER_CLASSES': [
        'rest_framework.renderers.MultiPartRenderer',
        'rest_framework.renderers.JSONRenderer'
    ],
    'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',

    # Hyperlink settings
    'URL_FORMAT_OVERRIDE': 'format',
    'FORMAT_SUFFIX_KWARG': 'format',
    'URL_FIELD_NAME': 'url',

    # Encoding
    'UNICODE_JSON': True,
    'COMPACT_JSON': True,
    'STRICT_JSON': True,
    'COERCE_DECIMAL_TO_STRING': True,
    'UPLOADED_FILES_USE_URL': True,

    # Browseable API
    'HTML_SELECT_CUTOFF': 1000,
    'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...",

    # Schemas
    'SCHEMA_COERCE_PATH_PK': True,
    'SCHEMA_COERCE_METHOD_NAMES': {
        'retrieve': 'read',
        'destroy': 'delete'
    },
}

settings.py

2. Code practice

Using modelviewset + modelserializerUsing modelviewset + modelserializer

from django.urls import include, path
from user import views
from rest_framework.routers import SimpleRouter, DefaultRouter

#To automatically generate routing methods, you must use view sets
#Router = simplerouter() # no root route / user / unrecognized
Router = defaultrouter() # 1
Router. Register (r'user ', views. Userviewset) ා 2. Configure routing

urlpatterns = [
    path('index/', views.index),
    path('api-auth/', include('rest_ framework.urls', namespace='rest_ Authentication address
]

Urlpatterns + = router.urls # 3. Module address

user/urls.py

Using modelviewset + modelserializerUsing modelviewset + modelserializer

from django.http import HttpResponse
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.pagination import PageNumberPagination
from rest_framework.views import APIView
from rest_framework.permissions import BasePermission, SAFE_METHODS
from user.models import User
from user.serializers import UserSerializer, UserUnActiveSerializer


#Paging (local): Custom pager local
class PageNum(PageNumberPagination):
    #The parameter name representing the number of returned data per page in the query string. The default value is none
    page_size_query_param = 'page_size'
    #The parameter name representing the page number in the query string has the default value: page
    # page_query_param = 'page'
    #Maximum number of results in a page
    max_page_size = 2


#Custom permissions (local)
class MyPermission(BasePermission):
    # has_ Permission is whether the user has get Post put patch delete permission on this view
    def has_permission(self, request, view):
        print('has_perm')
        # print(view.kwargs.get("pk"), request.user.id)
        "Determine whether users have access to the model or not"
        #Any user has access to the views that use this permission class
        if request.user.is_superuser:
            #Administrators have access to the user model
            return True
        elif view.kwargs.get('pk') == str(request.user.id):
            #The ID carried is the same as the user's ID and has access right
            return True
        return False

    # has_ object_ Permission means that the user has passed the has_ Permission determines whether the user has permission to operate a specific object
    #After this setting, even Django admin administrators can only query their own user information, not the single information of other users
    def has_object_permission(self, request, view, obj):
        print('has_object_perm')
        "When obtaining a single data, judge whether the user has access rights to a data object or not"
        if request.user.id == obj.id:
            return True
        return False


class UserViewSet(viewsets.ModelViewSet):
    """
    Add, delete, modify and check the products
    """
    queryset = User.objects.all()
    serializer_ Class = userserializer # get first_ serializer_ The serializer returned by class

    ## 1. Authentication: user defined authentication class, which will override the global configuration
    # authentication_classes = (BasicAuthentication, SessionAuthentication)
    #Permission: user defined permission class
    # permission_classes = (MyPermission,)

    #3. Paging: user defined pager covers global configuration
    pagination_class = PageNum

    #4. Current limiting: user defined current limiting class
    throttle_classes = [UserRateThrottle]

    #5. Filtering: specify the filtering method class, sorting method class, one or more
    filter_ Backends = (djangofilterbackend, ordering filter) # supports both filtering and sorting
    #5.1 if the sorting field is specified and not set, the sorting function will not work
    ordering_fields = ('date_joined', 'id')  # ?ordering=-id
    #5.2 if the filter field is specified and not set, the filter function will not work
    filter_fields = ('username', 'phone', 'is_active')  # ?username=tom&phone=&is_active=true

    #Different serializers are obtained according to different requests
    def get_serializer_class(self):
        if self.action == 'unactived':
            return UserUnActiveSerializer
        else:
            return UserSerializer

    @action(methods=['get'], detail=False)
    def unactived(self, request, *args, **kwargs):
        #Get the query set and filter out the inactive users
        qs = self.queryset.filter(is_active=False)
        #Use the serializer to serialize the query set, and
        ser = self.get_serializer(qs, many=True)
        return Response(ser.data)

    @action(methods=['get'], detail=False)
    def actived(self, request, *args, **kwargs):
        #Get the query set and filter out the inactive users
        qs = self.queryset.filter(is_active=True)
        #Use the serializer to serialize the query set, and
        ser = self.get_serializer(qs, many=True)
        return Response(ser.data)

user/views.py

Using modelviewset + modelserializerUsing modelviewset + modelserializer

from rest_framework import serializers
from user.models import User


def address_validate(data):
    #Data: the data of the address field submitted by the user (Zhengzhou City, Henan Province)
    #Independent calibrator
    #Raise serializers. Validationerror ('Please fill in the actual address') ා if there is an error, an exception will be thrown
    #Yes, return the data
    return data


class UserSerializer(serializers.ModelSerializer):
    #1. Independent verifier: reset the field, replace the setting in the model, and reset the length of the address to 5
    # address_ Validate is a custom data validation function
    address = serializers.CharField(max_length=255, min_length=5, validators=[address_validate])

    #2. Single field validation_ Field name) to verify the address
    def validate_address(self, data):
        If data = ='test ':
            Raise serializers. Validationerror ('Please fill in the actual address') ා if there is an error, an exception will be thrown
        Return data

    def validate_phone(self, data):
        #It does not conform to the format of mobile phone number
        #Raise serializers. Validationerror ('mobile number format is incorrect ')
        model = self.root.Meta.model
        num = model.objects.filter(phone=data).count()
        if num > 0:
            Raise serializers. Validationerror ('mobile number already exists')
        return data

    #3. All attribute verifiers
    def validate(self, attrs):
        # attrs:{"username":"zhangsan", "phone":"18538752511", ....}
        #All attribute validators
        #There are request and view contexts in self. Context
        #Self. Context ['view ']. Action can get the action
        #Attrs is the data that needs to be serialized
        #Raise serializers. Validationerror ('xxx error ') ා error if there is a problem
        Return attrs # no problem, return data

    class Meta:
        Model = user # which table to serialize
        fields = '__ all__'          #  All fields
        #Fields = ('id ') ා fields added temporarily also need to be written here
        #Exclude = ['id '] ා exclude ID field
        # read_ only_ Fields = (',) # the specified field is read_ only,
        #Depth = 1 # depth


class UserUnActiveSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'is_ The temporary addition field also needs to be written here
        # fields = '__ all__'  #  All fields

user/serializers.py

3. Postman test interface

  • Query routing

#1. Query all users
http://192.168.56.100:8888/user/user/
#2. Query the user with id = 1
http://192.168.56.100:8888/user/user/1/
#3. Query the user name (ToM) and activate the user
http://192.168.56.100:8888/user/user/?username=tom&phone=&is_active=true
#4. Query all users and reverse sort them with ID
http://192.168.56.100:8888/user/user/?ordering=-id
#5. Query the first page of the user table, and each page displays one piece of data
http://192.168.56.100:8888/user/user/?page=1&page_size=1
  • Add (post)

http://192.168.56.100:8888/user/user/
  • Modify (put)

http://192.168.56.100:8888/user/user/1/
  • Delete (delete)

http://192.168.56.100:8888/user/user/1/