#序列化组件是干什么的, #数据需要处理,不可能把queryset对象传给前台
一、自己用for循环处理(太麻烦)
class Books(APIView): def get(self,request,*args,**kwargs): response = {'status': 100, 'data': None} ret=models.Book.objects.all() print(ret) #<QuerySet [<Book: 西游记>, <Book: 红楼梦>, <Book: 三国演义>, <Book: 水浒传>]> l1=[{'name':book.name} for book in ret] l2=[{'name':book.name,'price':book.price} for book in ret] #展示的字段可控 print(l1) print(l2) #[{'name': '西游记'}, {'name': '红楼梦'}, {'name': '三国演义'}, {'name': '水浒传'}] #[{'name': '西游记', 'price': Decimal('11.00')}, {'name': '红楼梦', 'price': Decimal('22.00')}, {'name': '三国演义', 'price': Decimal('23.00')}, {'name': '水浒传', 'price': Decimal('3.00')}] response['data'] = l1 return JsonResponse(response, json_dumps_params={'ensure_ascii': False})
二、用django提供的序列化组件
# django提供的序列化组件(不可控,展示所有字段,有时候我们并不需要) #导入 from django.core import serializers ret=serializers.serialize('json','queryset对象') ret就是序列化之后的字符串了,不需要再序列化了 from django.core import serializers class Books(APIView): def get(self,request): response = {'status': 100, 'data': None} books = models.Book.objects.all() # 先构造出所有书籍的字典的列表 # 用django提供的序列化组件 ret=serializers.serialize('json',books) print(ret) # 返回数据是json格式数据 response['data'] = ret return HttpResponse(ret)
三、rest-framework序列化之Serializer

from django.db import models # Create your models here. class Book(models.Model): title=models.CharField(max_length=32) price=models.IntegerField() 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
mySer.py
#可以在views.py中直接写,也可创建一个py文件,在里边写 mySer.py #1 先导入from rest_framework import serializers #2 写一个类,继承serializers.Serrializer class BookSerializer(serializers.Serializer): #在类内部写想要的字段 name = serializers.CharField() xx = serializers.CharField(source='name') #同上,就把字段名改为xx price= serializers.CharField() publish = serializers.CharField() #支持跨表查询 test = serializers.CharField(source='publish.test') #指定函数 另外,source不仅可以指定字段,也可以指定方法(函数),拿到的是函数的返回结果,没有return,则拿到None ------------------------------------------------------------------- class BookSerializer(serializers.Serializer): publish=serializers.SerializerMethodField() # 方法名:叫get_字段名,要传参数,参数是:当前book对象 def get_publish(self,obj): # obj 是当前book对象 dic={'name':obj.name,'email':obj.publish.email} return dic
views.py

# 使用: from app01 import models from rest_framework.views import APIView from app01.mySer import BookSerializer from django.http import JsonResponse class Book(APIView): def get(self,request,*args,**kwargs): ret = models.Book.objects.all() #拿到所有queryset对象 book_serializer = BookSerializer(instance=ret,many=True) #需要的两个参数 return JsonResponse(book_serializer.data,safe=False) #先生成对象,需要传参数 instance:要序列化的对象 (可能是queryset,也可能是单个对象) #序列化多条 many=True #instance可不写,按位置传参
上边的是一对多字段,多对多字段

