后台返回json数据的方式
一.自己写for循环来处理
def get(self,request):
book_list = Book.objects.all()
dic = [{'id':book.pk,'name':book.name} for book in book_list]
return JsonResponse(dic,safe=False,json_dumps_params={'ensure_ascii':False})
#safe=False 可以处理列表
#json_dumps_params = {'ensure_ascii':False} 将默认编码ascii取消,使前台可以显示中文
#优点:可以自己处理字段
#缺点:单表查询ok,多表查询会复杂,无法处理时间字段
二,使用django提供的序列化组件
from django.core import serializers
ret = serializers.serialize('json',book_list)
return Httpresponse(ret)
#优点:操作简单
#缺点:不可控,将所有字段序列化,无法选择字段
三.使用drf提供的序列化组件
1.drf是一个app,使用前需在settings.py文件中设置app配置中添加'rest_framework'
2.导入
from rest_framework import serializers
from rest_framework.response import Response
3.新建myserializer.py文件,创建类继承serializers.Serializer
class BookSerializer(serializers.Serializer):
4.在类内部写字段(需要被序列化的字段)
name = serializers.CharField()
desc = serializers.CharField()
author = serializers.CharField()
#source参数将name字段以xx显示返回给前台
xx = serializers.CharField(source='name')
#publish为外键,前台显示为对象,可以改写Publish类的__str__方法,将publish.name显示在前台,
#也可以使用source参数将publish.name赋值给publish,source参数以需序列化类的对象为基础,即book.publish.name
#可以通过book对象连表查询的数据都可以通过source返回给前台,
publish = serializers.CharField(source = 'publish.name')
#source也可以指定方法,源码以split('.')拆分成列表,for循环,是方法的话(callable)执行方法,此处将test方法的结果返回给test字段
test = serializers.CharField(source='test')
5.使用,先生成对象,需要传参数instance,instance可以是queryset对象,也可以是单个对象
instance = 'queryset对象'时需设置参数many = True,源码会对列表进行序列化
instance = '单个对象'时需设置参数many=False,源码会使用单个序列化
from book.myserializers import BookSerializer
from rest_framework.response import Response
class Query(APIView):
def get(self,request):
book_list = Book.objects.all()
book_ser = BookSerializer(instance=book_list,many=True)
#使用drf提供的Response(继承了Httpresponse)返回数据,
return Response(book_ser.data)
6.返回字典book_ser.data #data为私有属性,实际是调用了data方法
SerializerMethodField
当返回的对象有多个时,比如一本书有多个作者
author = serializers.CharField() 需要返回一个列表,此时需要用到SerializerMethodField()
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
desc = serializers.CharField()
#1.定义字段
author = serializers.SerializerMethodField()
#2.定义对应方法,方法的返回值赋值给字段,以get_开头,才能被源码解析到
def get_author(self,obj):
author_list = obj.author.all()
#这里使用了for循环
#dic = [{'name':author.name,'phone':author.phone} for author in author_list]
#return dic
#也可以采用给author创建序列化类来实现
author_ser=AuthorSerializer(instance=author_list,many=True)
return author_ser.data
class AuthorSerializer(serlizers.Serializer):
name = serializers.CharField()
phone = serializers.CharField()
#优点:可控,可扩展
ModelSerializer
Serializer类并没有指明给哪个类进行序列化
使用ModelSerializer可以指明给哪个类进行序列化
from app01 import models
#继承ModelSerializer
class BookSerializer(serializers.ModelSerializer):
class Meta:
#指定表模型
model = Book
#指定要序列化的表字段
fields = ['nid','name']
#指定序列化所有字段
#fields = '__all__'
#指定不要序列化的表字段(不能跟fields连用)
#exclude=['id']
#深度,连表的深度,官方建议最多写10,个人建议3
depth=1
#可以再自定义自己要序列化的字段
publish = serializer.CharField(source='publish.name')
from book.models import *
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','desc','author']
# depth = 1
author = serializers.SerializerMethodField()
#注意:自定义的字段必须在fields中定义,否则报错
def get_author(self, obj):
author_list = obj.author.all()
author_ser = AuthorSerializer(instance=author_list, many=True)
return author_ser.data
# publish = serializers.CharField(source='publish.name')
序列化单个对象
class Book(APIView):
def get(self,request,id,*args,**kwargs):
book = models.Book.objects.filter(pk=id).first()
#单个对象,many=False,instance必须是单个对象,而不是querset对象(都是列表)
book_ser = BookSerializer(instance=book,many=False)
return Response(book_ser.data)
反序列化组件
class Books(APIView):
def get(self, request):
book_list = models.Book.objects.all()
book_ser = BookSerializer(instance=book_list, many=True)
return Response(book_ser.data)
def post(self, request):
res = {"staus":100,"msg":"新增成功","data":[]}
`
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
res["data"] =book_ser.data
else:
res["msg"]="新增失败"
res["data"] = book_ser.errors
return Response(res)
# 没有继承ModelSerializer无法使用save,因为不确定保存给哪个表
局部钩子
函数名称:validate_字段名
触发条件:字段名校验通过了,才会触发局部钩子
from book.models import *
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','desc','author']
# depth = 1
author = serializers.SerializerMethodField()
def get_author(self, obj):
author_list = obj.author.all()
author_ser = AuthorSerializer(instance=author_list, many=True)
return author_ser.data
# publish = serializers.CharField(source='publish.name')
def validate_name(self,value):
print(0)
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
return value
全局钩子
函数名称:validate
触发条件:局部钩子通过后才会触发
from book.models import *
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name','desc','author']
# depth = 1
author = serializers.SerializerMethodField()
def get_author(self, obj):
author_list = obj.author.all()
author_ser = AuthorSerializer(instance=author_list, many=True)
return author_ser.data
# publish = serializers.CharField(source='publish.name')
def validate_name(self,value):
if value.startswith('sb'):
raise ValidationError('不能以sb开头')
return value
def validate(self, attrs):
publish =attrs.get('publish')
if not publish:
raise ValidationError('不能为空')
return attrs
更新对象put方法
def put(self, request, id, *args, **kwargs):
res = {"staus": 100, "msg": "更新成功", "data": []}
book = models.Book.objects.filter(pk=id).first()
#更新的时候,反序列化内加入instance参数,保存的时候不需要instance
book_ser = BookSerializer(data=request.data,instance=book)
#进行save操作前必须判断是否通过校验,执行.is_valid才会去校验字段
if book_ser.is_valid():
book_ser.save()
res["data"]= {"name":book.name,'desc':book.desc}
else:
res["msg"] = "更新失败"
res["data"] = book_ser.errors
return Response(res)