django序列化组件
不用组件传值方式
views.py
from rest_framework.views import APIView
from app01 import models
from app01.Myserializer import BookSerializer
class BookView(APIview):
def get(self,request,*args,**kwargs):
#获取所有图书数据
response = {'status':100,'msg':'获取成功'}
book_list = models.Book.objects.all()
#列表推导式,结果为列表内元素为字典。
book_ll = [{'id':book.pk,'name':book.name,'price':book.price} for book in book_list ]
response['data'] = book_ll
#json不支持转列表,所有要传safe=False
return JsonResponse(response,safe=False,ensure)
使用序列化组件
方式一:rest-framework序列化之Serializer(继承serializers.Serializer)
注:需要在Settings的INSTALLED_APPS中添加 rest_framework
urls.py
views.Bookview.as_view()
MySerializer.py
from res_framework import serializers
#这个类用于被实例化,多对多字段这么写
class AuthorSerializer(serializers.Serializer):
id = serializers.Charfield()
name = serializers.Charfield()
age = serializers.Charfield()
#传给views.py的主类
class BookSerializer(serializers.Serializer):
name = serializers.Charfield()
#source 可以指定字段 , id是要序列化的表名。
id = serializers.CharField(source='nid')
#,source后字段用.的方式可以跨表查询。
publish = serializer.CharField(source='publish.email')
'''
如果在models.py的book类中定义一个test方法。
def test(self):
return str(self.price)+self.name
'''
# 返回的结果就会有xx字段,souce不但可以指定表模型字段,还可以指定模型表方法,并且赋值给xx变量
xx = serializers.Charfield(source='test')
#外键的实现方法:
#一对多字段
#如果要通过外键字段返回出版社的所有信息,包括id,name,email...
#obj是当前循环序列化到的数据对象
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
return {’id‘:obj.publish.pk,'name':obj.publish.name}
#多对多字段
#所有作者的详情,也展示出来
authors = serializers.SerializermethodFiled()
def get_authors(self,obj):
author_list = obj.authors.all()
author_ser = AuthorSerializer(author_list,many=True)
return author_ser.data
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
class BookView(APIview):
def get(self,request,*args,**kwargs):
#获取所有图书数据
response = {'status':100,'msg':'获取成功'}
book_list = models.Book.objects.all()
#实例化BookSerializer类,把要序列化的数据book_list传入
#如果要序列化querySet对象,一定要加many = True
book_ser = BookSerializer(book_list,many=True)
#把序列化后的数据book_ser.data 拿出来放到response字典中返回给客户端
response['data'] = book_ser.data
return Response(response)
访问 127.0.0.1/books
方式二:继承serialiazers.ModelSerializer(直接指定要序列化的表模型)
MySerializer.py
from app01 import models
class PublishSerializer(serializers.ModelSerializer):
class Meta: #固定写法
# 指定要序列化Book表
model = models.Book
#指定要序列化的字段
fields = ['nid','name']
#序列化所有字段
fileds ='__all__‘
#要排除的字段(不能与fileds连用)
# exclude = ['name','price']
#深度判定
depth = 1
#如果要不按照父类的来,想要自己定义显示的字段的话,自己定义一个,覆盖掉父类的字段属性。
publish = serializers.SerializerMethodField() #一对多字段
def get_publish(self,obj):
return {’id‘:obj.publish.pk,'name':obj.publish.name}
views.py(不变)
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
class BookView(APIview):
def get(self,request,*args,**kwargs):
#获取所有图书数据
response = {'status':100,'msg':'获取成功'}
book_list = models.Book.objects.all()
#实例化BookSerializer类,把要序列化的数据book_list传入
#如果要序列化querySet对象,一定要加many = True
book_ser = BookSerializer(book_list,many=True)
#把序列化后的数据book_ser.data 拿出来放到response字典中返回给客户端
response['data'] = book_ser.data
return Response(response)
获取单本图书的接口
urls.py
url(r'book/(?P<pk>\d+)',views.BookView.as_view())
MySerializer.py(参考上面的任意一种方式,最好是model)
views.py(有改动)
class BookView(APIView):
def get(self,request,pk,*args,**kwargs): # 有名分组,增加一个pk值更加方便
response = {'status':100,'msg':'获取成功'}
#取到pk =pk的这本书
book = models.Book.objects.all().filter(pk=pk).first()
#要序列化单条,many = False ,queryset的话many 就传True
#注意,这里的book是book对象,而不是queryset对象
book_ser = BookSerializer(instance=book,many=False)
#把序列化后的数据book_ser.data 拿出来放到response字典中返回给客户端
response['data'] = book_ser.data
return Response(response)
新增一本书、修改一本书、删除一本书
views.py
def post(self,request):
response = {'status':100,'msg':'新增成功'}
#取出每个字段(从request.data取出)
#简便方式:采用序列化类的反序列化功能(之前把对象转化成字典,现在把字典转化为对象)。
try:
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid(): #校验通过
book_ser.save()
response['data'] = book_ser.data
else:
response['msg'] = book_ser.errors
except Exception as e:
response['msg']=str(e)
return Response(response)
def put(self,request,pk):
response = {'status':100,'msg':'修改成功'}
#取出书籍
book = models.Book.objects.filter(pk=pk).first()
#修改,需要指定instance实例,指定修改的对象。
book_ser = BookSerializer(instance=book,data=request.data)
if book_ser.is_valid():
book_ser.save()
response['data'] = book_ser.data
else:
response['msg'] = book_ser.errors
return Response(response)
局部钩子函数对单个字段校验
全局钩子函数对全局字段校验
MySerializer.py
from app01 import models
class PublishSerializer(serializers.ModelSerializer):
class Meta: #固定写法
# 指定要序列化Book表
model = models.Book
#指定要序列化的字段
fields = ['nid','name']
#序列化所有字段
fileds ='__all__‘
#要排除的字段(不能与fileds连用)
# exclude = ['name','price']
#深度判定
depth = 1
#如果要不按照父类的来,想要自己定义显示的字段的话,自己定义一个,覆盖掉父类的字段属性。
publish = serializers.SerializerMethodField() #一对多字段
def get_publish(self,obj):
return {’id‘:obj.publish.pk,'name':obj.publish.name}
#--------------------------------------上面的都是复制的,一定要继承 serializers.ModelSerializer
from rest_framework.exceptions import ValidationError
#局部钩子
#校验name字段不能以 ‘sb’ 开头
def validate_name(self,value):
if value.startswith('sb'):
#不能让你过
raise ValidationError('出版社名不能以sb开头')
else:
return value
#全局钩子(attr为形参) ,如果不被局部校验拦截的话 attr为一个字典形式,打印出来的不是字典是因为重写了__str__方法。
def validate(self,attr):
print(attr)
name = attr.get('name') #返回的是name的值。
if name != price:
raise ValidationError('出错了')
return attr