序列化组件
我们在使用json进行数据的序列化操作时,只能对基本数据类型进行序列化
当需要序列化的是对象是比如QuerySet对象,我们只能循环取出每个对象将具体属性放到字典中后进行序列化操作。步骤较为复杂,如下所示
def get(self, request):
response = {'status': 100, 'data': None}
ll = [{'name': book.name, 'price': book.price} for book in books]
# 返回数据是json格式数据
response['data'] = ll
# safe = True 表示数据可以是列表
return JsonResponse(response, safe=False)
Django自带序列化组件
from django.core import serializers
def test(request):
book_list = Book.objects.all() # queryset对象
ret = serializers.serialize("json", book_list)
return HttpResponse(ret)
rest-framework序列化之Serializer
models.py
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
serializers.py
-1 先导入
from rest_framework.serializers import Serializer
from rest_framework import serializers
-2 写一个类,继承Serializer
-3 在类内部写属性:
name=serializers.CharField()
-4 使用:
先生成对象,需要传参数 instance:要序列化的对象(可能是queryset,也可能是单个对象)
many:如果是queryset---True,,如果是单个对象--False
-5 序列化的数据:对象.data --->是一个字典
(1)非关联字段或一对多字段
可以不用source,直接用 字段名 当变量名,必须为字段名
也可以用
source
来指定需要的目标字段 (推荐,尽量让字段名不要泄露)source`也可以用来指定模型层中的方法
一对多关联关系,可以在 source 中用
.
来指定字段,例如取出版社名字,用source='publish.name'
(2)一对多或者多对多字段
多对多要用
SerializerMethodField()
,然后定义一个get_变量名
的方法,方法名字必须为 get_变量名
get_变量名
方法要传参,传入当前对象,例如在 BookSerializer 中就是book对象在
get_变量名
方法中,也可以对数据进行序列化,例如取书的所有作者,就可以对作者序列化然后 return
from rest_framework import serializers
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
继承serializers.Serializer详解
继承serializers.ModelSerializer
from app01 import models
class PublishSerializers(serializers.ModelSerializer):
class Meta:
model=models.Publish
fields='__all__'
# 指定只取这两个字段
#fields = ['nid','name']
# 去掉指定的字段
# exclude=['publish','authors']
# fields,跟exclude不能连用
# 指定深度,就是跨几个表(官方建议小于10,我给你的建议小于3)
# depth = 2
# read_only_fields指明只读字段, 仅用于序列化输出的字段.
# write_only_fields指明只读写段, 仅用于反序列化输入的字段.
# 可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
# extra_kwargs = { 'bread': {'min_value': 0, 'required': True},
# 'bcomment': {'min_value': 0, 'required': True}, }
view.py:
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers
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
return Response(bs.data)
# 序列化方式4:
# ret=models.Book.objects.all().values('nid','title')
# dd=list(ret)
# return HttpResponse(json.dumps(dd))
注意:
source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))
choice的用法:
-拿出数字对应的中文:get _ 字段名 _ dispaly()
如在模型中定义一个方法,直接可以在在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
# fields = "__all__"
fields=['nid','title','authors','publish']
# exclude=('nid',) #不能跟fields同时用
# depth = 1 #深度控制,写 几 往里拿几层表的数据,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
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
小结:
反序列化的目的是为了调用反序列化对象的save方法
保存和更新:(必须继承ModelSerializer)
-保存
-ser=BookSerializer(data=request.data)
-ser.save()---->向数据库中插一条数据
-更新
-ser=BookSerializer(data=request.data.instance='要更新的对象')
-ser.save()---->向数据库中插一条数据
APIView类说明
APIView 类
-继承了View
-重写了as_view方法,在内部屏蔽了xsrf
-重写了dispatch方法---核心
Request 类
-封装了原来的request
-request.data --->前台传递过来的数据,放在里面
-request重写了__getattr__方法
-request.query_params 就是原来request.的GET
序列化组件之请求数据校验和保存功能
-
序列化类必须继承
ModelSerializer
类,只有该类可以指定数据保存修改的目标表模型。倘若一定要继承Serializer
类,可以通过重写save方法,来实现保存和修改数据 -
序列化组件校验和forms组件类似(validate->clean)
-
钩子函数抛异常,异常是 rest_framework.exceptions 下的 ValidationError
-
新增数据:
新增数据,将数据传入实例化类产生对象,通过is_valid()
校验,校验通过,利用序列化对象的save()
方法保存ser=BookSerializer(data=request.data) if ser.is_valid(): ser.save()
-
修改数据:
方式一:
修改数据一定要在实例化序列化类的时候传参instance='要修改的对象'
指定要修改的对象ret = models.Book.objects.filter(name=request.data.get('name')).first() ser=BookSerializer(data=request.data, instance=ret') if ser.is_valid(): ser.save()
方式二:
ret = models.Book.objects.filter(name=request.data.get('name')).first() ser=BookSerializer(data=request.data) if ser.is_valid(): ser.updata(instance=ret')