序列化:
api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:
序列化: 把我们识别的数据转换成指定的格式提供给别人。
例如:我们在django中获取到的数据默认是模型对象,但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
反序列化:把别人提供的数据转换/还原成我们需要的格式。
例如:前端js提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。
django序列化器:
图片来自:https://blog.csdn.net/wuuud1/article/details/91863489
一、什么是Django Rest_Framework
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework
github: https://github.com/encode/django-rest-framework/tree/master
英文文档:https://www.django-rest-framework.org/
特点
-
提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
-
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
-
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
-
多种身份认证和权限认证方式的支持;[jwt]
-
内置了限流系统;
-
直观的 API web 界面;
-
可扩展性,插件丰富
二、安装DRF
DRF需要以下依赖:
-
Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
-
Django (1.10, 1.11, 2.0)
DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)
pip3 install django==2.2
pip3 install djangorestframework
三、创建django项目
在**settings.py**的**INSTALLED_APPS**中添加'rest_framework'。
INSTALLED_APPS = [ ... 'rest_framework', ]
接下来就可以使用DRF提供的功能进行api接口开发了。在项目中如果使用rest_framework框架实现API接口,主要有以下三个步骤:
-
将请求的数据(如JSON格式)转换为模型类对象
-
操作数据库
-
四、drf简写代码示例
1、创建模型操作类
class Student(models.Model): # 模型字段 name = models.CharField(max_length=100,verbose_name="姓名",help_text='提示文本:不能为空') sex = models.BooleanField(default=1,verbose_name="性别") age = models.IntegerField(verbose_name="年龄") class_null = models.CharField(max_length=5,verbose_name="班级编号") description = models.TextField(max_length=1000,verbose_name="个性签名") class Meta: db_table="tb_student" verbose_name = "学生" verbose_name_plural = verbose_name
终端下,执行数据迁移报错:
注释掉 python/site-packages/django/backends/mysql/base.py中的35和36行代码。
执行数据迁移发生以下错误:
解决方法:
backends/mysql/operations.py146行里面新增一个行代码:
2、创建序列化器
例如,在django项目中创建学生子应用。
python manage.py startapp students
创建一个StudentModelSerializer用于序列化与反序列化
# 创建序列化器类,回头会在试图中被调用 class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__"
-
-
fields 指明该序列化器包含模型类中的哪些字段,'all
3、编写视图
在students应用的views.py中创建视图StudentViewSet,这是一个视图集合。
from rest_framework.viewsets import ModelViewSet from .models import Student from .serializers import StudentModelSerializer # Create your views here. class StudentViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer
- queryset 指明该视图集在查询数据时使用的查询集
- serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器
4、定义路由
在students应用的urls.py中定义路由信息。
from . import views from rest_framework.routers import DefaultRouter # 路由列表 urlpatterns = [] router = DefaultRouter() # 可以处理视图的路由器,自动通过视图来生成增删改查的url路径 router.register('students', views.StudentViewSet) #students是生成的url前缀,名称随便写, 向路由器中注册视图集 urlpatterns += router.urls # 将路由器中的所以路由信息追到到django的路由列表中
最后把students子应用中的路由文件加载到总路由文件中.
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path("stu/",include("students.urls")), ]
5、运行:
python manage.py runserver
在浏览器中输入网址127.0.0.1:8000,可以看到DRF提供的API Web浏览页面:
点击POST后,返回如下页面信息:
点击PUT,返回如下页面信息:
返回,如下页面:
五、序列化器-Serializer
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串 2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型 3. 反序列化,完成数据校验功能
1、定义序列化器
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
python manage.py startapp sers
模型类还用Student
from django.db import models # Create your models here. class Student(models.Model): # 模型字段 name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:账号不能为空!") sex = models.BooleanField(default=True,verbose_name="性别") age = models.IntegerField(verbose_name="年龄") class_null = models.CharField(max_length=5,verbose_name="班级编号") description = models.TextField(verbose_name="个性签名") class Meta: db_table="tb_student" verbose_name = "学生" verbose_name_plural = verbose_name
我们想为这个模型类提供一个序列化器,可以定义如下:
from rest_framework import serializers # 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer # 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化 class StudentSerializer(serializers.Serializer): """学生信息序列化器""" # 1. 需要进行数据转换的字段 id = serializers.IntegerField() name = serializers.CharField() age = serializers.IntegerField() sex = serializers.BooleanField() description = serializers.CharField() # 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息 # 3. 验证提交的数据的代码 # 4. 编写添加和更新模型的代码
字段构造方式 | |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 微软时间戳,通过微秒生成一个随机字符串 |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField |
选项参数:
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_length | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最大值 |
min_value |
2、创建Serializer对象
定义好Serializer类后,就可以创建Serializer对象了。
Serializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
serializer = AccountSerializer(account, context={'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
-
-
序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
-
序列化器的字段声明类似于我们前面使用过的表单系统。
-
开发restful api时,序列化器会帮我们把模型数据转换成字典.
-
3、序列化器的使用
序列化器的使用分两个阶段:
-
在客户端请求时,使用序列化器可以完成对数据的反序列化。
-
3.1、序列化
1) 先查询出一个学生对象
from students.models import Student student = Student.objects.get(id=3)
2) 构造序列化器对象
from .serializers import StudentSerializer serializer = StudentSerializer(instance=student) -- {}
3)获取序列化数据
serializer.data # {'id': 4, 'name': '小张', 'age': 18, 'sex': True, 'description': '猴赛雷'}
完整视图代码:
from django.views import View from students.models import Student from .serializers import StudentSerializer from django.http.response import JsonResponse class StudentView(View): """使用序列化器序列化转换单个模型数据""" def get(self,request,pk): # 获取数据 student = Student.objects.get(pk=pk) # 数据转换[序列化过程] serializer = StudentSerializer(instance=student) print(serializer.data) # 响应数据 return JsonResponse(serializer.data)
"""使用序列化器序列化转换多个模型数据""" def get(self,request): # 获取数据 student_list = Student.objects.all() # 转换数据[序列化过程] # 如果转换多个模型对象数据,则需要加上many=True serializer = StudentSerializer(instance=student_list,many=True) print( serializer.data ) # 序列化器转换后的数据 # 响应数据给客户端 # 返回的json数据,如果是列表,则需要声明safe=False, json_dumps_params={'ensure_ascii':False} 中文 return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii':False}) # 访问结果: # [OrderedDict([('id', 1), ('name', 'xiaoming'), ('age', 20), ('sex', True), ('description', '测试')]), OrderedDict([('id', 2), ('name', 'xiaohui'), ('age', 22), ('sex', True), ('description', '后面来的测试')]), OrderedDict([('id', 4), ('name', '小张'), ('age', 18), ('sex', True), ('description', '猴赛雷')])]
在ser应用中创建Urls.py
from django.urls import path from . import views urlpatterns = [ path(r'students/',views.StudentView.as_view()), ]
别忘了在总路由中include一下
from django.contrib import admin from django.urls import path,include,re_path urlpatterns = [ path('admin/', admin.site.urls), path('stu/',include('students.urls')), path('ser/',include('sers.urls')), ]
3.2、反序列化
3.2.1、数据验证
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
为了方便演示效果,我们单独再次创建一个子应用unsers,。
python manage.py startapp unsers
定义序列化器,代码:
from rest_framework import serializers class StudentSerializer(serializers.Serializer): # 需要转换的字段声明 # 小括号里面声明主要提供给反序列化使用的 name = serializers.CharField(required=True, max_length=20) age = serializers.IntegerField(max_value=150, min_value=0,required=True) sex = serializers.BooleanField(default=True) description = serializers.CharField(required=False,allow_null=True, allow_blank=True) #required=False,字段都可以不传递给后端,allow_null=True,允许提交过来的数据为空值(null--None),allow_blank=True 允许提交过来的数据为空字符串 # 如果序列化器调用的模型中的字段声明,则需要声明Meta类 # 验证 # 添加和更新代码
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
# Create your views here. from django.http import JsonResponse from django.views import View from .serializers import StudentSerializer from students.models import Student class StudentView(View): def post(self,request): """添加一个学生""" # 接受参数 post_data = request.POST data = { "name":post_data.get('name'), "age":post_data.get('age'), "sex":post_data.get('sex'), "description":post_data.get('description'), } # 调用序列化器进行反序列化验证和转换 serializer = StudentSerializer(data=data) serializer.errors #查看错误信息 # 当验证失败时,可以直接通过声明 raise_exception=True 让django直接跑出异常,那么验证出错之后,直接就再这里报错,程序中断了就 result = serializer.is_valid(raise_exception=True) print( "验证结果:%s" % result ) # 获取通过验证后的数据 print( serializer.validated_data ) # form -- clean_data # 保存数据 student = Student.objects.create( name=serializer.validated_data.get("name"), age=serializer.validated_data.get("age"), sex=serializer.validated_data.get("sex") ) print(student) # 返回响应结果给客户端 # alt + enter,可以实现快速导包 return JsonResponse({"message": "ok"})
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:
局部钩子
对`<field_name>`字段进行验证,如
class StudentSerializer(serializers.Serializer): """学生数据序列化器""" ... # 序列化器中可以自定义单个字段的验证方法 def validate_<字段名>(用户提交的字段数据): def validate_name(self,data): if(data=="kkk"): raise serializers.ValidationError("用户名不能是kkk") # 验证完成以后务必要返回字段值 return data
全局钩子
class StudentSerializer(serializers.Serializer): """学生数据序列化器""" ... # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数 def validate(self,data): name = data.get("name") if(name == "python"): raise serializers.ValidationError("用户名不能是python") age = data.get("age") if(age==0): raise serializers.ValidationError("年龄不能是0") # 验证完成以后务必要返回data return data
在字段中添加validators选项参数,也可以补充验证行为,如
def check_age(age): if age ==50: raise serializers.ValidationError("年龄不能刚好是50") return age class StudentSerializer(serializers.Serializer): # 需要转换的字段声明 # 小括号里面声明主要提供给反序列化使用的 name = serializers.CharField(required=True, max_length=20) age = serializers.IntegerField(max_value=150, min_value=0,required=True,validators=[check_age]) sex = serializers.BooleanField(default=True) description = serializers.CharField(required=False,allow_null=True, allow_blank=True)
3.2.2、反序列化-保存数据
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
# Create your views here. from django.http import JsonResponse from django.views import View from .serializers import StudentSerializer from students.models import Student class StudentView(View): def post(self,request): """添加一个学生""" # 接受参数 post_data = request.POST data = { "name":post_data.get('name'), "age":post_data.get('age'), "sex":post_data.get('sex'), "description":post_data.get('description'), } serializer = StudentSerializer(data=data) serializer.errors result = serializer.is_valid(raise_exception=True) print( "验证结果:%s" % result ) print( serializer.validated_data ) student = Student.objects.create( name=serializer.validated_data.get("name"), age=serializer.validated_data.get("age"), sex=serializer.validated_data.get("sex") ) print(student) return JsonResponse({"message": "ok"})
还可以通过序列化器提供的create()和update()两个方法来实现。
from rest_framework import serializers from students.models import Student def check_age(age): if age ==50: raise serializers.ValidationError("年龄不能刚好是50") return age class StudentSerializer(serializers.Serializer): # 需要转换的字段声明 # 小括号里面声明主要提供给反序列化使用的 name = serializers.CharField(required=True, max_length=20) age = serializers.IntegerField(max_value=150, min_value=0,required=True,validators=[check_age]) sex = serializers.BooleanField(default=True) description = serializers.CharField(required=False,allow_null=True, allow_blank=True) #required=False, # 如果序列化器调用的模型中的字段声明,则需要声明Meta类 # 验证 # 序列化器中可以自定义单个字段的验证方法 def validate_<字段名>(用户提交的字段数据): def validate_name(self,data): if(data=="kkk"): raise serializers.ValidationError("用户名不能是kkk") # 验证完成以后务必要返回字段值 return data # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数 def validate(self,data): name = data.get("name") if(name == "python"): raise serializers.ValidationError("用户名不能是python") age = data.get("age") if(age==0): raise serializers.ValidationError("年龄不能是0") # 验证完成以后务必要返回data return data # 添加和更新代码 # 序列化器中会提供了两个方法: create 和 update,方法名是固定的 def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据 student = Student.objects.create( name=self.validated_data.get("name"), age=self.validated_data.get("age"), sex=self.validated_data.get("sex") ) return student def update(self,instance,validated_data): #instance表示当前更新的记录对象 """更新学生信息""" instance.name=validated_data.get("name") instance.sex=validated_data.get("sex") instance.age=validated_data.get("age") instance.description=validated_data.get("description") # 调用模型的save更新保存数据 instance.save() return instance
实现了上述两个方法后,在视图中调用序列化器进行反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
student = serializer.save() #如果是添加,自动会调用create,更新就自动调用update
视图代码:
# Create your views here. from django.http import JsonResponse from django.views import View from .serializers import StudentSerializer from students.models import Student class StudentView(View): def post(self,request): """添加一个学生""" .... def put(self,request): """更新学生信息""" # 接受参数 data = { "id":9, "name":"abc", "age":18, "sex":1, "description":"测试", } # 获取要修改的数据 instance = Student.objects.get(pk=data.get("id")) # 调用序列化器 serializer = StudentSerializer(instance=instance,data=data) # 验证 serializer.is_valid(raise_exception=True) # 转换成模型数据 student = serializer.save() return JsonResponse({"message": "ok"})
3.2.3、附加说明
1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
# request.user 是django中记录当前登录用户的模型对象 serializer.save(owner=user)
2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
# 更新学生的部分字段信息,当数据库允许为空,但是序列化器要求必须字段填写的时候,可以使用以下方式避开 serializer = StudentSerializer(instance=instance, data=data, partial=True)
把上面序列化器子应用sers和反序列化器子应用unsers里面的序列化器进行对比。
from rest_framework import serializers # 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer # 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化 class StudentSerializer(serializers.Serializer): """学生信息序列化器""" # 1. 需要进行数据转换的字段 id = serializers.IntegerField() name = serializers.CharField() age = serializers.IntegerField() sex = serializers.BooleanField() description = serializers.CharField()
from rest_framework import serializers from students.models import Student def check_age(age): if age ==50: raise serializers.ValidationError("年龄不能刚好是50") return age class StudentSerializer(serializers.Serializer): # 需要转换的字段声明 # 小括号里面声明主要提供给反序列化使用的 name = serializers.CharField(required=True, max_length=20) age = serializers.IntegerField(max_value=150, min_value=0,required=True,validators=[check_age]) sex = serializers.BooleanField(default=True) description = serializers.CharField(required=False, allow_null=True, allow_blank=True) # 如果序列化器调用的模型中的字段声明,则需要声明Meta类 # 验证 # 序列化器中可以自定义单个字段的验证方法 def validate_<字段名>(用户提交的字段数据): def validate_name(self,data): if(data=="老男孩"): raise serializers.ValidationError("用户名不能是老男孩") # 验证完成以后务必要返回字段值 return data # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数 def validate(self,data): name = data.get("name") if(name == "python"): raise serializers.ValidationError("用户名不能是python") age = data.get("age") if(age==0): raise serializers.ValidationError("年龄不能是0") # 验证完成以后务必要返回data return data # 添加和更新代码 # 序列化器中会提供了两个方法: create 和 update,方法名是固定的 def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据 student = Student.objects.create( name=self.validated_data.get("name"), age=self.validated_data.get("age"), sex=self.validated_data.get("sex") ) return student def update(self,instance,validated_data): """更新学生信息""" instance.name=validated_data.get("name") instance.sex=validated_data.get("sex") instance.age=validated_data.get("age") instance.description=validated_data.get("description") # 调用模型的save更新保存数据 instance.save() return instance
所以在开发的时候,我们一般都是直接写在一起,那么有些字段只会出现在序列化器阶段,例如ID。还有些字段只会出现在反序列化阶段,例如:用户密码。
那么, 我们需要在序列化器类中,声明那些字段是在序列化时使用,哪些字段在反序列化中使用了。
最终序列化器中的代码:
from rest_framework import serializers from students.models import Student def check_age(age): if age ==50: raise serializers.ValidationError("年龄不能刚好是50") return age class StudentSerializer(serializers.Serializer): # 需要转换的字段声明 # 小括号里面声明主要提供给反序列化使用的 id=serializers.IntegerField(read_only=True) #read_only=True读取数据时能读出来,反序列化校验数据的时候不需要校验。 name = serializers.CharField(required=True, max_length=20) age = serializers.IntegerField(max_value=150, min_value=0,required=True,validators=[check_age]) sex = serializers.BooleanField(default=True,write_only=True)#write_only=True读取数据时不能读出来。但是反序列化校验数据保存时,需要传给我们的序列化器 description = serializers.CharField(required=True, allow_null=True, allow_blank=True) # 如果序列化器调用的模型中的字段声明,则需要声明Meta类 # 验证 # 序列化器中可以自定义单个字段的验证方法 def validate_<字段名>(用户提交的字段数据): def validate_name(self,data): if(data=="老男孩"): raise serializers.ValidationError("用户名不能是老男孩") # 验证完成以后务必要返回字段值 return data # 方法名时固定的,用于验证多个字段,参数就是实例化序列化器类时的data参数 def validate(self,data): name = data.get("name") if(name == "python"): raise serializers.ValidationError("用户名不能是python") age = data.get("age") if(age==0): raise serializers.ValidationError("年龄不能是0") # 验证完成以后务必要返回data return data # 添加和更新代码 # 序列化器中会提供了两个方法: create 和 update,方法名是固定的 def create(self, validated_data): # validated_data 参数,在序列化器调用时,会自动传递验证完成以后的数据 student = Student.objects.create( name=self.validated_data.get("name"), age=self.validated_data.get("age"), sex=self.validated_data.get("sex") ) return student def update(self,instance,validated_data): """更新学生信息""" instance.name=validated_data.get("name") instance.sex=validated_data.get("sex") instance.age=validated_data.get("age") instance.description=validated_data.get("description") # 调用模型的save更新保存数据 instance.save() return instance
3.3、模型类序列化器
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
-
基于模型类自动生成一系列字段
-
基于模型类自动为Serializer生成validators,比如unique_together
-
包含默认的create()和update()的实现
新建一个子应用msers。
python manage.py startapp msers
创建一个StudentModelSerializer序列化器
from rest_framework import serializers from students.models import Student class StudentModelSerializer(serializers.ModelSerializer): # 字段声明 # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段 class Meta: model = Student fields = ["id","name","age","description","sex"] # fields = "__all__" # 表示操作模型中的所有字段 # 添加额外的验证选项 exclude = ['id',] # 排除字段 extra_kwargs = { "sex":{"write_only":True,}, "id":{"read_only":True,} }
3.3.1、指定字段
1) 使用**fields**来明确字段,`__all__`表名包含所有字段,也可以写明具体哪些字段,如
class StudentModelSerializer(serializers.ModelSerializer): """学生数据序列化器""" class Meta: model = Student fields = ['id', 'age', 'name',"description"]
class StudentModelSerializer(serializers.ModelSerializer): """学生数据序列化器""" class Meta: model = Student exclude = ['sex']
3) 指明只读字段[少用,通过extra_kwargs更方便一些],
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class StudentModelSerializer(serializers.ModelSerializer): """学生数据序列化器""" class Meta: model = Student fields = ['id', 'age', 'name',"description"] read_only_fields = ('id',) #write_only_fields = ('sex',)
3.3.2、添加额外参数
from rest_framework import serializers from students.models import Student class StudentModelSerializer(serializers.ModelSerializer): # 额外字段声明,必须在fields里面也要声明上去,否则序列化器不会调用 # password2 = serializers.CharField(write_only=True,required=True) # 如果模型类序列化器,必须声明本次调用是哪个模型,模型里面的哪些字段 class Meta: model = Student # fields = ["id","name","age","description","sex","password2"] fields = ["id","name","age","description","sex"] # fields = "__all__" # 表示操作模型中的所有字段 # 添加额外的验证选项,比如额外的字段验证 extra_kwargs = { "sex":{"write_only":True,}, "id":{"read_only":True,} } # 验证代码 # 也可以重新声明一个create和update
示例:
class StudentViewSet(View): def post(self,request): data = request.POST serializers = StudentsSerializer(data=data) status = serializers.is_valid() # print(status) # print(serializers.validated_data) student = serializers.save() #上面使用的ModelSerializer,所以不需要我们自己写create方法了 print(student) return JsonResponse({'msg':'henhao'})
什么时候继承序列化器类Serializer,什么时候继承模型序列化器类ModelSerializer?主要还是看哪个更适合你的应用场景
继承序列化器类Serializer 字段声明 验证 添加/保存数据功能 继承模型序列化器类ModelSerializer 字段声明[可选,看需要] Meta声明 验证 添加/保存数据功能[可选]
看表字段大小,看使用哪个更加节省代码了
六、视图
视图流程:
图片来源:https://blog.csdn.net/qq_41341757/article/details/108981403
Django REST framwork 提供的视图的主要作用:
-
控制序列化器的执行(检验、保存、转换数据)
-
控制数据库查询的执行
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
6.1、两个视图基类
6.1.1、APIView
rest_framework.views.APIView
APIView
与View
的不同之处在于:
-
传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象; -
视图方法可以返回REST framework的
Response
对象,视图会为响应数据设置(render)符合前端要求的格式; -
任何
APIException
异常都会被捕获到,并且处理成合适的响应信息; -
在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的类属性
-
authentication_classes 列表或元祖,身份认证类
-
permissoin_classes 列表或元祖,权限检查类
-
throttle_classes 列表或元祖,流量控制类
在APIView
中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
举例:比如我们创建一个demo的应用,然后我们写下面5个接口
from django.shortcuts import render from rest_framework.views import APIView # Create your views here. from rest_framework import status from app01 import models from .serializers import StudentSerializer, Student2Serializer from rest_framework.response import Response class Students1View(APIView): # 获取所有数据接口 def get(self,request): """ 获取所有学生数据 :param request: :return: """ """ 简单总结: 1 获取一个数据,传instance参数 获取多条数据,传instance,many=True参数 2 更新数据,传instance和data参数 部分字段更新,可以增加partial=True参数 3 添加数据,传data参数 4 删除数据,不需要使用序列化器 """ all_data = models.Student.objects.all() serializer = StudentSerializer(instance=all_data,many=True) return Response(serializer.data) # 添加一条记录的接口 def post(self,request): """ 添加学生信息 :param requeset: :return: """ data = request.data serializer = StudentSerializer(data=data) if serializer.is_valid(): instance = serializer.save() #instance为添加的新纪录对象 # 将添加的新的数据返回给客户端,可以使用我们的序列化组件先序列化一下 serializer = StudentSerializer(instance=instance) return Response(serializer.data,status=status.HTTP_201_CREATED) else: print(serializer.errors) class Student1View(APIView): # 获取单条记录 def get(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) serializer = StudentSerializer(instance=stu_obj) return Response(serializer.data) # 更新单条记录 def put(self,request,pk): #由于更新操作,我们需要找到被更新的是哪条记录,所以需要客户端给我们传一个id过来,并且以后我们会用到获取一条数据, #删除一条数据,都需要用到一个id值,所以我们把上面的get和post方法写成一个类, #更新、获取单条数据和删除数据我们再单独写一个类 stu_obj = models.Student.objects.get(pk=pk) data = request.data #可能提交过来的是部分数据,所以加上一个partial=True参数 serializer = StudentSerializer(instance=stu_obj, data=data, partial=True) if serializer.is_valid(): instance = serializer.save() # instance为添加的新纪录对象 # 将修改后的数据返回给客户端 serializer = StudentSerializer(instance=instance) return Response(serializer.data) else: print(serializer.errors) # 删除单条记录 def delete(self,request,pk): models.Student.objects.get(pk=pk).delete() return Response(None,status=status.HTTP_204_NO_CONTENT)
对应的urls.py
from django.urls import path,re_path from . import views urlpatterns = [ path(r'students/',views.StudentsAPIView.as_view()), re_path(r'students/(?P<pk>d+)/',views.StudentAPIView.as_view()), ]
6.1.2、GeneriAPIView[通用视图类]
rest_framework.generics.GenericAPIView
继承自APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
-
属性:
-
serializer_class 指明视图使用的序列化器
-
-
方法:
-
get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
返回序列化器类,默认返回
serializer_class
,可以重写,例如:def get_serializer_class(self): if self.request.user.is_staff: return Student2Serializer return StudentSerializer
-
get_serializer(self, args, *kwargs)
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。
比如
serializer = self.get_serializer(instance=self.get_object(),context={'pk':pk})
,下面的request和view我们后面会用到,现在先了解一下,后面使用就知道了-
request 当前视图的请求对象
-
view 当前请求的类视图对象
-
format 当前请求期望返回的数据格式
-
-
提供的关于数据库查询的属性与方法
-
属性:
-
queryset 指明使用的数据查询集
-
-
方法:
-
get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回
queryset
def get_queryset(self): user = self.request.user return user.accounts.all()
-
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在视图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# re_path('students2/(?P<pk>d+)/', views.Student2View.as_view()), class Student2View(GenericAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer def get(self, request, pk): book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象 serializer = self.get_serializer(book) return Response(serializer.data)
-
其他可以设置的属性
-
pagination_class 指明分页控制类
-
filter_backends 指明过滤控制后端(查询一些数据的过滤条件等等)
代码:
from rest_framework.generics import GenericAPIView from students.models import Student from .serializers import StudentModelSerializer, StudentModel2Serializer from rest_framework.response import Response from rest_framework.generics import GenericAPIView from rest_framework.mixins import ListModelMixin class Students2View(GenericAPIView,): queryset = models.Student.objects.all() #必须要指定的 serializer_class = StudentSerializer #选填的 # 通过get_serializer_class来控制不同条件下,使用不同的序列化器类 # def get_serializer_class(self): # if self.request.method == 'GET': # return Student2Serializer # else: # return StudentSerializer # 获取所有数据接口 def get(self, request): # all_data = models.Student.objects.all() # serializer = StudentSerializer(instance=all_data, many=True) serializer = self.get_serializer(instance=self.get_queryset(), many=True) return Response(serializer.data) # 添加一条记录的接口 def post(self, request): data = request.data serializer = self.get_serializer(data=data) if serializer.is_valid(): instance = serializer.save() # instance为添加的新纪录对象 serializer = self.get_serializer(instance=instance) return Response(serializer.data, status=status.HTTP_201_CREATED) else: print(serializer.errors) return Response({'error':'字段错误'}) class Student2View(GenericAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer #一个视图中使用多个序列化类的方法,目前的例子是:get请求获取数据时,我们只给他两个字段数据,其他方法时我们给他所 有字段数据,定义了这个get_serializer_class方法之后(其实是对父类的方法进行了重写),其实上面的serializer_clas s就可以不同写了 def get_serializer_class(self): """重写获取序列化器类的方法""" if self.request.method == "GET": return Student2Serializer else: return StudentSerializer #在使用GenericAPIView实现获取操作单个数据时,我们试图方法中的参数变量pk最好是pk名,别叫id什么的,不然还需要进 行一些其他的配置,比较麻烦一些了 # 获取单条记录 def get(self, request, pk): # stu_obj = models.Student.objects.get(pk=pk) serializer = self.get_serializer(instance=self.get_object()) return Response(serializer.data) # 更新单条记录 def put(self, request, pk): # stu_obj = models.Student.objects.get(pk=pk) data = request.data serializer = self.get_serializer(instance=self.get_object(), data=data, partial=True) if serializer.is_valid(): # print('>>>',serializer.data) #在save方法之前,不能调用data属性,serializer.data instance = serializer.save() # instance为添加的新纪录对象 print(serializer.data) #之后可以看 serializer = self.get_serializer(instance=instance) return Response(serializer.data) else: print(serializer.errors) # 删除单条记录 def delete(self, request, pk): models.Student.objects.get(pk=pk).delete() return Response(None, status=status.HTTP_204_NO_CONTENT)
序列化器类:
from app01 import models from rest_framework import serializers class StudentSerializer(serializers.ModelSerializer): class Meta: model = models.Student fields = '__all__' extra_kwargs = { 'id':{'read_only':True}, 'age':{'write_only':True}, } class Student2Serializer(serializers.ModelSerializer): class Meta: model = models.Student fields = ['name','class_null'] extra_kwargs = { 'id':{'read_only':True}, 'age':{'write_only':True}, }
其实GenericAPIView只是帮我们把数据库查询啊调用序列化器类啊进行了一步封装,目的是为了将一些公共性质的代码挑出去封装一下,其他感觉没啥大用,但其实这个公共性质的代码都不要我们写了,看下面几个扩展类来增强GenericAPIView的作用。
6.2、五个视图扩展类
作用:
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
1)ListModelMixin
获取多条数据的 列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
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)
举例:
from rest_framework.mixins import ListModelMixin class BookListView(ListModelMixin, GenericAPIView): queryset = BookInfo.objects.all() serializer_class = StudentSerializer
def get(self, request):
return self.list(request)
2)CreateModelMixin
添加数据的创建视图扩展类,提供create(request, *args, **kwargs)
方法快速实现创建资源的视图,成功返回201状态码。
如果序列化器对前端发送的数据验证失败,返回400错误。
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 {}
示例:
def post(self,request): return self.create(requset)
3)RetrieveModelMixin
获取单条数据,详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,可以快速实现返回一个存在的数据对象。
如果存在,返回200, 否则返回404。
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)
举例:
class BookDetailView(RetrieveModelMixin, GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request, pk): return self.retrieve(request,pk) return self.retrieve(request) #pk也可以不传
4)UpdateModelMixin
更新视图扩展类,提供update(request, *args, **kwargs)
方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)
方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。
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)
示例:
def put(self,request,pk): """更新一条数据""" return self.update(request,pk)
5)DestroyModelMixin
删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
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()
示例:
def delete(self,request,pk): """删除一条数据""" return self.destroy(request,pk)
使用GenericAPIView和视图扩展类mixins,实现api接口,代码:
from rest_framework.generics import GenericAPIView from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Students3View(GenericAPIView,ListModelMixin,CreateModelMixin):
# 本次视图类中要操作的数据[必填] queryset = models.Student.objects.all() #必须要指定的
# 本次视图类中要调用的默认序列化器[选填] serializer_class = StudentSerializer #选填的 # 获取所有数据接口 def get(self, request): return self.list(request) # 添加一条记录的接口 def post(self, request): return self.create(request) class Student3View(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = models.Student.objects.all() serializer_class = StudentSerializer
# 在使用GenericAPIView视图获取或操作单个数据时,视图方法中的代表主键的参数最好是pk # 获取单条记录 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)
下面还能对我们上面的代码进行简化。视图子类,也叫通用视图子类。
6.3、GenericAPIView的视图子类
from rest_framework.generics import ListAPIView...
1)CreateAPIView
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
3)RetrieveAPIView
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
6)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
示例:
"""使用GenericAPIView的视图子类进一步简化开发api接口的代码""" from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView class Students4View(ListAPIView,CreateAPIView): queryset = models.Student.objects.all() #必须要指定的 serializer_class = StudentSerializer #选填的 from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView from rest_framework.generics import RetrieveUpdateDestroyAPIView # 结合了上面三个子类的功能 class Student4View(RetrieveAPIView,UpdateAPIView,DestroyAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer # class Student3GenericAPIView(RetrieveUpdateDestroyAPIView): # queryset = Student.objects.all() # serializer_class = StudentModelSerializer
6.4、视图集基类ViewSet
使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:
-
list() 提供一组数据
-
retrieve() 提供单个数据
-
create() 创建数据
-
update() 保存数据
-
destory() 删除数据
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action
"""使用视图集把上面的两个视图类组成一个视图类""" from rest_framework.viewsets import ViewSet class Students5View(ViewSet): # 获取所有数据接口 def get_all_student(self,request): # action all_data = models.Student.objects.all() serializer = StudentSerializer(instance=all_data,many=True) return Response(serializer.data) # 添加一条记录的接口 def add_student(self,request): data = request.data serializer = StudentSerializer(data=data) if serializer.is_valid(): instance = serializer.save() #instance为添加的新纪录对象 serializer = StudentSerializer(instance=instance) return Response(serializer.data,status=status.HTTP_201_CREATED) else: print(serializer.errors) def get_one(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) serializer = StudentSerializer(instance=stu_obj) return Response(serializer.data)
在设置路由时,我们可以如下操作
urlpatterns = [ path('students5/', views.Students5View.as_view({'get':'get_all_student','post':'add_student'})), re_path('students5/(?P<pk>d+)/', views.Students5View.as_view({'get':'get_one'})), ]
再改善一下我们viewset
"""发挥下ViewSet的作用""" from rest_framework.viewsets import ViewSet from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView class Students5View(ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 获取所有数据接口 def get_all_student(self,request): # action return self.list(request) # 添加一条记录的接口 def add_student(self,request): return self.create(request) def get_one(self,request,pk): return self.retrieve(request,pk)
6.4.1、常用视图集父类
1) ViewSet
继承自APIView
与ViewSetMixin
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
2)GenericViewSet
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖于GenericAPIView
,所以还需要继承GenericAPIView
。
GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView
与ViewSetMixin
,在实现了调用as_view()时传入字典(如{'get':'list'}
)的映射处理工作的同时,还提供了GenericAPIView
提供的基础方法,可以直接搭配Mixin扩展类使用。
继承GenericViewSet
from rest_framework.viewsets import ViewSet,GenericViewSet class Students6View(GenericViewSet): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 获取所有数据接口 def get_all_student(self,request): # action all_data = self.get_queryset() serializer = self.get_serializer(instance=all_data,many=True) return Response(serializer.data) # 添加一条记录的接口 def add_student(self,request): data = request.data serializer = StudentSerializer(data=data) if serializer.is_valid(): instance = serializer.save() #instance为添加的新纪录对象 serializer = StudentSerializer(instance=instance) return Response(serializer.data,status=status.HTTP_201_CREATED) else: print(serializer.errors) def get_one(self,request,pk): stu_obj = models.Student.objects.get(pk=pk) serializer = StudentSerializer(instance=stu_obj) return Response(serializer.data)
在设置路由时,我们可以如下操作
urlpatterns = [ path('students6/', views.Students6View.as_view({'get':'get_all_student','post':'add_student'})), re_path('students6/(?P<pk>d+)/', views.Students6View.as_view({'get':'get_one'})), ]
举例:
from rest_framework.viewsets import ViewSet,GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Students7View(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 获取所有数据接口 def get_all_student(self,request): # action return self.list(request) # 添加一条记录的接口 def add_student(self,request): return self.create(request) def get_one(self,request,pk): return self.retrieve(request,pk) def update_one(self,request,pk): return self.update(request,pk) def delete_one(self,request,pk): return self.destroy(request,pk)
在设置路由时,我们可以如下操作
urlpatterns = [ path('students7/', views.Students7View.as_view({'get':'get_all_student','post':'add_student'})), re_path('students7/(?P<pk>d+)/', views.Students7View.as_view({'get':'get_one','put':'update_one','delete':'delete_one'})), ]
简化上面的代码
from rest_framework.viewsets import ViewSet,GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Students7View(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = models.Student.objects.all() serializer_class = StudentSerializer
"""使用ModelViewSet简写上面的继承代码,最终版""" from rest_framework.decorators import action from rest_framework.viewsets import ModelViewSet class Students8View(ModelViewSet): queryset = models.Student.objects.all() serializer_class = StudentSerializer
七、路由Routers
对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。
REST framework提供了两个router
-
SimpleRouter
-
7.1、使用方法
1) 创建router对象,并注册视图集,例如
from rest_framework import routers router = routers.DefaultRouter() router.register(r'router_stu', views.Students8View, base_name='student') get login #但是注意:路由对象只会按照modelviewset中的五个接口生成对应的访问地址而已,上面的login这种自定义动作就不能访问到了
register(prefix, viewset, base_name)
-
prefix 该视图集的路由前缀
-
viewset 视图集
-
base_name 路由别名的前缀 #student-get student-login
如上述代码会形成的路由如下:
^books/$ name: book-list
^books/{pk}/$ name: book-detail
添加路由数据:
使用路由类给视图集生成了路由地址 视图函数
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class Students8View(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer def login(self,request): """学生登录功能""" print(self.action) return Response({"message":"登录成功"})
路由代码:
from django.urls import path, re_path from . import views urlpatterns = [ ... ] """使用drf提供路由类router给视图集生成路由列表""" # 实例化路由类 # drf提供一共提供了两个路由类给我们使用,他们用法一致,功能几乎一样 from rest_framework.routers import DefaultRouter router = DefaultRouter() # 注册视图集 # router.register("路由前缀",视图集类) router.register("router_stu",views.Students8View) # 把生成的路由列表追加到urlpatterns print( router.urls ) urlpatterns += router.urls
上面的代码就成功生成了路由地址[增/删/改/查一条/查多条的功能],但是不会自动帮我们在视图集自定义方法的路由。
所以我们如果也要给自定义方法生成路由,则需要进行action动作的声明。
7.2、视图集中附加action的声明
在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。
action装饰器可以接收两个参数:
-
-
detail
-
-
False 表示路径格式是
from rest_framework.decorators import action from rest_framework.viewsets import ModelViewSet class Students8View(ModelViewSet): queryset = models.Student.objects.all() serializer_class = StudentSerializer # 想让defultrouter帮你 # methods 设置当前方法允许哪些http请求访问当前视图方法 # detail 设置当前视图方法是否是操作一个数据 # detail为True,表示路径名格式应该为 router_stu/{pk}/login/ @action(methods=['get'], detail=True) def login(self, request,pk): """登录""" ... # detail为False 表示路径名格式应该为 router_stu/get_new_5/ @action(methods=['put'], detail=False) def get_new_5(self, request): """获取最新添加的5个学生信息""" ...
由路由器自动为此视图集自定义action方法形成的路由会是如下内容:
^router_stu/get_new_5/$ name: router_stu-get_new_5
^router_stu/{pk}/login/$ name: router_stu-login
7.3、路由router形成URL的方式
1) SimpleRouter
2)DefaultRouter
八、认证Authentication
创建一个新的子应用 four
python manage.py startapp four
需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.
python manage.py createsuperuser 填一下用户名、邮箱和密码 root 1232@qq.com 1
创建管理员以后,访问admin站点,先修改站点的语言配置
settings.py
访问admin 站点效果:
admin后台管理系统简单使用
在应用的admin.py文件中
from django.contrib import admin # Register your models here. from students 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) admin.site.register(models.Student,StudentAdmin)
认证Authentication
可以在配置文件中配置全局默认的认证方案
from rest_framework import settings中可以看到它默认使用的 在settings配置文件中,我们可以进行下面的配置来覆盖默认配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( #哪个写在前面,优先使用哪个认证 'rest_framework.authentication.SessionAuthentication',
# session认证,admin后台其实就使用的session认证,其实接口开发很少用到session认证,
# 所以我们通过配置可以改为其他认证,比如后面项目里面我们用到jwt,JSON WEB TOKEN认证,或者一些配合redis的认证 'rest_framework.authentication.BasicAuthentication',
# 基本认证,工作当中可能一些测试人员会参与的话,他们会将一些认证数据保存在内存当中,然后验证的,我们基本上用不上 ) }
也可以在每个视图中通过设置authentication_classess属性来设置,比如说我们很多接口的数据都是可以让别人获取数据的,但是有可能有些接口是调用给别人网站的,有可能到时候我们就需要一些单独的认证了
from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.views import APIView class ExampleView(APIView): # 类属性 authentication_classes = [SessionAuthentication, BasicAuthentication] #也可以写成元祖形式的,到时候我们使用我们自己开发的认证组件的时候,就需要自己写一个认证组件类,然后写在列表中来使用 ...
认证失败会有两种可能的返回值:
-
401 Unauthorized 未认证
-
示例1:自定义认证组件
1 写一个认证类
在应用下建一个文件夹utils,建一个Auth.py的文件
# drf 提供的基础认证类 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('认证失败')
全局使用,settings配置文件中使用
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( ... 'four.utils.auth.APIAuth', #全局配置,所有的接口请求过来,都会执行这个类 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' ), }
局部视图中使用:
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) #AnonymousUser 匿名用户,假用户 print('>>>>',request.auth) #AnonymousUser 匿名用户,假用户 #>>>> root return Response({'msg':'hello'})
九、权限Permissions
权限控制可以限制用户对于视图的访问和对于具体数据对象的访问
可以在配置文件中全局设置默认的权限管理类,如
REST_FRAMEWORK = { .... 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', #登录状态下才能访问我们的接口,可以通过退出admin后台之后,你看一下还能不能访问我们正常的接口就看到效果了 ) }
如果为指明,则采用如下默认配置
from rest_framework import permissions 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.AllowAny', #表示任何人都可以进行任何的操作,没做限制 )
也可以在具体的视图中通过permission_classes属性来设置,如
from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView class ExampleView(APIView): permission_classes = (IsAuthenticated,) ...
提供的权限
-
-
IsAuthenticated 仅通过认证的用户
-
IsAdminUser 仅管理员用户(可以通过admin创建一个用户进行测试)
-
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]
自定义权限
如果自定义权限,需要继承
-
.has_permission(self, request, view)
是否可以访问视图, view表示当前视图对象
-
.has_object_permission(self, request, view, obj)
是否可以访问数据对象, view表示当前视图, obj为数据对象
例如:
在当前子应用下,创建一个权限文件permissions.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]
十、限流Throttling
可以对接口访问的频次进行限制,以减轻服务器压力。
使用
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', #匿名用户,未登录的 'rest_framework.throttling.UserRateThrottle' #经过登录之后的用户 ), 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' } }
源码: {'s': 1, 'm': 60, 'h': 3600, 'd': 86400} m表示分钟,可以写m,也可以写minute
也可以在具体视图中通过throttle_classess属性来配置,如
from rest_framework.throttling import UserRateThrottle from rest_framework.views import APIView class ExampleView(APIView): throttle_classes = (UserRateThrottle,) #局部配置 ...
可选限流类
1) AnonRateThrottle
限制所有匿名未认证用户,使用IP区分用户。
使用DEFAULT_THROTTLE_RATES['anon']
来设置频次
限制认证用户,使用User id 来区分。
使用DEFAULT_THROTTLE_RATES['user']
来设置频次
3)ScopedRateThrottle (待定...)
限制用户对于每个视图的访问频次,使用ip或user id,先找的用户id,没有设置用户id的话就会使用ip地址。
例如: 全局
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' } }
实例:
全局配置中设置访问频率
'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局部使用示例
settings.py内容 'DEFAULT_THROTTLE_RATES': { 'xx': '3/minute', 'oo': '5/minute', }, views.py内容 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内容 path(r'students/',views.StudentAPIView.as_view()), path(r'students2/',views.StudentAPI2View.as_view()),
十一、过滤Filtering
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-filter扩展来增强支持。
pip install django-filter
在配置文件中增加过滤后端的设置:
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/four/students/?sex=1
十二、排序
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
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 # 必须是ordering=某个值 # -id 表示针对id字段进行倒序排序 # id 表示针对id字段进行升序排序
如果需要在过滤以后再次进行排序,则需要两者结合!
from rest_framework.generics import ListAPIView from students.models import Student from .serializers import StudentModelSerializer from django_filters.rest_framework import DjangoFilterBackend #需要使用一下它才能结合使用 class Student3ListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_fields = ('age', 'sex') # 因为filter_backends是局部过滤配置,局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明, # 否则过滤功能会失效 filter_backends = [OrderingFilter,DjangoFilterBackend] ordering_fields = ('id', 'age') # 针对的是继承的类中的list方法 # 127.0.0.1:8000/books/?sex=1&ordering=-age
十三、分页Pagination
我们可以在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK = { # 全局分页,一旦设置了全局分页,那么我们drf中的视图扩展类里面的list方法提供的列表页都会产生分页的效果。所以一般不用全局分页 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 # 每页最大数据量 }
class LargeResultsSetPagination(PageNumberPagination): page_size = 1000 #每页显示多少条 #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
注意:如果在视图内关闭分页功能,只需在视图内设置
pagination_class = None
1、可选分页器
前段访问网址形式:
GET http://127.0.0.1:8000/students/?page=4
可以在子类中定义的属性:
-
page_size 每页数目
-
page_query_param 前端发送的页数关键字名,默认为"page"
-
page_size_query_param 前端发送的每页数目关键字名,默认为None
-
max_page_size 前端最多能设置的每页数量
# 声明分页的配置类 from rest_framework.pagination import PageNumberPagination class StandardPageNumberPagination(PageNumberPagination): # 默认每一页显示的数据量 page_size = 2 # 允许客户端通过get参数来控制每一页的数据量 page_size_query_param = "size" max_page_size = 10 #客户端通过size指定获取数据的条数时,最大不能超过多少 # 自定义页码的参数名 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
GET http://127.0.0.1/four/students/?limit=100&offset=400 #从下标为400的记录开始,取100条记录
-
default_limit 默认限制,每页数据量大小,默认值与
PAGE_SIZE
设置一致 -
limit_query_param limit参数名,默认'limit' , 可以通过这个参数来改名字
-
offset_query_param offset参数名,默认'offset' ,可以通过这个参数来改名字
-
max_limit 最大limit限制,默认None, 无限制
from rest_framework.pagination import LimitOffsetPagination class StandardLimitOffsetPagination(LimitOffsetPagination): # 默认每一页查询的数据量,类似上面的page_size default_limit = 2 limit_query_param = "size" #默认是limit offset_query_param = "start" #默认是offset class StudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer # 调用页码分页类 # pagination_class = StandardPageNumberPagination # 调用查询偏移分页类 pagination_class = StandardLimitOffsetPagination
十四、异常处理 Exceptions
class APIError(Exception): pass class Student2APIView(APIView): def get(self,request,pk): try: instance = Student.objects.get(pk=pk) except Student.DoesNotExist: raise APIError('自定义API错误') return Response({"message":"访问的商品已经下架~"}) serializer = StudentModelSerializer(instance=instance) return Response(serializer.data)
可以创建一个utils文件夹,里面放一个exceptions.py文件,名字随便写,然后写下面的内容
from rest_framework.views import exception_handler def custom_exception_handler(exc, context): #自定义的错误处理函数 ”“” exc错误对象 context 异常发生时的一些上下文信息 “”“ # 先调用REST framework默认的异常处理方法获得标准错误响应对象 response = exception_handler(exc, context) #这个函数是drf提供的,它处理了一些错误,但是如果它处理不了的,它会返回None,所以,如果是None的话,我们需要自己来处理错误 # 在此处补充自定义的异常处理 if response is None: if isinstance(exc,APIError) #这里就可以记录错误信息了,一般记录到文件中,可以使用日志系统来进行记录 # return Respose({'msg':'自定义API错误了'}) response.data['status_code'] = response.status_code return response
在配置文件中还要声明自定义的异常处理
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' }
如果未声明,会采用默认的方式,如下
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' }
补充上处理关于数据库的异常
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'] #出错的方法或者函数名称 if isinstance(exc, DatabaseError): print('[%s]: %s' % (view, exc)) response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) return response
-
APIException 所有异常的父类
-
ParseError 解析错误
-
-
NotAuthenticated 尚未认证
-
PermissionDenied 权限决绝
-
NotFound 未找到
-
MethodNotAllowed 请求方式不支持
-
NotAcceptable 要获取的数据格式不支持
-
Throttled 超过限流次数
-
ValidationError 校验失败
也就是说,上面列出来的异常不需要我们自行处理了,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
十五、自动生成接口文档
REST framework可以自动帮助我们生成接口文档。
接口文档以网页的方式呈现。
自动接口文档能生成的是继承自
1、安装依赖
pip install coreapi
2、设置接口文档访问路径
文档路由对应的视图配置为rest_framework.documentation.include_docs_urls
,
参数title
为接口文档网站的标题。
from rest_framework.documentation import include_docs_urls urlpatterns = [ ... path('docs/', include_docs_urls(title='站点页面标题')) ]
'AutoSchema' object has no attribute 'get_link'
配置:
REST_FRAMEWORK = { ... 'DEFAULT_SCHEMA_CLASS': "rest_framework.schemas.AutoSchema", }
3、文档描述说明的定义位置
1) 单一方法的视图,可直接使用类视图的文档字符串,如
class BookListView(generics.ListAPIView): """ get: 返回所有图书信息. post: 添加记录 """ #注意,这是在类中声明的注释,如果在方法中你声明了其他注释,会覆盖这个注释的
2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
class BookListCreateView(generics.ListCreateAPIView): """ get: 返回所有图书信息. post: 新建图书. """
3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,但是应使用action名称区分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet): """ list: 返回图书列表数据 retrieve: 返回图书详情数据 latest: 返回最新的图书数据 read: 修改图书的阅读量 """
4、访问接口文档网页
浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档。
两点说明:
1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫做read
2)参数的Description需要在模型类或序列化器类的字段中以help_text选项定义,如:
class Student(models.Model): ... age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄') ...
注意,如果你多个应用使用同一个序列化器,可能会导致help_text的内容显示有些问题,小事情
class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__" extra_kwargs = { 'age': { 'required': True, 'help_text': '年龄' } }
十六、Xadmin
xadmin是Django的第三方扩展,比使用Django的admin站点更强大也更方便。
文档:https://xadmin.readthedocs.io/en/latest/index.html
GitHub地址:https://github.com/sshwsfc/django-xadmin
1、安装
通过如下命令安装xadmin的最新版,它文档里面的安装方法好久没有更新了,会导致你安装不成功,所以我们使用下面的网址进行安装
pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2
在配置文件中注册如下应用
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(r'xadmin/', xadmin.site.urls), ]
如果之前没有创建超级用户,需要创建,如果有了,则可以直接使用之前的。
python manage.py createsuperuser
2、使用
-
xadmin不再使用Django的admin.py,而是需要编写代码在adminx.py文件中,每一个应用都可以写一创建adminx.py对xadmin站点进行配置。
-
xadmin的站点管理类不用继承
admin.ModelAdmin
,而是直接继承object
例如:在子应用中创建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', 'btitle', 'bread', 'bcomment']
-
search_fields 控制可以通过搜索框搜索的字段名称,xadmin使用的是模糊查询
search_fields = ['id','btitle']
-
list_filter 可以进行过滤操作的列,对于分类、性别、状态
list_filter = ['is_delete']
-
ordering 默认排序的字段
ordering = ['-age',] #-倒序
-
show_detail_fields 在列表页提供快速显示详情信息
show_detail_fields = ['id',]
-
list_editable 在列表页可以快速直接编辑的字段
list_editable = ['name','age',]
-
refresh_times 指定列表页的定时刷新
refresh_times = [5, 10,30,60] # 设置允许后端管理人员按多长时间(秒)刷新页面,选好之后就能自动刷新了
-
list_export 控制列表页导出数据的可选格式
list_export = ('xls', 'json','csv')#写元祖或者列表都行 list_export设置为None来禁用数据导出功能 list_export_fields = ('id', 'btitle', 'bpub_date') #设置允许导出的字段
-
show_bookmarks 控制是否显示书签功能
show_bookmarks = True #False就隐藏了这个功能
-
data_charts
-
data_charts = { "order_amount": { #随便写的名称order_amount 'title': '图书发布日期表', "x-field": "bpub_date", "y-field": ('btitle',), "order": ('id',), }, # 支持生成多个不同的图表 # "order_amount2": { # 'title': '图书发布日期表', # "x-field": "bpub_date", # "y-field": ('btitle',), # "order": ('id',) # }, }
-
title 控制图标名称
-
x-field 控制x轴字段
-
y-field 控制y轴字段,可以是多个值
-
order 控制默认排序
-
-
model_icon 控制菜单的图标【图标的设置可以参考font-awesome的图标css名称】
model_icon = 'fa fa-gift'
-
readonly_fields 在编辑页面的只读字段
readonly_fields = ['name',]
-
exclude 在编辑页面隐藏的字段,比如判断这个数据是否删除的delete_status字段,一般就是用来标识一下字段是不是被删除了,但是数据库中不删除
exclude = ['name',]
3、。。。。
它提供的一些功能可能还需要自定制,调整或者添加一些它没有的功能