day84
1 修改,删除接口
2 高级用法之source
3 模型类序列化器
4 高级用法之SerializerMethodField
5 drf的请求与相应
6 通过配置,选择默认模板的显示形式(浏览器方式,json方式)
7 many=True源码分析,局部全局钩子源码解析
## 1 修改,删除接口 ### views.py ```python def put(self, request, id): # 通过id取到对象 res = {'code': 100, 'msg': ''} try: book = models.Book.objects.get(id=id) ser = BookSerializer(instance=book, data=request.data) ser.is_valid(raise_exception=True) ser.save() res['msg'] = '修改成功' res['result'] = ser.data except Exception as e: res['code'] = 101 res['msg'] = str(e) return Response(res) def delete(self,request,id): response = {'code': 100, 'msg': '删除成功'} models.Book.objects.filter(id=id).delete() return Response(response) ``` ### serializer.py ```python class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) title = serializers.CharField(max_length=32,min_length=2) price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.CharField(max_length=32) def create(self, validated_data): res=models.Book.objects.create(**validated_data) print(res) return res def update(self, book, validated_data): book.title=validated_data.get('title') book.price=validated_data.get('price') book.publish=validated_data.get('publish') book.save() return book ``` ## 2 高级用法之source ```python 1 修改返回到前端的字段名 # source=title 字段名就不能再叫title name = serializers.CharField(max_length=32,min_length=2,source='title') 2 如果表模型中有方法 # 执行表模型中的test方法,并且把返回值赋值给xxx xxx=serializers.CharField(source='test') 3 source支持跨表操作 addr=serializers.CharField(source='publish.addr') # 希望你们去看以下源码,内部如何实现的 ``` ## 3 模型类序列化器 ```python 1 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系 2 使用 class BookModelSerializer(serializers.ModelSerializer): class Meta: model=表模型 # 跟哪个表模型建立关系 fields=[字段,字段] # 序列化的字段,反序列化的字段 fields='__all__' # 所有字段都序列化,反序列化 exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用) read_only_fields=['price','publish'] # 序列化显示的字段 write_only_fields=['title'] # 反序列化需要传入的字段 extra_kwargs ={'title':{'max_length':32,'write_only':True}} depth=1 # 了解,跨表1查询,最多建议写3 # 重写某些字段 publish = serializers.CharField(max_length=32,source='publish.name') # 局部钩子,全局钩子,跟原来完全一样 3 新增,修改 -统统不用重写create和update方法了,在ModelSerializer中重写了create和update ``` ## 4 高级用法之SerializerMethodField ```python class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) name = serializers.CharField(max_length=32,min_length=2,source='title') price = serializers.DecimalField(max_digits=5, decimal_places=2) publish = serializers.SerializerMethodField() def get_publish(self,obj): dic={'name':obj.publish.name,'addr':obj.publish.addr} return dic class BookModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' publish = serializers.SerializerMethodField() def get_publish(self,obj): dic={'name':obj.publish.name,'addr':obj.publish.addr} return dic ## 第三种方案,使用序列化类的嵌套 class PublishSerializer(serializers.ModelSerializer): class Meta: model = models.Publish # fields = '__all__' fields = ['name','addr'] class BookModelSerializer(serializers.ModelSerializer): publish = PublishSerializer() class Meta: model = models.Book fields = '__all__' ``` ## 5 drf的请求与相应 ```python # Request -data :前端以post请求提交的数据都在它中 -FILES :前端提交的文件 -query_params:就是原来的request.GET -重写了 __getattr__ -使用新的request.method其实取得就是原生request.method(通过反射实现) # Response -from rest_framework.response import Response -data:响应的字典 -status:http响应的状态码 -drf提供给你了所有的状态码,以及它的意思 from rest_framework.status import HTTP_201_CREATED -template_name:模板名字(一般不动),了解 -headers:响应头,字典 -content_type:响应的编码方式,了解 # 自己封装一个Response对象 class CommonResponse: def __init__(self): self.code=100 self.msg='' @property def get_dic(self): return self.__dict__ # 自己封装一个response,继承drf的Response ## 6 通过配置,选择默认模板的显示形式(浏览器方式,json方式) -配置文件方式(全局) -如果没有配置,默认有浏览器和json -drf有默认配置文件 from rest_framework.settings import DEFAULTS REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类 'rest_framework.renderers.JSONRenderer', # json渲染器 'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器 ) } -在视图类中配置(局部) -粒度更小 -class BookDetail(APIView): renderer_classes=[JSONRenderer,] ``` ## 7 many=True源码分析,局部全局钩子源码解析 ```python 1 many=True -__init__----->一路找到了BaseSerializer---》__new__决定了生成的对象是谁 2 入口是is_valid()---》BaseSerializer--》is_valid---》self._validated_data = self.run_validation(self.initial_data) -Serializer这个类的:self.run_validation def run_validation(self, data=empty): value = self.to_internal_value(data) # 局部字段自己的校验和局部钩子校验 try: self.run_validators(value) value = self.validate(value) # 全局钩子的校验 except (ValidationError, DjangoValidationError) as exc: raise ValidationError(detail=as_serializer_error(exc)) return value ```
views.py
from django.shortcuts import render # Create your views here. from rest_framework.response import Response from rest_framework.views import APIView from app01 import serrializer from app01 import models class MyView(APIView): def get(self, request): return Response({'name': 'abc', 'age': 1111}) class Index(APIView): def get(self, request, *args, **kwargs): # 这个request是新的drf的Request类的对象 print(type(request)) print(type(request._request)) print(request._request.method) print(request.method) print(request.POST) print(request.data) return Response({'name': 'sss'}) # class Book(APIView): # def get(self, request, *args, **kwargs): # dic = models.Book.objects.all() # ser = serrializer.BookSerializer(instance=dic, many=True) # 实例化需要传入对象,如果是多条则many=True # print(type(ser)) # # rest_framework.serializers.ListSerializer # return Response(ser.data) # # def post(self, request): # # post提交的数据都在request.data中 是个字典 # ser = serrializer.BookSerializer(data=request.data) # post请求需要传入data # if ser.is_valid(): # 校验 # ser.save() # 保存至数据库 # return Response(request.data) # else: # return Response(ser.errors) # # # class BookDetail(APIView): # def get(self, request, id): # book = models.Book.objects.filter(id=id).first() # ser = serrializer.BookSerializer(instance=book) # 单个数据不能many=True # print(type(ser)) # app01.serializer.BookSerializer # return Response(ser.data) # # def put(self, request, id): # 修改 # dic = {'code': 100, 'msg': ''} # book = models.Book.objects.filter(id=id).first() # try: # ser = serrializer.BookSerializer(instance=book, data=request.data) # ser.is_valid(raise_exception=True) # 省去if判断,添加raise_exception=True,若校验通过则继续执行否则抛出异常 # ser.save() # dic['msg'] = '修改成功' # dic['result'] = ser.data # except Exception as e: # print(e) # dic['code'] = 101 # dic['msg'] = '未知异常' # return Response(dic) # # def delete(self, request, id): # dic = {'code': 100, 'msg': '删除成功'} # models.Book.objects.filter(id=id).delete() # return Response(dic) class Book(APIView): def get(self, request, *args, **kwargs): dic = models.Book.objects.all() ser = serrializer.BookModelSerializer(instance=dic, many=True) # 实例化需要传入对象,如果是多条则many=True print(type(ser)) # # rest_framework.serializers.ListSerializer return Response(ser.data) def post(self, request): # post提交的数据都在request.data中 是个字典 ser = serrializer.BookModelSerializer(data=request.data) # post请求需要传入data if ser.is_valid(): # 校验 ser.save() # 保存至数据库 return Response(ser.data) else: return Response(ser.errors) from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer class BookDetail(APIView): renderer_classes = [JSONRenderer] # 局部配置 def get(self, request, id): book = models.Book.objects.filter(id=id).first() ser = serrializer.BookModelSerializer(instance=book) # 单个数据不能many=True print(type(ser)) # app01.serializer.BookSerializer return Response(ser.data) def put(self, request, id): # 修改 dic = {'code': 100, 'msg': ''} book = models.Book.objects.filter(id=id).first() try: ser = serrializer.BookModelSerializer(instance=book, data=request.data) ser.is_valid(raise_exception=True) # 省去if判断,添加raise_exception=True,若校验通过则继续执行否则抛出异常 ser.save() dic['msg'] = '修改成功' dic['result'] = ser.data except Exception as e: print(e) dic['code'] = 101 dic['msg'] = '未知异常' return Response(dic) def delete(self, request, id): dic = {'code': 100, 'msg': '删除成功'} models.Book.objects.filter(id=id).delete() return Response(dic)
models.py
from django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32, null=True) price = models.DecimalField(max_digits=5, decimal_places=2, null=True) # publish = models.CharField(max_length=32) publish = models.ForeignKey(to='Publish', null=True, on_delete=models.CASCADE) def test(self): return self.title+str(self.price) class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) def __str__(self): return self.name
serializer.py
from rest_framework import serializers from rest_framework.exceptions import ValidationError from app01 import models def check_publish(data): if len(data) > 10: raise ValidationError('最长不能超过10') else: return data class BookSerializer(serializers.Serializer): id = serializers.IntegerField(required=False) name = serializers.CharField(max_length=32, source='title') # source指定该字段对应表中的哪一个字段,并且不能同名 price = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True) # publish = serializers.CharField(max_length=32, validators=[check_publish, ], # required=False) # validators验证,列表中写函数内存地址 # func_test = serializers.CharField(source='test') # 执行表模型中的test方法,并将返回值赋给该字段 publish_addr = serializers.CharField(source='publish.addr') # source支持跨表操作 publish = serializers.SerializerMethodField() # SerializerMethodField跨表查询,需要搭配写一个 'get_字段名' 方法 def get_publish(self,obj): dic = {'name':obj.publish.name, 'addr':obj.publish.addr} return dic # 因为没有建立表关联关系,不知道要存哪一张表,所以需要手动重写create def create(self, validated_data): res = models.Book.objects.create(**validated_data) print(res) return res def update(self, instance, validated_data): instance.title = validated_data.get('title') instance.price = validated_data.get('price') instance.publish = validated_data.get('publish') instance.save() return instance # 局部钩子 def validate_title(self, data): if data.startswith('sb'): raise ValidationError('不能以sb开始') else: return data # 全局钩子 def validate(self, attrs): title = attrs.get('title') publish = attrs.get('publish') if title == publish: raise ValidationError('重名!') else: return attrs # class BookModelSerializer(serializers.ModelSerializer): # # publish = serializers.CharField(max_length=32, source='publish.name') # 重写publish字段,通过source跨表操作 # # class Meta: # model = models.Book # 表示该序列化类与book表建立了关系 # # fields = ['id', 'title', 'publish'] # fields中是序列化和反序列化的字段 # fields = '__all__' # 表示序列化所有字段(包括重写字段) # # exclude = ['id'] # 表示序列化除去列表中以外的所有字段 ### 不能与fields同时使用 # # read_only_fields = ['price', 'publish'] # 序列化显示的字段 # # write_only_fields = ['title'] # 反序列化需要传入的字段 (可能部分版本不能使用) # # # extra_kwargs给指定字段添加额外参数 # # extra_kwargs = {'title': {'max_length': 32, 'write_only': True}, 'publish': {'validators': [check_publish, ]}} # # depth = 1 # 表示可以跨1个表查询(连表一次) class PublishModelSerializer(serializers.ModelSerializer): class Meta: model = models.Publish # fields = '__all__' fields = ['name', 'addr'] class BookModelSerializer(serializers.ModelSerializer): publish = PublishModelSerializer() # 序列化类的嵌套 class Meta: model = models.Book fields = '__all__' # publish = serializers.SerializerMethodField() # SerializerMethodField跨表查询,需要搭配写一个 'get_字段名' 方法 # def get_publish(self, obj): # dic = {'name': obj.publish.name, 'addr': obj.publish.addr} # return dic

浙公网安备 33010602011771号