class BookSerializer(serializers.Serializer): publish=serializers.SerializerMethodField() def get_publish(self,obj): dic={'name':obj.publish.name,"city":obj.publish.city} return dic #方式一 authors = serializers.SerializerMethodField() def get_authors(self,obj): aus=obj.authors.all() li=[] for a in aus: #通过for循环拿到所有作者 c=li.append({'name':a.name,'age':a.age}) return c #方式二 authors = serializers.SerializerMethodField() def get_authors(self,obj): aus = obj.authors.all() #拿到书的所有作者 aus_author = AuthorSerializer(aus,many=True) return aus_author.data
四、rest-framework序列化之ModelSerializer
#上边的都需要手动写字段 class BookSerializers(serializers.ModelSerializer): class Meta: #必须写这么一个类 model = models.Book #指定模型表 # fields = "__all__" #展示所有字段 fields=['nid','title','authors','publish'] #展示指定字段
# exclude=('nid',) # 哪个字段不展示 # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢, #重写属性(如果没有指定deoth,内层的仅显示id,也就是跨表的字段没有显示出来,仅显示当前表,) 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(快速生成链接)
#关键是怎么拼接"http://127.0.0.1:8000/publish/1"这个域名
views.py
from app01.mySer import BookSerializer from django.http import JsonResponse,HttpResponse from app01 import models from rest_framework.views import APIView class Books(APIView): def get(self,request,*args,**kwargs): ret = models.Book.objects.all() book_ser = BookSerializer(ret, many=True, context={'request': request}) # context={'request': request},可以从request中拿到http://127.0.0.1:8000 return JsonResponse(book_ser.data,safe=False) class Publish(APIView): def get(self,request,*args,**kwargs): return HttpResponse('ok')
urls.py
url(r'^publish/(?P<pk>d+)',views.Books.as_view(),name='pub_link_name'), #name='pub_link_name,取别名,方便反向解析
mySer.py
from rest_framework import serializers class BookSerializer(serializers.Serializer): name = serializers.CharField() # publish = serializers.CharField() publish = serializers.HyperlinkedIdentityField(view_name='pub_link_name',lookup_field='publish_id',lookup_url_kwarg='pk') #view_name='pub_link_name',就是urls中的name,这里拿到publish #lookup_field:根据表的哪个字段,来拼路径 #,lookup_url_kwarg='pk',反向解析有名分组的名字
六、请求数据校验与保存

class BookSerializers(serializers.ModelSerializer): class Meta: model=Book fields="__all__" #———————— class BookView(APIView): def post(self, request): books=BookSerializers(data=request.data) #books是BookSerializers的对象 if books.is_valid(): #是否校验通过 bs.save() #把数据同步到数据库 # BookSerializers中没有save方法,找父类,ModelSerializer有, 如果BookSerializers继承的是serializers.Serializer,该类中没有save方法,所以只有继承了ModelSerializer才能掉用save方法 return Response(bs.data) else: return Response(bs.errors)

# 前提: # 1)序列化类中不能修改原字段的深度 # 2)通过 data=请求数据包 得到可以操作orm的序列化对象,instance来明确修改的对象,校验成功后还是走save()来更新 # 3)必须先校验,才能保存或更新 # 增 class Books(APIView): """ { "name":"水浒传", "price":"88.88", "author":[1, 2, 3 ] } """ def post(self, request): book_dic = request.data book_json = objson.BookJson(data=book_dic) # 数据的校验 if book_json.is_valid(): book_json.save() # 不涉及跨表操作 return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) # 查改删 class Book(APIView): def get(self, request, id): book_obj = models.Book.objects.filter(pk=id).first() book_data = objson.BookJson(book_obj).data return Response({ 'status': 0, 'msg': 'ok', 'results': book_data }) def put(self, request, id): book_obj = models.Book.objects.filter(pk=id).first() # instance来明确修改的对象,校验成功后还是走save()来保存 book_json = objson.BookJson(data=request.data, instance=book_obj) if book_json.is_valid(): book_json.save() return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) def delete(self, request, id): models.Book.objects.filter(pk=id).delete() return Response({ 'status': 2, 'msg': 'delete success', })

# views.py class Books(APIView): def post(self, request): book_dic = request.data book_json = objson.BookJson(data=book_dic) # 数据的校验 if book_json.is_valid(): # book_json.save() # 不涉及跨表操作 return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) return Response({ 'status': 0, 'msg': book_json.errors, }) # objson.py class BookJson(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' # 认证 name = serializers.CharField( max_length=5, min_length=1, error_messages={ "max_length": "太长了", "min_length": "太短了", } ) # 局部钩子 def validate_name(self, value): from rest_framework.exceptions import ValidationError if 'sb' in value: raise ValidationError("出现了敏感词汇") return value # def validate_price(self, value): # from rest_framework.exceptions import ValidationError # if float(value) < 0: # raise ValidationError("价格不合理") # return # 了解:如果多个字段直接协同校验,采用全局钩子 def validate(self, attrs): from rest_framework.exceptions import ValidationError pwd = attrs.get('pwd') re_pwd = attrs.get('re_pwd') if pwd == re_pwd: return attrs else: raise ValidationError('密码校验失败')