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

  use
  use
  example
 
To facilitate learning, first create a new sub application four
python manage.py 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 manage.py createsuperuser
 Fill in the user name, email address and password
root
1232@qq.com
123

  

 

 

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

  settings.py

'zh-hans'

  

 

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)
admin.site.register(models.Student,StudentAdmin)

Create super administrator user

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

  url

path('admin/', admin.site.urls),

  

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
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
      #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'

        else:
            raise AuthenticationFailed('Authentication failed')

Global use, used in the settings configuration file

    REST_FRAMEWORK = {
      'DEFAULT_AUTHENTICATION_CLASSES': (
          ...
          '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):
         pass
#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:
        :return:
        '''
        #In this way, you get the two return values of the authenticate method of the UserAuth class above
        print(request.user)  
        print(request.auth)
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)

  

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

use

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

REST_FRAMEWORK = {
    ....
    
    'DEFAULT_PERMISSION_CLASSES': (
        '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
'DEFAULT_PERMISSION_CLASSES': (
   '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

use

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

REST_FRAMEWORK = {
  
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle', #Anonymous user, not logged in
        'rest_framework.throttling.UserRateThrottle' #Logged in users
    ),
    'DEFAULT_THROTTLE_RATES': {
        '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

2)UserRateThrottle

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'
    ...
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}

  

example

Set access frequency in global configuration

    'DEFAULT_THROTTLE_RATES': {
        '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

settings.py content
'DEFAULT_THROTTLE_RATES': {
        'xx': '3/minute',
        'oo': '5/minute',
    },
    
    
views.py content

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'
    
urls.py content
    path(r'students/',views.StudentAPIView.as_view()),
    path(r'students2/',views.StudentAPI2View.as_view()),

  

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:

INSTALLED_APPS = [
    ...
    'django_filters',  # You need to register the app,
]

REST_FRAMEWORK = {
    ...
    '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')

# 127.0.0.1:8000/four/students/?sex=1

  

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.

Example:

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

# 127.0.0.1:8000/books/?ordering=-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
    
# 127.0.0.1:8000/books/?sex=1&ordering=-age

  

6. Pagination

REST framework provides paging support.

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

REST_FRAMEWORK = {
  # 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
    #127.0.0.1:8001/students/?page=5&page_size=10
    
    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:

GET  http://127.0.0.1:8000/students/?page=4

  

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

# 127.0.0.1/four/students/?p=1&size=5

  

2)LimitOffsetPagination

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

GET http://127.0.0.1/four/students/? 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):
    pass

class Student2APIView(APIView):
    def get(self,request,pk):
        try:
            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(serializer.data)

  

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'})
        response.data['status_code'] = response.status_code

    return response

Custom exception handling should also be declared in the configuration file

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}

  

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

rest_frame/settings.py

REST_FRAMEWORK = {
    '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'`

Configuration:

REST_FRAMEWORK = {
    ...
    '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):
    """
    get:
    Return all book information.
​
    post:
    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):
    """
    list:
    Return book list data
​
    retrieve:
    Return book details data
​
    latest:
    Return the latest book data
​
    read:
    Revise the reading volume of books
    """

8.4. Two point description of access interface document web page

Visit 127.0.0.1:8000/docs / 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.

file: https://xadmin.readthedocs.io/en/latest/index.html

GitHub address: https://github.com/sshwsfc/django-xadmin

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 https://codeload.github.com/sshwsfc/xadmin/zip/django2

Register the following applications in the configuration file

INSTALLED_APPS = [
    ...
    'xadmin',
    'crispy_forms',
    'reversion',
    ...
]

# Modify and use Chinese interface
LANGUAGE_CODE = 'zh-Hans'

# 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 manage.py makemigrations
python manage.py migrate

Add xadmin's route information to the total route

import xadmin
xadmin.autodiscover()

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

urlpatterns = [
    path(r'xadmin/', xadmin.site.urls),
]

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 manage.py 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 adminx.com 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)

xadmin.site.register(views.BaseAdminView, 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

xadmin.site.register(views.CommAdminView, 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