drf组件
1. 认证和权限 :
首先在admin站点中创建一个超级用户
python manage.py createsuperuser
权限控制可以限制用户对于视图的访问和对于具体数据模型对象的访问。
-
在执行视图的as_view()方法的dispatch()方法前,会先进行视图访问权限的判断
-
- AllowAny 允许所有用户 (默认) - IsAuthenticated 仅通过登录认证的用户 - IsAdminUser 仅管理员用户 - IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。
在视图中通过permission_classes属性来设置,如
from rest_framework.permissions import AllowAny, IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly class ExampleAPIView(ViewSet): permission_classes = [IsAuthenticated] @action(methods=["get", "post"], detail=False) def auth(self, request): return Response("可以的")
自定义权限:
如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部
-
.has_permission(self, request, view)
是否可以访问视图, view表示当前视图对象
-
.has_object_permission(self, request, view, obj)
是否可以访问数据模型对象, view表示当前视图, obj为模型数据对象
from rest_framework.permissions import BasePermission class ConstomPermission(BasePermission): def has_permission(self, request, view): if request.user and request.user.username == "manage": return True class Example2APIView(ViewSet): permission_classes = [ConstomPermission] @action(methods=["get", "post"], detail=False) def auth(self, request): return Response("OK啦")
2. 限流throttling:
可以对接口访问的频次进行限制,以减轻服务器压力,或者实现特定的业务。
一般用于付费购买次数,投票等场景使用.
1) AnonRateThrottle 限制所有匿名未认证用户,使用IP区分用户。 使用`DEFAULT_THROTTLE_RATES['anon']` 来设置频次 2)UserRateThrottle 限制认证用户,使用User id 来区分。 使用`DEFAULT_THROTTLE_RATES['user']` 来设置频次 3)ScopedRateThrottle 限制用户对于每个视图的访问频次,使用ip或user id。
REST_FRAMEWORK = { # 配置认证方式 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' ], # Throttling 限流 'DEFAULT_THROTTLE_RATES': { 'user': '5/minute', 'anon': '5/minute', 'throttlingtest': '3/minute', }, }
views.py
# 限流 from rest_framework.throttling import UserRateThrottle, AnonRateThrottle, ScopedRateThrottle class Example3APIView(ViewSet): # throttle_classes = [UserRateThrottle, AnonRateThrottle] # 对登录用户和未登录用户进行的限流 throttle_classes = [ScopedRateThrottle] throttle_scope = 'throttlingtest' # 对视图进行限流,与登录与否无关 @action(methods=["get", "post"], detail=False) def auth2(self, request): return Response("限流操作")
3. 过滤:
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
pip install django-filter
在配置文件settings.py中增加过滤组件的设置:
INSTALLED_APPS = [ ... 'django_filters', # 需要注册应用, ] REST_FRAMEWORK = { ... # 全局配置,也可以使用局部配置 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
在视图类中添加类属性filter_fields,指定可以过滤的字段
class StudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex') # 127.0.0.1:8000/opt/students/?sex=true #单个过滤条件 # http://127.0.0.1:8000/opt/students/?sex=false&age=27 # 多个并列的过滤条件
4. 排序
views.py
# 排序 from rest_framework.filters import OrderingFilter from django_filters.rest_framework import DjangoFilterBackend class Example5APIView(GenericViewSet, ListModelMixin): serializer_class = StudentModelSerializer queryset = models.Student.objects filter_backends = [OrderingFilter, DjangoFilterBackend] # 表示排序和过滤一起使用,这个时候就要把这两个都替换成局部的,因为排序和过滤使用的是一个配置, # 如果过滤没有设置成局部的,那排序的局部设置会覆盖过滤的全局配置,导致过滤设置失效 order_fields = ["age", "class_num"] filter_fields = ["name", "age"]
5. 分页:
我们可以在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 # 每页数目 }
如果在配置settings.py文件中, 设置了全局分页,那么在drf中凡是调用了ListModelMixin的list(),都会自动分页。如果项目中出现大量需要分页的数据,
只有少数部分的分页,则可以在少部分的视图类中关闭分页功能。 class 视图类(ListAPIView): pagination_class = None
views.py
# 分页 # 偏移量分页器 LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination class Mypage(LimitOffsetPagination): default_limit = 3 # 默认限制,默认值与`PAGE_SIZE`设置一致 limit_query_param = "limit" # limit参数名,默认'limit' max_limit = 5 # 最大limit限制,默认None offset_query_param = "offset" # offset参数名,默认'offset' # 页码分页器 PageNumberPagination from rest_framework.pagination import PageNumberPagination class Numpage(PageNumberPagination): page_size = 3 # 默认每一页显示的数据量 max_page_size = 5 # 允许客户端通过get参数来控制每一页的数据量 page_size_query_param = "size" page_query_param = "pg" # 自定义页码的参数名 class Example6APIView(GenericViewSet, ListModelMixin): serializer_class = StudentModelSerializer queryset = models.Student.objects.all() pagination_class = Numpage # 选择分页器类型
6. 异常处理
在主应用的配置文件settings.py中声明自定义的异常处理
REST_FRAMEWORK = { # 异常处理 'EXCEPTION_HANDLER': 'drfdemo.exceptions.custom_exception_handler', }
APIException使用drf中所有异常的父类,他的子类有以下: - ParseError 解析错误 - AuthenticationFailed 认证失败 - NotAuthenticated 尚未认证 - PermissionDenied 权限受限 - NotFound 未找到 - MethodNotAllowed 请求方式不支持 - NotAcceptable 要获取的数据格式不支持 - Throttled 超过限流次数 - ValidationError 校验失败 也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
exceptions.py
from rest_framework.views import exception_handler as drf_exception_handler from django.db import DatabaseError from rest_framework.response import Response from rest_framework import status def custom_exception_handler(exc, context): """ 自定义异常处理函数 :param exc: 发生异常的异常对象 :param context: 异常发生时的执行上下文,就是异常发生时的环境信息 :return: 响应对象或者None """ # 先让drf自己异常判断 response = drf_exception_handler(exc, context) if not response: # 表明drf自己没有处理到这个异常 view = context["view"] if isinstance(exc, DatabaseError): return Response({"error": "数据库错误!", "error_num": 1000}, status=status.HTTP_400_BAD_REQUEST) elif isinstance(exc, ZeroDivisionError): return Response({"error": "0不能作为除数!", "error_num": 1002}, status=status.HTTP_400_BAD_REQUEST) return response
views.py
# 异常处理 class Example7APIView(ViewSet): @action(methods=["get", "post"], detail=False) def list(self,request): a = 5/0 return Response("异常处理")
7. 自动生成接口文档
pip install coreapi
在settings.py中配置接口文档。
REST_FRAMEWORK = { # 。。。 其他选项 # 接口文档 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', }
在总路由中添加接口文档路径。
from rest_framework.documentation import include_docs_urls urlpatterns = [ ... path('docs/', include_docs_urls(title='站点页面标题')) ]
浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档。
文档描述说明的定义位置
1) 单一方法的视图,可直接使用类视图的文档字符串,如
class BookListView(generics.ListAPIView): """ 返回所有图书信息. """
2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
class BookListCreateView(generics.ListCreateAPIView): """ get: 返回所有图书信息. post: 新建图书. """
3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet): """ list: 返回图书列表数据 retrieve: 返回图书详情数据 latest: 返回最新的图书数据 read: 修改图书的阅读量 """
这样就可以在自动生成的文档里看到对应方法的描述了
说明:
1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫做read
2)参数的Description需要在模型类或序列化器类的字段中以help_text选项定义,如:
class Student(models.Model): ... age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄') ...
或
class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__" extra_kwargs = { 'age': { 'required': True, 'help_text': '年龄' } }
8. admin:
admin站点默认并没有提供其他的操作给我们,所以一切功能都需要我们进行配置,在项目中,我们每次创建子应用的时候都会存在一个admin.py文件,这个文件就是用于配置admin站点功能的文件。
admin.py里面允许我们编写的代码一共可以分成2部分:
1) 列表页配置:
主要用于针对项目中各个子应用里面的models.py里面的模型,根据这些模型自动生成后台运营站点的管理功能。
admin.py
将表数据添加到admin里去
from django.contrib import admin from .models import Student class StudentModelAdmin(admin.ModelAdmin): """学生模型管理类""" pass # admin.site.register(模型类, 模型管理类) admin.site.register(Student, StudentModelAdmin)
相关配置
from django.contrib import admin from .models import Student class StudentModelAdmin(admin.ModelAdmin): """学生模型管理类""" date_hierarchy = 'born' # 按指定时间字段的不同值来进行选项排列 list_display = ['id', "name", "sex", "age", "class_num","born","my_born"] # 设置列表页的展示字段 ordering = ['-id'] # 设置默认排序字段,字段前面加上-号表示倒叙排列 actions_on_bottom = True # 下方控制栏是否显示,默认False表示隐藏 actions_on_top = True # 上方控制栏是否显示,默认False表示隐藏 list_filter = ["class_num"] # 过滤器,按指定字段的不同值来进行展示 search_fields = ["name"] # 搜索内容 def my_born(self,obj): return str(obj.born).split(" ")[0] my_born.short_description = "出生日期" # 自定义字段的描述信息 my_born.admin_order_field = "born" # 自定义字段点击时使用哪个字段作为排序条件 # admin.site.register(模型类, 模型管理类) admin.site.register(Student, StudentModelAdmin)
详情页配置:
from django.contrib import admin from .models import Student class StudentModelAdmin(admin.ModelAdmin): """学生模型管理类""" date_hierarchy = 'born' # 按指定时间字段的不同值来进行选项排列 list_display = ['id', "name", "sex", "age", "class_null","born","my_born"] # 设置列表页的展示字段 ordering = ['-id'] # 设置默认排序字段,字段前面加上-号表示倒叙排列 actions_on_bottom = True # 下方控制栏是否显示,默认False表示隐藏 actions_on_top = True # 上方控制栏是否显示,默认False表示隐藏 list_filter = ["class_null"] # 过滤器,按指定字段的不同值来进行展示 search_fields = ["name"] # 搜索内容 def my_born(self,obj): return str(obj.born).split(" ")[0] my_born.short_description = "出生日期" # 自定义字段的描述信息 my_born.admin_order_field = "born" # 自定义字段点击时使用哪个字段作为排序条件 def delete_model(self, request, obj): """当站点删除当前模型时执行的钩子方法""" print("有人删除了模型信息[添加/修改]") # raise Exception("无法删除") # 阻止删除 return super().delete_model(request, obj) # 继续删除 def save_model(self, request, obj, form, change): """ 当站点保存当前模型时 """ print("有人修改了模型信息[添加/修改]") # 区分添加和修改? obj是否有id print(obj.id) return super().save_model(request, obj, form, change) # fields = ('name', 'age', 'class_null', "description") # exclude 作用与fields相反 # readonly_fields = ["name"] # 设置只读字段 # 字段集,fieldsets和fields只能使用其中之一 fieldsets = ( ("必填项", { 'fields': ('name', 'age', 'sex') }), ('可选项', { 'classes': ('collapse',), # 折叠样式 'fields': ('class_null', 'description'), }), ) # admin.site.register(模型类, 模型管理类) admin.site.register(Student, StudentModelAdmin)
9. xadmin:
xadmin是Django的第三方扩展,是一个比Django的admin站点使用更方便的后台站点。构建于admin站点之上。
通过如下命令安装xadmin的最新版
pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2
在配置文件settings.py中注册如下应用
INSTALLED_APPS = [ ... 'xadmin', 'crispy_forms', 'reversion', ... ] # 修改使用中文界面 LANGUAGE_CODE = 'zh-Hans' # 修改时区 TIME_ZONE = 'Asia/Shanghai'
xadmin要建立自己的数据库模型类,需要进行数据库迁移
python manage.py makemigrations
python manage.py migrate
在总路由中添加xadmin的路由信息
import xadmin xadmin.autodiscover() # version模块自动注册需要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() urlpatterns = [ path('xadmin/', xadmin.site.urls), ]
创建超级用户(若未创建)
python manage.py createsuperuser
-
xadmin不再使用Django的admin.py进行功能配置了,而是需要编写代码在adminx.py文件中。
xadmin的配置文件需要我们在每个子应用中使用时先创建adminx.py
-
xadmin的站点管理类不用继承
admin.ModelAdmin
,而是直接继承object
即可。
例如:在子应用students中创建adminx.py文件。
全局配置:
import xadmin from xadmin import views class BaseSetting(object): """xadmin的基本配置""" enable_themes = True # 开启主题切换功能 use_bootswatch = True xadmin.site.register(views.BaseAdminView, BaseSetting) class GlobalSettings(object): """xadmin的全局配置""" site_title = "一一一" # 设置站点标题 site_footer = "二二二" # 设置站点的页脚 menu_style = "accordion" # 设置菜单折叠 xadmin.site.register(views.CommAdminView, GlobalSettings)
xadmin可以使用的页面样式控制基本与Django原生的admin一致
list_display = ['id', 'name', 'sex', 'age']
search_fields = ['id','name']
list_filter = ['is_delete']
- ordering 默认排序的字段 - readonly_fields 在编辑页面的只读字段 - exclude 在编辑页面隐藏的字段 - list_editable 在列表页可以快速直接编辑的字段 - show_detail_fields 在列表页提供快速显示详情信息 - refresh_times 指定列表页的定时刷新
refresh_times = [5, 10,30,60] # 设置允许后端管理人员按多长时间(秒)刷新页面
list_export = ('xls', 'xml', 'json') list_export设置为None来禁用数据导出功能 list_export_fields = ('id', 'title', 'pub_date') # 允许导出的字段
show_bookmarks = True
data_charts = { "order_amount": { 'title': '图书发布日期表', "x-field": "pub_date", "y-field": ('title',), "order": ('id',) }, # 支持生成多个不同的图表 # "order_amount": { # 'title': '图书发布日期表', # "x-field": "pub_date", # "y-field": ('title',), # "order": ('id',) # }, }
-
-
x-field 控制x轴字段
-
y-field 控制y轴字段,可以是多个值
-
这里使用的图标是来自bootstrap3的图标。
class BookInfoAdmin(object): model_icon = 'fa fa-gift' xadmin.site.register(models.BookInfo, BookInfodmin)
修改admin或者xadmin站点下的子应用成中文内容。
# 在子应用的apps.py下面的配置中,新增一个属性verbose_name from django.apps import AppConfig class StudentsConfig(AppConfig): name = 'students' verbose_name = "学生管理" # 然后在当前子应用的__init__.py里面新增一下代码: default_app_config = "students.apps.StudentsConfig"