Authentication, permission Permissions, flow Throttling, Filtering, sorting, paging, exception handling Exceptions, automatic generation of interface documents, Xadmin

To facilitate learning, first create a new sub application four
python startapp four
Because the login function needs to be used in the following functions, we use django's built-in admin site and create an administrator
python createsuperuser
 Fill in the user name, email address and password




After creating the administrator, visit the admin site. Modify the language configuration of the site first




admin site visit effect:


admin background management system is simple to use

In the application's admin Py file

from app01 import models

class StudentAdmin(admin.ModelAdmin):
    list_display = ['id','name','age','class_null']
    list_editable = ['name','age']

# admin.register(models.Student),StudentAdmin)

Create super administrator user

python createsuperuser
 Enter user name and password,Mailbox can be left blank




1. Authentication

You can configure the global default authentication scheme in the configuration file

from rest_framework import settings You can see the default

stay settings In the configuration file, we can make the following configuration to override the default configuration
      #Which is written in the front and which authentication is preferred
        'rest_framework.authentication.SessionAuthentication',  # Session authentication is actually used in the admin background. In fact, session authentication is rarely used in interface development, so we can change it to other authentication through configuration. For example, in the later projects, we use jwt, JSON, web token authentication, or some authentication with redis
        'rest_framework.authentication.BasicAuthentication',   # Basic certification. If some testers may participate in the work, they will save some certification data in memory and then verify it. We basically can't use it

Look at the effect: you can see our current login user, but you can also see it without configuration, because we have not modified the authentication system


You can also set authentication in each view_ For example, the data of many of our interfaces can be obtained by others, but some interfaces may be called to other websites, and we may need some separate authentication at that time

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.views import APIView

class ExampleView(APIView):
    # Class properties
    authentication_classes = [SessionAuthentication, BasicAuthentication] #It can also be written in the form of Yuanzu. When we use the authentication component developed by ourselves, we need to write a authentication component class ourselves and then write it in the list for use


There are two possible return values for authentication failure:

  • 401 unauthorised unauthenticated

  • 403 Permission Denied permission is prohibited


Example 1: custom authentication component

1 write an authentication class

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class APIAuth(BaseAuthentication):

    def authenticate(self, request):
        print(request) #<rest_framework.request.Request object at 0x1142bd190>   request.user

        if 1:
            return 'xx','oo'  #request.user = 'xx'  request.auth = 'oo'

            raise AuthenticationFailed('Authentication failed')

Global use, used in the settings configuration file

          'four.utils.auth.APIAuth',  #Path to class


Used in detail views:

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from four.utils.auth import APIAuth

class AuthAPIView(APIView):
    authentication_classes = [APIAuth,]
    def get(self,request):
        print('>>>>',request.user)  #Anonymous user, anonymous user, fake user
        print('>>>>',request.auth)  #Anonymous user, anonymous user, fake user
        #>>>> root
        return Response({'msg':'hello'})

Examples from my blog:

class UserAuth():
   def authenticate_header(self,request):
#The authenticate method is fixed and must have a parameter. This parameter is a new request object. If you don't believe it, look at the source code
    def authenticate(self,request):
				print('Do something')
        if 1:
        #It will be found in the source code that this method will have two return values, and these two return values are encapsulated in a new request object, request User -- > username and request Auth -- > token value. These two values are used as the return result after authentication
            return "chao","asdfasdfasdf"

class BookView(APIView):
    #The authentication component must be executed before the get, post and other methods are executed. Remember the source code? This component is called in the place of dispatch. We write a UserAuth class above
    authentication_classes = [UserAuth,] #Multiple authentication classes can be written, one by one
    def get(self,request):
        View all books
        :param request:
        #In this way, you get the two return values of the authenticate method of the UserAuth class above
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(


2. Permissions

Permission control can restrict users' access to views and specific data objects.

  • Before executing the dispatch() method of the view, the access permission of the view will be judged first

  • Through get_ When object() obtains a specific object, it will judge the access permission of the model object


The default permission management class can be set globally in the configuration file, such as

        'rest_framework.permissions.IsAuthenticated', #You can access our interface only when you are logged in. You can see the effect by checking whether you can access our normal interface after exiting the admin background

If not specified, the following default configuration is used

from rest_framework import permissions
   'rest_framework.permissions.AllowAny', #It means that anyone can perform any operation without restrictions

You can also use permission in a specific view_ Classes property, such as

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)


