1、关于序列化与反序列化
web有两种应用模式,一种是前后端不分离,一种是前后端分离,当前后端分离的时候,后端只需要向前端传输数据即可,不需要进行其他的操作;
现阶段主流的数据格式为json格式,所以在restframework在前后端传输数据时,也主要是json数据,过程中就要需要把其他数据转换成json数据,
比如数据库查询所有数据时,是queryset对象,那就要把这对象处理成json数据返回前端。
序列化与反序列化
增:效验请求数据 > 执行反序列化过程 > 保存数据库 > 将保存的对象序列化并返回
删:判断要删除的数据是否存在 > 执行数据库删除
改:判断要修改的数据是否存在 > 效验请求的参数 > 执行反序列化过程 > 保存数据库 > 将保存的对象序列化并返回
查:查询数据库 > 将数据序列化并返回
rest-framework的序列化组件:
提供了定义序列化器Serializer的方法,可以快速根据Django ORM 或者其他库自动序列化/反序列化;
2、Serializers序列化与反序列化
序列化
-使用drf的序列化组件
-1 新建一个序列化类继承Serializer
-2 在序列化类中写要序列化的字段
-在视图中使用序列化的类
-1 实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
-2 对象.data
-3 return Response(对象.data)
-高级用法:
-source:可以指定字段(name publish.name),可以指定方法,
-SerializerMethodField搭配方法使用(get_字段名字)
publish_detail=serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city}
-read_only:反序列化时,不传
-write_only:序列化时,不显示
案例:
settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
models.py中建表
from django.db import models
# Create your models here.
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField()
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author')
def __str__(self):
return self.name
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
def __str__(self):
return self.name
执行数据库迁移命令;
在app下新建一个序列化类并继承Serializer :
app01serializer.py
from rest_framework import serializers
# 序列化Author的类
class AuthorSerializer(serializers.Serializer):
name = serializers.CharField()
age = serializers.CharField()
# 序列化Book的类
class BookSerializer(serializers.Serializer):
# 指定source='name',表示序列化模型表中的name字段,重名命为name5,可以避免直接暴露数据库字段
# 模型表中的字段和source指定的字段不能重名
# name = serializers.CharField()
name5 = serializers.CharField(source='name')
# write_only 序列化的时候,该字段不显示
# read_only 反序列化的时候,该字段不传
# price = serializers.CharField()
price = serializers.CharField(write_only=True)
# 如果要取出版社的city--> source='publish.city'
publish = serializers.CharField(source='publish.city')
# source不仅可以指定一个字段,还可以指定一个方法
# 在modles.py的Book表中写了一个test方法,并返回xxx
xxx = serializers.CharField(source='test')
# 比如要序列化出版社的详情; SerializerMethodField对应着一个方法,方法返回什么内容,publish_detail就是什么内容
publish_detail = serializers.SerializerMethodField()
# SerializerMethodField对应的方法,固定写法:get_字段名
# 因为这个类是序列化Book的,参数obj就是Book对象,然后用Book对象去拿出版社的详情
def get_publish_detail(self, obj):
print(type(obj))
return {'name':obj.publish.name, 'city':obj.publish.city}
# 比如要返回所有的作者信息
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
# return [{'name': author.name, 'age': author.age} for author in obj.authors.all()]
# 上面这种return的方式是用的列表推导式,当有变化时就要不断修改这个推导式,
# 我们也可以再添加一个序列化的类,当有变化时修改类就行了
# 此时在上面添加了一个序列化Author的类,在这里使用它
authorser = AuthorSerializer(obj.authors.all(), many=True)
return authorser.data
在视图中使用序列化的类 :
views.py
from app01 import models
from rest_framework.views import APIView
from rest_framework.serializers import Serializer
# Response本质也会是继承了Httpresponse,但是功能更强大了
from rest_framework.response import Response
# 导入新建的序列化类
from app01.app01serializer import BookSerializer
# Create your views here.
class Books(APIView):
def get(self, request):
response = {"code":100, "msg":"查询成功"}
books = models.Book.objects.all()
# 如果序列化多条,要写many=True(序列化多条时,其实是序列化的queryset对象 )
# 如果序列化一条,many=True可以不写(序列化一条时,就不是queryset了)
bookser = BookSerializer(books, many=True)
response['data'] = bookser.data
print(type(bookser.data))
return Response(response)
urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^books/', views.Books.as_view()),
]
反序列化
-使用继承了Serializers序列化类的对象,来进行反序列化
-在自己写的序列化类中重写create方法
-重写create方法,实现序列化
-在序列化类中:
def create(self, validated_data):
ret=models.Book.objects.create(**validated_data)
return ret
-在视图中:
def post(self,request):
bookser=BookSerializer(data=request.data)
if bookser.is_valid():
ret=bookser.create(bookser.validated_data)
return Response()
在app01serializer.py的序列化Book的类中,重写create方法:
# 序列化Book的类
class BookSerializer(serializers.Serializer):
……
……
# 重写create方法
def create(self, validated_data):
ret = models.Book.objects.create(**validated_data)
return ret
views.py
from app01 import models
from rest_framework.views import APIView
from rest_framework.serializers import Serializer
from rest_framework.response import Response
# 导入新建的序列化类
from app01.app01serializer import BookSerializer
# Create your views here.
class Books(APIView):
def get(self, request):
response = {"code":100, "msg":"查询成功"}
books = models.Book.objects.all()
# 如果序列化多条,要写many=True(序列化多条时,其实是序列化的queryset对象 )
# 如果序列化一条,many=True可以不写(序列化一条时,就不是queryset了)
bookser = BookSerializer(books, many=True)
response['data'] = bookser.data
print(type(bookser.data))
return Response(response)
def post(self, request):
# 实例化产生一个序列化类的对象,data是要反序列化的字典
bookser = BookSerializer(data=request.data)
if bookser.is_valid():
ret = bookser.create(bookser.validated_data)
return Response()
3、ModelSerializers序列化与反序列化
序列化
app01serializer.py
from app01 import models
class BookSerializer(serializers.ModelSerializer):
class Meta:
# 指定表模型
model = models.Book
# fields表示要序列化哪几个字段
# fields=('nid','name')
# exclude表示不序列化哪些字段,不能跟fields同时使用
# exclude=['name',]
# __all__表示序列化所有字段
fields = ('__all__')
# 深度是1,表示可以跨的表数量,官方建议不要超过10,个人建议不要超过3
# 会拿到与此表深度关系为1的表中的所有数据,且不能定制化,与下面的方式各有不同的使用场景
depth=1
# 比如要序列化所有作者的详情信息(和Serializer中相同),这种方法可以定制化(代码在Meta类外面)
# authors = serializers.SerializerMethodField()
# def get_authors(self,obj):
# ret = AuthorSerializer(instance=obj.authors.all(), many=True)
# return ret.data
反序列化
#使用继承了ModelSerializers序列化类的对象,反序列化
#在视图中:
def post(self,request):
bookser=BookSerializer(data=request.data)
if bookser.is_valid():
ret=bookser.save()
return Response()
4、反序列化的校验
app01serializer.py
# 局部校验
def validate_name(self,value):
# value就是传过来的值,如:name:wei 这里的wei就是value
print(value)
raise exceptions.ValidationError('不能以sb开头')
# if value.startswith('sb'):
# raise ValidationError('不能以sb开头')
# return value
#全局校验
# 如果用了fields=('__all__')的方式,这里的attrs可能会找不到具体的字段
def validate(self,attrs):
# attrs是校验通过的数据,是一个字典
print(attrs)
# if attrs.get('price')!=attrs.get('xx'):
# raise exceptions.ValidationError('name和price相等,不正常')
return attrs
views.py
class Books(APIView):
def get(self,request):
...
def post(self,request):
#实例化产生一个序列化类的对象,data是要反序列化的字典
bookser=BookSerializer(data=request.data)
# bookser.data
# raise_exception=True把校验的错误数据抛到前端,前后端分离项目用不到
if bookser.is_valid(raise_exception=True):
#清洗通过的数据
bookser.save()
else:
# 抛出校验错误的信息
print(bookser.errors['name'][0])
return Response()