一 rest-framework序列化之Serializer
models部分:
from django.db import models
# Create your models here.
class Book(models.Model):
title=models.CharField(max_length=32)
price=models.IntegerField() #int类型
pub_date=models.DateField() #时间类型
publish=models.ForeignKey("Publish") #外键
authors=models.ManyToManyField("Author") #多对多的表
def __str__(self):
return self.title
class Publish(models.Model):
name=models.CharField(max_length=32)
email=models.EmailField() #邮箱类型
def __str__(self):
return self.name
class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
def __str__(self):
return self.name
#创建三种类,其中书和出版社时多对一的关系,外键放在多一方。书和作者是多对多的关系,建第三张表
views部分:
from rest_framework.views import APIView #在View上封装的
from rest_framework.response import Response #用来响应,Json序列化
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers #django自带的序列化文件
from rest_framework import serializers #rest封装的序列化模块
class BookSerializers(serializers.Serializer):
title=serializers.CharField(max_length=32)
price=serializers.IntegerField()
pub_date=serializers.DateField()
publish=serializers.CharField(source="publish.name") #可以直接点属性
#authors=serializers.CharField(source="authors.all") #可以直接点方法,但是不加括号
authors=serializers.SerializerMethodField()
def get_authors(self,obj):
temp=[]
for author in obj.authors.all():
temp.append(author.name)
return temp
#此处可以继续用author的Serializers,
# def get_authors(self,obj):
# ret=obj.authors.all()
# ss=AuthorSerializer(ret,many=True)
# return ss.data
class BookViewSet(APIView):
def get(self,request,*args,**kwargs):
book_list=Book.objects.all()
# 序列化方式1:
# from django.forms.models import model_to_dict
# import json
# data=[]
# for obj in book_list:
# data.append(model_to_dict(obj)) #直接将对象变成字典
# print(data)
# return HttpResponse("ok")
# 序列化方式2:
# data=serializers.serialize("json",book_list)
# return HttpResponse(data)
# 序列化方式3:
bs=BookSerializers(book_list,many=True) #many=True代表有多条数据,如果只有一条数据,many=False,默认就是false
return Response(bs.data)
# 序列化方式4:
# ret=models.Book.objects.all().values('nid','title')
# dd=list(ret)
# return HttpResponse(json.dumps(dd))
注意:
1. 浏览器中访问时,必须在settings中配置app,将rest_framework加入其中,这样放回Reponse时不会出错
2. source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))
如在模型中定义一个方法,直接可以在在source指定执行
class UserInfo(models.Model):
user_type_choices = (
(1,'普通用户'),
(2,'VIP'),
(3,'SVIP'),
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32,unique=True)
password = models.CharField(max_length=64)
#视图
ret=models.UserInfo.objects.filter(pk=1).first()
aa=ret.get_user_type_display()
#serializer
xx=serializers.CharField(source='get_user_type_display')
二 rest-framework序列化之ModelSerializer
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book #指定model类,这里的
# fields = "__all__" #所有的字段
fields=['nid','title','authors','publish']
# exclude=('nid',) #不能跟fields同时用
# depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层 ,1就拿出外键的第一层详细数据
publish=serializers.SerializerMethodField() #可以重写属性这个方法可以与下面的函数名对应
def get_publish(self,obj):
return obj.publish.name
authors=serializers.SerializerMethodField()
def get_authors(self,obj):
ret=obj.authors.all()
ss=AuthorSerializer(ret,many=True)
return ss.data #返回的值就是返回给前端的值
三 生成hypermedialink(极少数)
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
# 生成连接,直接查看出版社详情
publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id', lookup_url_kwarg='pkk')
#第一值为url中的别名,第二个值为当前对象的publish的值,第三个为有名分组名。
authors=serializers.SerializerMethodField()
#只有这种SerializerMethodField方法可以这样自定义返回的值
def get_authors(self,obj):
ret=obj.authors.all()
ss=AuthorSerializer(ret,many=True)
return ss.data
#--------------
res=BookSerializers(ret,many=True,context={'request': request}) #固定写法
#--------------
class Publish(APIView):
def get(self,request,pkk): #获取有名分组名数据
print(pkk)
return HttpResponse('ok')
#----路由---
url(r'^publish/(?P\d+)$', views.Publish.as_view(),name='ttt'),
四 序列化组件之请求数据校验和保存功能
class BookSerializers(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
class BookView(APIView):
def post(self, request):
# 添加一条数据
print(request.data)
bs=BookSerializers(data=request.data) #通过序列化文件来校验字段
if bs.is_valid():
bs.save() # 生成记录 ModelSerializer只有这个类有save方法
return Response(bs.data) #返回添加的信息
else:
return Response(bs.errors)#返回错误信息
自定义errors的值:
#注意自定义create方法的使用
class BookSerializer1(serializers.Serializer):
title=serializers.CharField(error_messages={'required': '标题不能为空'})
#这种方式要保存,还有继承serializers.ModelSerializer类中自定义的属性,都必须重写create方法
def create(self, validated_data):
authors=validated_data.pop('authors') #拿出字段值,并删除字典中的key:value值
obj=models.Book.objects.create(**validated_data) #创建book对象
obj.author.add(*authors) #第三张表中添加数据
return obj
通过源码查看留的校验字段的钩子函数:
#源码的查找顺序
#is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
局部
def validate_title(self, value): #value是字段的值
from rest_framework import exceptions
raise exceptions.ValidationError('看你不顺眼') #如果校验不通过就报错
return value
#全局
def validate(self, attrs): #attr是一个字典
from rest_framework import exceptions
if attrs.get('title')== attrs.get('title2'):
return attrs
else:
raise exceptions.ValidationError('不想等啊')
五 序列化组件源码分析
序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
当参数传过去,判断是方法就加括号执行,是属性就把值取出来