Permissions provided

  • AllowAny allows all users

  • IsAuthenticated only authenticated users

  • IsAdminUser is only an administrator user (you can create a user through admin to test)

  • IsAuthenticatedOrReadOnly users who have logged in and authenticated can add, delete and modify data. Those who have not logged in and authenticated can only view data.

give an example

from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]


Custom permissions

To customize permissions, you need to inherit rest_framework.permissions.BasePermission parent class and implements any or all of the following two methods

  • .has_permission(self, request, view)

    Whether the view can be accessed. View indicates the current view object

  • .has_object_permission(self, request, view, obj)

    Whether the data object can be accessed. View indicates the current view and obj is the data object

For example:

Under the current sub application, create a permission file permissions To declare a custom permission class in py:

from rest_framework.permissions import BasePermission

class IsXiaoMingPermission(BasePermission):
    def has_permission(self, request, view):
        if( request.user.username == "xiaoming" ):
            return True


from .permissions import IsXiaoMingPermission
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [IsXiaoMingPermission]


3. Current limiting Throttling

The frequency of interface access can be limited to reduce the pressure on the server.

It is generally used in paid purchase times, voting and other scenarios


You can use default in the configuration file_ THROTTLE_ Classes and DEFAULT_THROTTLE_RATES for global configuration,

        'rest_framework.throttling.AnonRateThrottle', #Anonymous user, not logged in
        'rest_framework.throttling.UserRateThrottle' #Logged in users
        'anon': '100/day',
        'user': '1000/day'

  DEFAULT_THROTTLE_RATES , you can use , second, minute, hour , or day to indicate the period.

Source code:
{'s': 1, 'm': 60, 'h': 3600, 'd': 86400} m Indicates minutes, which can be written m,You can also write minute

You can also use throttle in a specific view_ Classess attribute, such as

from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = (UserRateThrottle,)  #Local configuration


Optional current limiting class

1) AnonRateThrottle

Restrict all anonymous unauthenticated users and use IP to distinguish users.

Use DEFAULT_THROTTLE_RATES['anon '] to set the frequency


Restrict authenticated users and use User id to distinguish them.

Use DEFAULT_THROTTLE_RATES['user '] to set the frequency

3) ScopedRateThrottle (pending...)

Limit the user's access frequency to each view. Use ip or user id to find the user id first. If the user id is not set, the ip address will be used.

For example: Global

class ContactListView(APIView):
    throttle_scope = 'contacts'

class ContactDetailView(APIView):
    throttle_scope = 'contacts'

class UploadView(APIView):
    throttle_scope = 'uploads'
        'contacts': '1000/day',
        'uploads': '20/day'



Set access frequency in global configuration

        'anon': '3/minute',
        'user': '10/minute'


from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import RetrieveAPIView
from rest_framework.throttling import UserRateThrottle

class StudentAPIView(RetrieveAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    authentication_classes = [SessionAuthentication]
    permission_classes = [IsAuthenticated]
    throttle_classes = (UserRateThrottle,)

ScopedRateThrottle local usage example content
        'xx': '3/minute',
        'oo': '5/minute',

from rest_framework.throttling import ScopedRateThrottle

class StudentAPIView(ListAPIView):
    queryset = models.Student.objects.all()
    serializer_class = StudentModelSerializer
    throttle_classes = [ScopedRateThrottle,]
    throttle_scope = 'xx'

class StudentAPI2View(ListAPIView):
    queryset = models.Student.objects.all()
    serializer_class = StudentModelSerializer
    throttle_classes = [ScopedRateThrottle, ]
    throttle_scope = 'oo' content


4. Filtering

List data may need to be filtered according to fields. We can add Django fitlter extension to enhance support.

pip install django-filter  

Add the settings of filtering backend in the configuration file:

    'django_filters',  # You need to register the app,

    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)

