Django REST framework序列化

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()
posted @ 2020-03-17 16:49  米兰的小铁將  阅读(211)  评论(0编辑  收藏  举报