序列化组件的使用、反序列化、全局钩子和局部钩子的使用、raise_exception参数、modelserializer进行数据保存时的问题
序列化组件的使用
1. 在应用中创建一个py文件,比如叫做serializers.py
1 2 3 4 5 6 7 | from rest_framework import serializers class StudentSerizlizer(serializers.Serializer): name = serializers.CharField() age = serializers.IntegerField() class_null = serializers.CharField() description = serializers.CharField() |
2. 在视图中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from django.shortcuts import render,HttpResponse from django.http import JsonResponse from students import models # Create your views here. from django.views import View from .serializers import StudentSerizlizer class StudentView(View): def get( self ,request): # all = models.Student.objects.all() #quseryset model one = models.Student.objects.get( id = 1 ) #quseryset model # serializer = StudentSerizlizer(all,many=True) # serializer = StudentSerizlizer(all) #结果为:[{},{}]形式 serializer = StudentSerizlizer(one) #得到的结果为字典 data print (serializer.data) #{'name': 'chao', 'age': 18, 'class_null': '31', 'description': 'xxxxx'} return JsonResponse(serializer.data,safe = False ,json_dumps_params = { 'ensure_ascii' : False }) |
3. 应用配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | INSTALLED_APPS = [ ... 'students.apps.StudentsConfig' , 'rest_framework' , 'ser' ] DATABASES = { 'default' : { 'ENGINE' : 'django.db.backends.mysql' , 'NAME' : 'drf01' , 'HOST' : '127.0.0.1' , 'PORT' : 3306 , 'USER' : 'root' , 'PASSWORD' : '123456' } } |
反序列化功能
1. 创建反序列化组件
在应用中创建一个py文件,比如叫做serializers.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from rest_framework import serializers # 自定义校验函数 def check666(val): if '666' in val: raise serializers.ValidationError( '不能光喊6666啊,没有用' ) else : return val class StudentSerizlizer(serializers.Serializer): name = serializers.CharField(max_length = 4 ,validators = [check666,]) age = serializers.IntegerField(max_value = 18 ) class_null = serializers.CharField() # description = serializers.CharField(required=False,allow_null=True) # required=False,allow_null=True允许字段为空,也就是不用传递过来这个data description = serializers.CharField(allow_blank = True ) #allow_blank=True 允许只为空字符串 |
2. 视图中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class Student(View): def get.. ... def post( self ,request): # content-type # if content-type == 'urlencoded': # #username=chao&password=123&a=1 # request.POST['username'] = 'chao' # elif content-type == 'form-data': # # 分片接受数据 # request.FILES # django没有自带解析json数据的解析器,所以需要我们手动的解析,但是drf中已经有了 # content - type == 'application/json' # print (request.POST) data = { 'name' :request.POST.get( 'name' ), 'age' :request.POST.get( 'age' ), 'class_null' :request.POST.get( 'class_null' ), 'description' :request.POST.get( 'description' ), } ser = StudentSerizlizer(data = data) print (ser.is_valid()) #校验,全部通过得到True,一个字段错了都是得到False print (ser.errors) #所有字段的错误信息 # print(request.body) return HttpResponse( 'ok' ) |
全局钩子和局部钩子的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class StudentSerizlizer(serializers.Serializer): # <QueryDict: {'name': ['c777'], 'age': ['6'], 'description': ['123'], 'class_null': ['1']}> name = serializers.CharField(max_length = 4 ,validators = [check666,]) age = serializers.IntegerField(max_value = 18 ) class_null = serializers.CharField() # description = serializers.CharField(required=False,allow_null=True) # required=False,allow_null=True允许字段为空,也就是不用传递过来这个data description = serializers.CharField(allow_blank = True ) #allow_blank=True 允许只为空字符串 # 局部钩子:针对单个属性对应的数据进行校验 def validate_name( self ,val): # print('xxxxx>>>',val) #xxxxx>>> ccbb if '777' in val: raise serializers.ValidationError( '不能有777' ) return val #如果没有错误,需要return这个属性数据 # 全局钩子: 主要是针对多个属性数据进行校验 def validate( self ,data): print (data) #OrderedDict([('name', 'c778'), ('age', 6), ('class_null', '1'), ('description', '123')]) age = data.get( 'age' ) class_null = data.get( 'age' ) if age = = class_null: raise serializers.ValidationError( 'age和class——null不能相等' ) return data #如果没有错误,全局钩子要return所有数据 |
视图部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | def post( self ,request): # print (request.POST) data = { 'name' :request.POST.get( 'name' ), 'age' :request.POST.get( 'age' ), 'class_null' :request.POST.get( 'class_null' ), 'description' :request.POST.get( 'description' ), } ser = StudentSerizlizer(data = data) if ser.is_valid(): print (request.body) ret = models.Student.objects.create( * * ser.validated_data ) serializer = StudentSerizlizer(instance = ret) print (serializer.data) #得到的是教研成功之后的所有正确数据 return JsonResponse(serializer.data,safe = False ,json_dumps_params = { 'ensure_ascii' : False }) # return JsonResponse({'xx':'xx'}) else : return JsonResponse({ 'error' : '有字段错误' }) |
执行顺序如下
1 2 3 4 5 | # is_valid()方法时,先校验序列化器类中的所有属性Field(CharField(参数))参数对应的校验规则 # 再执行局部钩子 # 举例:比如有name和age两个属性,先执行name 的参数校验,在执行name的局部钩子(validate_name(self,val)),然后再执行age属性的参数校验,再执行age的局部钩子,最后所有属性的参数校验和局部钩子校验完成之后,执行全局钩子 # 最后执行全局钩子 |
常用字段和参数
字段 | 字段构造方式 |
---|---|
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 | DictField(child=) |
选项参数:
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_length | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最大值 |
min_value | 最小值 |
通用参数:
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
raise_exception参数
等于True会主动抛出异常
1 | serializer.is_valid(raise_exception = True ) |
保存数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 方式 1 直接在视图中保存 if ser.is_valid(): # print(request.body) ret = models.Student.objects.create( * * ser.validated_data ) serializer = StudentSerizlizer(instance = ret) return JsonResponse(serializer.data,safe = False ,json_dumps_params = { 'ensure_ascii' : False }) else : print (ser.errors) return JsonResponse({ 'error' : '有字段错误' }) 方式 2 在序列化器中定义create方法来数据的保存 class StudentSerizlizer(serializers.Serializer): # <QueryDict: {'name': ['c777'], 'age': ['6'], 'description': ['123'], 'class_null': ['1']}> name = serializers.CharField(max_length = 4 ,validators = [check666,]) ... def create( self , validated_data): # self.validated_data # validated_data # print('>>',self.validated_data) print ( '>>' ,validated_data) ret = models.Student.objects.create( * * validated_data ) return ret 视图中通过save方法来触发,序列化器类中的create方法 if ser.is_valid(): instance = ser.save() #得到create方法的返回值 serializer = StudentSerizlizer(instance = instance) return JsonResponse(serializer.data,safe = False ,json_dumps_params = { 'ensure_ascii' : False }) # return JsonResponse({'xx':'xx'}) |
更新数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 在序列化器中定义update方法来数据的更新 class StudentSerizlizer(serializers.Serializer): # <QueryDict: {'name': ['c777'], 'age': ['6'], 'description': ['123'], 'class_null': ['1']}> name = serializers.CharField(max_length = 4 ,validators = [check666,]) ... # 做更新动作 def update( self , instance, validated_data): # print(instance) # print(validated_data) instance.name = validated_data[ 'name' ] instance.age = validated_data[ 'age' ] instance.class_null = validated_data[ 'class_null' ] instance.description = validated_data[ 'description' ] instance.save() return instance 视图 def put( self ,request): data = { 'id' : 2 , 'name' : 'xx' , 'age' : 8 , 'sex' : 0 , 'class_null' : '9' , 'description' : 'xx' , } obj = models.Student.objects.get( id = data.get( 'id' )) s_obj = StudentSerizlizer(instance = obj,data = data) # 实例化序列化器类时,传入instance参数 if s_obj.is_valid(): s_obj.save() #触发序列化器类的update方法 else : return JsonResponse({ 'error' : '数据错误' }) |
read_only和write_only参数的区别
1 2 3 4 5 6 7 8 9 10 11 12 | from rest_framework import serializers class StudentSerizlizer(serializers.Serializer): id = serializers.IntegerField(read_only = True ) # read_only=True,序列化时序列化出该字段数据,反序列化校验时不要校验这个数据 name = serializers.CharField(max_length = 4 ,) age = serializers.IntegerField(max_value = 18 ,write_only = True ) # write_only=True,序列化时不序列化这个字段数据,反序列校验时,需要客户端传递这个数据过来进行校验 class_null = serializers.CharField() description = serializers.CharField(allow_blank = True ) |
视图部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | from django.shortcuts import render from django.views import View # Create your views here. from students import models from .serializers import StudentSerizlizer from django.http import JsonResponse class StudentView(View): def get( self ,request): all = models.Student.objects. all () serializer = StudentSerizlizer(instance = all , many = True ) return JsonResponse(serializer.data, safe = False , json_dumps_params = { 'ensure_ascii' : False }) def post( self ,request): print (request.POST) data = { 'name' :request.POST.get( 'name' ), 'sex' :request.POST.get( 'sex' ), 'age' :request.POST.get( 'age' ), 'class_null' :request.POST.get( 'class_null' ), 'description' :request.POST.get( 'description' ), } serializer = StudentSerizlizer(data = data) serializer.is_valid() print (serializer.errors) print ( '正确数据:' ,serializer.validated_data) return JsonResponse({ 'xx' : 'xx' }) |
partial参数:默认为False
1 2 3 4 5 6 7 8 9 10 11 12 | def put( self ,request): data = { 'name' : 'chao' , 'age' : 18 } serializer = StudentSerizlizer(data = data,partial = True ) # partial=True:只需要校验传入给序列化器的数据,适用于部分数据更新 serializer.is_valid() print (serializer.errors) print ( '正确数据:' , serializer.validated_data) return JsonResponse({ 'ss' : 'kk' }) |
modelSerializer的使用
序列化和反序列化的使用
定义如下的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | from rest_framework import serializers from students import models class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = models.Student fields = '__all__' # fields = ['id', 'name', 'age'] # fields = ['id', 'name', 'age'] # exclude = ['name','age'] extra_kwargs = { 'id' :{ 'read_only' : True ,}, 'age' :{ 'write_only' : True ,} } ''' id 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="个性签名") ''' ''' id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=6,) # name char(6) age = serializers.IntegerField(max_value=18,write_only=True) sex = serializers.BooleanField() class_null = serializers.CharField() description = serializers.CharField(allow_blank=True) ''' |
视图当中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | from django.shortcuts import render from django.http import JsonResponse # Create your views here. from django.views import View from .serializers import StudentModelSerializer from students import models class StudentView(View): def get( self ,request): all = models.Student.objects. all () model_ser = StudentModelSerializer(instance = all ,many = True ) print () return JsonResponse(model_ser.data, safe = False , json_dumps_params = { 'ensure_ascii' : False }) def post( self ,request): print (request.POST) obj = StudentModelSerializer(data = request.POST) if obj.is_valid(): print (obj.validated_data) obj.save() #自动能够帮我们进行数据保存 return JsonResponse({ 'msg' : 'success' }) print (obj.errors) print (obj.validated_data) return JsonResponse({ 'xx' : 'ssssss' }) |
modelserializer进行数据保存时的问题
视图相关
APIView类
request对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from rest_framework.views import APIView class UserView(APIView): def get( self ,request): print (request.GET) print (request.query_params) # request.GET和request.query_params是等价的 return JsonResponse({ 'xx' : 'xxxxx' }) def post( self ,request): print (request) # 当发送的数据格式为..urlencoded类型时,request.POST和request.data等价 # print(request.POST.getlist('hobby')) #<QueryDict: {'name': ['小林2'], 'age': ['6']}> # 当发送过来的是json类型数据时,我们使用request.data属性能够获取到数据 print (request.data) #{'username': 'xxxx', 'password': '123'},普通字典类型 # request.data能够获取到客户端发送过来的json类型数据,但是得到的结果为普通字典类型,但是如果是多选数据,不能使用getlist方法获取 return JsonResponse({ 'xx' : 'xxxxx' }) |
response对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 查看drf的默认配置 from rest_framework import settings 引入response from rest_framework.response import Response Response默认响应的是json数据类型 当用浏览器访问时看到页面效果. 用户配置替换drf内部配置的写法 REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES' : ( # 默认响应渲染类 'rest_framework.renderers.JSONRenderer' , # json渲染器 'rest_framework.renderers.BrowsableAPIRenderer' , # 浏览器API渲染器 ) } |
response的方法的相关参数
1 | Response(data, status = None , template_name = None , headers = None , content_type = None ) |
’响应状态码
1 2 3 4 | from rest_framework import status # return Response({'xx':'xxxxx'}, status=201) return Response({ 'xx' : 'xxxxx' }, status = status.HTTP_201_CREATED) |
所有状态码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | HTTP_100_CONTINUE = 100 HTTP_101_SWITCHING_PROTOCOLS = 101 HTTP_200_OK = 200 HTTP_201_CREATED = 201 HTTP_202_ACCEPTED = 202 HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 HTTP_204_NO_CONTENT = 204 HTTP_205_RESET_CONTENT = 205 HTTP_206_PARTIAL_CONTENT = 206 HTTP_207_MULTI_STATUS = 207 HTTP_208_ALREADY_REPORTED = 208 HTTP_226_IM_USED = 226 HTTP_300_MULTIPLE_CHOICES = 300 HTTP_301_MOVED_PERMANENTLY = 301 HTTP_302_FOUND = 302 HTTP_303_SEE_OTHER = 303 HTTP_304_NOT_MODIFIED = 304 HTTP_305_USE_PROXY = 305 HTTP_306_RESERVED = 306 HTTP_307_TEMPORARY_REDIRECT = 307 HTTP_308_PERMANENT_REDIRECT = 308 HTTP_400_BAD_REQUEST = 400 HTTP_401_UNAUTHORIZED = 401 HTTP_402_PAYMENT_REQUIRED = 402 HTTP_403_FORBIDDEN = 403 HTTP_404_NOT_FOUND = 404 HTTP_405_METHOD_NOT_ALLOWED = 405 HTTP_406_NOT_ACCEPTABLE = 406 HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 HTTP_408_REQUEST_TIMEOUT = 408 HTTP_409_CONFLICT = 409 HTTP_410_GONE = 410 HTTP_411_LENGTH_REQUIRED = 411 HTTP_412_PRECONDITION_FAILED = 412 HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413 HTTP_414_REQUEST_URI_TOO_LONG = 414 HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416 HTTP_417_EXPECTATION_FAILED = 417 HTTP_418_IM_A_TEAPOT = 418 HTTP_422_UNPROCESSABLE_ENTITY = 422 HTTP_423_LOCKED = 423 HTTP_424_FAILED_DEPENDENCY = 424 HTTP_426_UPGRADE_REQUIRED = 426 HTTP_428_PRECONDITION_REQUIRED = 428 HTTP_429_TOO_MANY_REQUESTS = 429 HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 HTTP_500_INTERNAL_SERVER_ERROR = 500 HTTP_501_NOT_IMPLEMENTED = 501 HTTP_502_BAD_GATEWAY = 502 HTTP_503_SERVICE_UNAVAILABLE = 503 HTTP_504_GATEWAY_TIMEOUT = 504 HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 HTTP_506_VARIANT_ALSO_NEGOTIATES = 506 HTTP_507_INSUFFICIENT_STORAGE = 507 HTTP_508_LOOP_DETECTED = 508 HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509 HTTP_510_NOT_EXTENDED = 510 HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 |
headers定制响应头键值对
1 | return Response({ 'xx' : 'xxxxx' }, status = status.HTTP_201_CREATED,headers = { 'xx' : 'oo' }) |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步