Add filter to view_ The fields property specifies the fields that can be filtered

class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    filter_fields = ('age', 'sex')



5. Sorting

For list data, the REST framework provides an OrderingFilter filter to help us quickly indicate that the data is sorted according to the specified fields.

usage method:

Set filter in class view_ Backends, using rest_framework.filters.OrderingFilter filter: the REST framework will check whether the ordering parameter is included in the requested query string parameters. If the ordering parameter is included, the dataset will be sorted according to the sorting field specified by the ordering parameter.

The optional field value of the ordering parameter that can be passed by the front end needs to be in the ordering_fields.


class StudentListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'age')

# Must be ordering = a value
# -id indicates that the id fields are sorted in reverse order
# id indicates ascending sorting for the id field

If you need to sort again after filtering, you need to combine the two!  

from rest_framework.generics import ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend #You need to use it to use it together
class Student3ListView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_fields = ('age', 'sex')
    # Because filter_backends is a local filter configuration, which will override the global configuration, so it is necessary to declare the core class of the filter component again,
    # Otherwise, the filtering function will fail
    filter_backends = [OrderingFilter,DjangoFilterBackend]
    ordering_fields = ('id', 'age')
    # It is aimed at the list method in the inherited class


6. Pagination

REST framework provides paging support.

We can set the global paging mode in the configuration file, such as:

  # Global paging. Once global paging is set, the list pages provided by the list method in the view extension class in drf will produce paging effect. Therefore, global paging is generally not used
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100  # Maximum data per page

You can also customize the Pagination class to add different Pagination behaviors to the view. Through Pagination in view_ Class attribute.

class LargeResultsSetPagination(PageNumberPagination):
    page_size = 1000  #How many are displayed on each page
    page_size_query_param = 'page_size'
    max_page_size = 10000
class BookDetailView(RetrieveAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    pagination_class = LargeResultsSetPagination

* * Note: if the paging function is turned off in the view, you only need to set it in the view**

pagination_class = None


Optional pager

1) PageNumberPagination

Form of front-end access website:



Properties that can be defined in subclasses:

  • page_size number of pages

  • page_ query_ The number of pages sent by param front-end is the keyword name. The default is "page"

  • page_ size_ query_ The number of pages per page sent by param front-end keyword name. The default is None

  • max_page_size the maximum number of pages that can be set in the front end

# Declare the configuration class of paging
from rest_framework.pagination import PageNumberPagination
class StandardPageNumberPagination(PageNumberPagination):
    # By default, the amount of data displayed on each page
    page_size = 2
    # Allows the client to control the amount of data on each page through the get parameter
    page_size_query_param = "size"
    max_page_size = 10  #When the client specifies the number of pieces of data obtained through size, the maximum number cannot exceed
    # Parameter name of custom page number
    page_query_param = "p"

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    pagination_class = StandardPageNumberPagination




Form of front-end access to website: # in fact, it is to get data through offset

GET Limit = 100 & offset = 400 # start from the record with subscript 400 and take 100 records


Properties that can be defined in subclasses:

  • default_ The default limit is the size of data per page. The default value is the same as page_ The size setting is consistent

  • limit_query_param limit parameter name. The default is' limit '. You can change the name through this parameter

  • offset_query_param offset parameter name. The default is' offset '. You can change the name through this parameter

  • max_limit maximum limit, default None, unlimited

from rest_framework.pagination import LimitOffsetPagination
class StandardLimitOffsetPagination(LimitOffsetPagination):
    # By default, the amount of data queried on each page is similar to the above page_size
    default_limit = 2
    limit_query_param = "size"  #The default is limit
    offset_query_param = "start"  #The default is offset

class StudentAPIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # Call page number paging class
    # pagination_class = StandardPageNumberPagination
    # Call query offset paging class
    pagination_class = StandardLimitOffsetPagination


7. Exception handling Exceptions

Look at a simple example

class APIError(Exception):

