DRF序列化和反序列化(一:Serializer)
一:表关系如下
from django.db import models # Create your models here. __all__=['Book','Publisher','Authon'] class Book(models.Model): title =models.CharField(max_length=32,verbose_name='图书名称') CHOICES=((1,'python'),(2,'go'),(3,'linux')) category=models.IntegerField(choices=CHOICES,verbose_name='图书类别') pub_time=models.DateTimeField(verbose_name='出版日期') authon=models.ManyToManyField('Authon') publisher=models.ForeignKey(to='Publisher',on_delete=None) def __str__(self): return self.title class Authon(models.Model): name= models.CharField(max_length=32, verbose_name='作者姓名') def __str__(self): return self.name class Publisher(models.Model): title = models.CharField(max_length=32, verbose_name='出版社名称') def __str__(self): return self.title
二:使用django编写接口
1:使用jsonResponse模块进行数据序列化。
from django.http import JsonResponse class Bookview(View): #使用jsonResponse 当存在外键时,需要自己手动对数据进行处理。 def get(self,request): book_list=models.Book.objects.values('id','title','pub_time','publisher',"category") book_list=list(book_list) for book in book_list: print(book) publisher_id = book['publisher'] publisher_obj=models.Publisher.objects.filter(id=publisher_id).first() book['pulisher']={ 'id':publisher_id, 'title':publisher_obj.title } return JsonResponse(book_list,safe=False,json_dumps_params={'ensure_ascii':False})
2:使用serialize模块进行数据序列化。
def get(self,request): book_list=models.Book.objects.all() book_list=serializers.serialize('json',book_list,ensure_ascii=False ) return HttpResponse(book_list)
3:使用serialize和JsonResponse不方便处
a:遇到外键关系,需要非常繁琐的处理。
三:使用rest_framework 中 serializers进行序列化和反序列化
1:基本准备
a:下载 rest-framewoke模块,pip install rest-framework
b:首先要明白后端展示给前端页面的数据,可能是经过跨表查询的具体值。而前端传送给后端,并不需要传送具体的值,也就是说前端和后端对同一个资源传递的数据类型可能不一样。比如性别,前端展示的是,男,女。但是后端在数据库存储的时候,往往是0,1
c:新建文件serializers.py(用于编写序列化规则)
d:settings中注册app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'SerDemo', 'rest_framework' #app注册 ]
2:serializers序列化
a:设定路由
--注意需要调用as_view方法
from django.urls import path,include from SerDemo import views urlpatterns = [ path('list/', views.BookApiView.as_view()), ]
b:在serializes.py编写序列化规则
--注意序列化规则内每一个字段都和models字段相对应。重点,
--外键关系一对多和多对多需要注意
--read_only=True(只进行序列化),同理write_only=True(该字段只进行反序列化)
from rest_framework import serializers from SerDemo.models import Book #一对多外键关系序列化处理 class PublisherSerializers(serializers.Serializer): id = serializers.IntegerField() title=serializers.CharField(max_length=32) #多对多外键关系序列化处理 class AuthonSerializers(serializers.Serializer): id = serializers.IntegerField() name=serializers.CharField(max_length=32) class BookSerializers(serializers.Serializer): #不需要校验 id = serializers.IntegerField(required=False,) title = serializers.CharField(max_length=32) CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux')) category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True) pub_time = serializers.DateTimeField() #处理一对多 publisher=PublisherSerializers(read_only=True) #处理多对多外键关系 many=True authon=AuthonSerializers(many=True,read_only=True)
c:视图函数的编写
--导包 (APIView,Response)
--视图函数继承APIView
--many默认参数不写默认序列化一个对象,many=True 表示序列化多个对象
--get请求会对应get方法
from SerDemo import models from rest_framework.views import APIView #视图函数继承APIView 不是View from rest_framework.response import Response #用于返回值 #BookSerializers 自己定义的序列化规则 from SerDemo.serializers import * class BookApiView(APIView): def get(self,request): book_obj = models.Book.objects.all() #序列化多组数据 和一个对象,需要many=TRUE 默认一个 ret =BookSerializers(book_obj,many=True) #序列化的数据在data属性中 return Response(ret.data)
3:serializers反序列化
a:在serializes.py编写反序列化规则
--首先序列化,我们常常需要把外键对象的值获取给前端,而反序列化,后端仅仅需要数据库一个id就能进行数据库值的插入。
--write_only表示该字段只是反序列化使用,前端发送时key也应该和该值对应
--注意一对多,多对多关系,choices的字段
class BookSerializers(serializers.Serializer): #不需要校验 id = serializers.IntegerField(required=False,) title = serializers.CharField(max_length=32,validators=[my_validata]) CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux')) category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True) w_category=serializers.ChoiceField(choices=CHOICES,write_only=True) pub_time = serializers.DateTimeField() #处理一对多 publisher=PublisherSerializers(read_only=True) publisher_id=serializers.IntegerField(write_only=True) #处理多对多外键关系 many=True authon=AuthonSerializers(many=True,read_only=True) authon_id =serializers.ListField(write_only=True)
b:views文件中编写post的请求,对数据进行添加。
--添加数据需要在BookSerializers重新编写create方法
--注意返回值
--所有的数据都在request.data方法中,(与View方法存在request.get,request.post中不同,该方法对这些方法进行封装)
def post(self,request): # print(request.data) data = BookSerializers(data=request.data) #进行数据验证,并且在BookSerializers中重写create方法 if data.is_valid(): data.save() return Response(data.data) else: return Response(data.errors)
c:编写create方法
class BookSerializers(serializers.Serializer): #不需要校验 id = serializers.IntegerField(required=False,) title = serializers.CharField(max_length=32,validators=[my_validata]) CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux')) category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True) w_category=serializers.ChoiceField(choices=CHOICES,write_only=True) pub_time = serializers.DateTimeField() #处理一对多 publisher=PublisherSerializers(read_only=True) publisher_id=serializers.IntegerField(write_only=True) #处理多对多外键关系 many=True authon=AuthonSerializers(many=True,read_only=True) authon_id =serializers.ListField(write_only=True) #向服务器添加数据,需要实现该方法 def create(self, validated_data): book =Book.objects.create(title=validated_data['title'],category=validated_data['w_category'], pub_time=validated_data['pub_time'], publisher_id=validated_data['publisher_id'] ) #添加多对多关系 book.authon.add(*validated_data['authon_id']) return book
d:put实现更新
--路由分发 path('retrieve/<int:id>',views.BookEditView.as_view())
--代码编写
--partial参数
def put(self,request,id): print(request.data) book_obj = Book.objects.filter(id=id).first() # partial True 表示可以进行部分字段跟新,Flase 表示全部跟新,默认False book_serializers = BookSerializers(book_obj,data=request.data,partial=True) #需要重写 update if book_serializers.is_valid(): book_serializers.save() return Response(book_serializers.validated_data) else: return Response(book_serializers.errors)
--重写update方法
#数据跟新 def update(self, instance, validated_data): print(validated_data.get('authon')) instance.title =validated_data.get('title',instance.title) instance.category=validated_data.get('category',instance.category) instance.pub_time =validated_data.get('pub_time',instance.pub_time) instance.publisher_id =validated_data.get('publisher_id',instance.publisher_id) if validated_data.get('authon_id'): instance.authon.set(validated_data.get('authon_id')) instance.save() return instance
e:实现delete方法
def delete(self,request,id): book_obj = Book.objects.filter(id=id).first() book_obj.delete() return Response("")
4:serializers字段校验扩展
a:局部钩子校验
--校验字段方法,固定格式validate_字段名
-- 参数value,就是该字段的值
-- 返回值
#单个字段进行校验 def validate_title(self, value): if 'python' not in value.lower: return serializers.ValidationError('标题必须含有python') return value
b:全局钩子多个字段联合校验
--方法 validate为固定方法
--attrs保存联合字段的字段值
--注意返回值
#全局钩子对字段进行联合校验 def validate(self, attrs): if attrs['category'] =='linux' and attrs['publisher_id']==3: return attrs else: return serializers.ValidationError('类型或出版社错误')
c:自定义钩子验证
#自定义校验 #在需要进行验证的字段引用 title = serializers.CharField(max_length=32,validators=[my_validata]) #优先级大于 validata_title 局部钩子 def my_validata(value): if value in '敏感信息': raise serializers.ValidationError('不能含有敏感信息') return value