class Student2APIView(APIView):
    def get(self,request,pk):
            instance = Student.objects.get(pk=pk)
        except Student.DoesNotExist:
            raise APIError('custom API error')
            return Response({"message":"The goods visited have been taken off the shelves~"})

        serializer = StudentModelSerializer(instance=instance)
        return Response(


The REST framework provides exception handling, and we can customize the exception handling function.

You can create a utils folder with exceptions Py file, write the name casually, and then write the following content

from rest_framework.views import exception_handler

def custom_exception_handler(exc, context): #Custom error handling function
    	exc Wrong object
      context Some context information when the exception occurs
    # First call the default exception handling method of REST framework to obtain the standard error response object
    response = exception_handler(exc, context) #This function is provided by drf. It handles some errors, but if it cannot handle them, it will return None. Therefore, if it is None, we need to handle the errors ourselves

    # Add custom exception handling here
    if response is None:
      	if isinstance(exc,APIError)
        #Here you can record the error information, which is usually recorded in a file. You can use the log system to record it
        # Return repose ({'MSG': 'custom API error'})['status_code'] = response.status_code

    return response

Custom exception handling should also be declared in the configuration file

    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'


If not declared, the default method will be adopted, as follows


    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'


For example:

In addition, handle exceptions about the database

from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError

def exception_handler(exc, context):
    response = drf_exception_handler(exc, context)

    if response is None:
        view = context['view'] #Wrong method or function name
        if isinstance(exc, DatabaseError):
            print('[%s]: %s' % (view, exc))
            response = Response({'detail': 'Server internal error'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

    return response


Exceptions defined by REST framework

  • APIException is the parent class of all exceptions

  • ParseError parsing error

  • AuthenticationFailed authentication failed

  • NotAuthenticated not authenticated

  • PermissionDenied permission denied

  • NotFound not found

  • MethodNotAllowed request method is not supported

  • The data format to be obtained by NotAcceptable is not supported

  • Number of times Throttled exceeds current limit

  • ValidationError validation failed

In other words, the exceptions listed above do not need to be handled by ourselves. Many exceptions not listed above need to be handled by ourselves in custom exceptions.

8. Automatically generate interface documents

REST framework can automatically help us generate interface documents.

Interface documents are presented as web pages.

Automatic interface documents can generate views inherited from APIView and its subclasses.

8.1. Installation dependency

The generation of interface documents by REST framewrok requires the support of core API library.

pip install coreapi

8.2. Set interface document access path

Add the interface document path to the general route.

The view corresponding to the document route is configured as rest_framework.documentation.include_docs_urls,

The parameter title is the title of the interface document website.

from rest_framework.documentation import include_docs_urls

urlpatterns = [
    path('docs/', include_docs_urls(title='Site page title'))

If an error is reported, the following error indicates that we lack a dependency. Just configure it

`'AutoSchema' object has no attribute 'get_link'`


    'DEFAULT_SCHEMA_CLASS': "rest_framework.schemas.AutoSchema",



8.3. Definition location of document description

1) For a single method view, you can directly use the document string of the class view, such as

class BookListView(generics.ListAPIView):
    get: Return all book information.
    post: Add record
    #Note that this is the annotation declared in the class. If you declare other annotations in the method, this annotation will be overwritten

2) For a view containing multiple methods, separate the method definitions in the document string of the class view, such as

class BookListCreateView(generics.ListCreateAPIView):
    Return all book information.
    New book.

3) For view set ViewSet, the definition is still sealed in the document string of class view, but it should be distinguished by action name, such as

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    Return book list data
    Return book details data
    Return the latest book data
    Revise the reading volume of books

8.4. Two point description of access interface document web page

Visit / in the browser to see the automatically generated interface document.


Two points:

1) The retrieve name in the ViewSet of the view set is called read in the interface document website

2) The Description of the parameter needs help in the field of the model class or serializer class_ Text option definition, such as:

class Student(models.Model):
    age = models.IntegerField(default=0, verbose_name='Age', help_text='Age')

Or note that if you use the same serializer for multiple applications, it may cause help_ The content of text shows some problems and small things

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
        extra_kwargs = {
            'age': {
                'required': True,
                'help_text': 'Age'


9. Xadmin

xadmin is a third-party extension of Django, which is more powerful and convenient than using Django's admin site.


GitHub address:

9.1. install

Install the latest version of xadmin through the following command. The installation method in its document has not been updated for a long time, which will lead to your unsuccessful installation, so we use the following website for installation

pip install

Register the following applications in the configuration file


# Modify and use Chinese interface

# Modify time zone
TIME_ZONE = 'Asia/Shanghai'


9.2. Use the global configuration of the site to manage the site Model

xadmin has its own database model class, which requires database migration

python makemigrations
python migrate

Add xadmin's route information to the total route

import xadmin

# The version module automatically registers models that require version control
from xadmin.plugins import xversion

urlpatterns = [

If you have not created a super user before, you need to create it. If you have, you can directly use the previous one.

python createsuperuser

9.3 use

  • Xadmin no longer uses Django's admin Py, but you need to write code in Adminx In the. Py file, each application can write an admin. X Py configures the xadmin site.

  • xadmin's site management class does not inherit admin Modeladmin, but directly inherit the object.

For example: create in the sub application Py file.

Global configuration of the site

import xadmin
from xadmin import views

class BaseSetting(object):
    """xadmin Basic configuration of"""
    enable_themes = True  # Turn on the theme switching function
    use_bootswatch = True # Boot wheel (actually our left menu bar), BaseSetting)

class GlobalSettings(object):
    """xadmin Global configuration of"""
    site_title = "Lu Feixue City"  # Set site title
    site_footer = "Luffy Learning City Co., Ltd"  # Set the footer of the site
    menu_style = "accordion"  # Set menu collapse, GlobalSettings)

Site Model management

The page style control that xadmin can use is basically the same as the native admin of Django.


You can define one in the models class__ str__ Method to define what the object is displayed as

  • list_display controls the fields displayed in the list

list_display = ['id', 'btitle', 'bread', 'bcomment']
  • search_fields controls the field names that can be searched through the search box. xadmin uses fuzzy query

search_fields = ['id','btitle']

  list_filter the columns that can be filtered, including classification, gender and status

list_filter = ['is_delete']

Fields sorted by default in ordering

ordering = ['-age',]  #-Reverse order

  show_detail_fields provides a quick display of detailed information on the list page

show_detail_fields = ['id',]

  list_editable fields that can be edited quickly and directly on the list page

list_editable = ['name','age',]

  refresh_times specifies the scheduled refresh of the list page

refresh_times = [5, 10,30,60]  # Set how long (seconds) the back-end manager is allowed to refresh the page. After selection, it can refresh automatically

  list_export controls the optional format of data exported from the list page

list_export = ('xls', 'json','csv')#Write Yuanzu or list_ Set export to None to disable the data export function
list_export_fields = ('id', 'btitle', 'bpub_date') #Set the fields allowed to export

  show_bookmarks controls whether the bookmark function is displayed

show_bookmarks = True #False hides this function

  data_charts controls the style in which charts are displayed

data_charts = {
        "order_amount": {  #Casually write the name order_amount
          'title': 'Book release date table', 
          "x-field": "bpub_date", 
          "y-field": ('btitle',),
          "order": ('id',),
    #    Support the generation of multiple different charts
    #    "order_amount2": {
    #      'title ':' book release date table ', 
    #      "x-field": "bpub_date", 
    #      "y-field": ('btitle',),
    #      "order": ('id',)
    #    },


  • title control icon name

  • x-field controls the x-axis field

  • y-field controls the y-axis field, which can be multiple values

  • order controls the default sort

  model_icon of icon control menu [for icon settings, please refer to the icon css name of font awesome]

model_icon = 'fa fa-gift'

  readonly_fields is a read-only field on the edit page

readonly_fields = ['name',]

exclude the fields hidden on the editing page, such as delete to determine whether the data is deleted_ The status field is generally used to identify whether the field has been deleted, but it will not be deleted in the database

exclude = ['name',]

This is not all functions. You can refer to its documentation. We may also need to customize, adjust or add some functions that it does not have, which will be discussed later





Posted by Stoneguard on Tue, 10 May 2022 16:34:51 +0300