zoukankan      html  css  js  c++  java
  • Django框架深入了解——DRF之序列化、反序列化

    Django框架深入了解——DRF之序列化、反序列化

    序列化:将Python对象准换成json格式的字符串,反之即为反序列化

    DRF的序列化使用过程:

    使用drf的序列化组件
    -1 新建一个序列化类继承Serializer
    -2 在类中写要序列化的字段

    -在视图中使用序列化的类
    -1 实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
    -2 对象.data
    -3 return Response(对象.data)

    使用示例:

    新建Django项目:settings.py文件注册rest_framework,使用MySQL数据库创建数据

    MySQL数据库连接

    models

    app01新建MySer.py

    # 先创建一个BookSer序列化类
    from rest_framework import serializers
    
    
    class BookSer(serializers.Serializer):
        id = serializers.CharField()
        title = serializers.CharField()
        publish = serializers.CharField()
        author = serializers.CharField()
    

    app01视图函数views.py中

    from django.shortcuts import render,HttpResponse,redirect
    from app01.MySer import BookSer
    from rest_framework.response import Response
    from rest_framework.views import APIView
    from app01 import models
    
    # Create your views here.
    
    class Books(APIView):
        response = {'code': 100, 'msg': '查询成功'}
        def get(self, request):
            books = models.Book.objects.all()
            books_ser = BookSer(instance=books, many=True)
            return Response(books_ser.data)
    

    配路由:

    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()),
    ]
    

    (通过NaviCat创建图书数据,用于查询...)

    使用Postman发送get请求,获取到数据库中所有图书信息

    img

    可以看出一对多和多对多的外键字段显示的是对象名字,下面进一步使用序列化,让信息显示更完善

    -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}
    

    更新版本BookSer

    from rest_framework import serializers
    
    
    class BookSer(serializers.Serializer):
        id = serializers.CharField()
        title = serializers.CharField()
        publish = serializers.CharField(source='publish.name')
        author = serializers.SerializerMethodField()
        def get_author(self, obj):
            authors = []
            for author_obj in obj.author.all():
                authors.append({'name': author_obj.name, 'age': author_obj.age})
            return authors
    

    img

    补充:

    -read_only:反序列化时,不传
    -write_only:序列化时,不显示
    

    以上是序列化的一种方式

    下面看看序列化的另外一种方式:ModelSerializers:指定了表模型

                class Meta:
                    model=表模型
                    #要显示的字段
                    fields=('__all__')
                    fields=('id','name')
                    #要排除的字段
                    exclude=('name')
                    #深度控制
                    depth=1
                -重写某个字段
                    在Meta外部,重写某些字段,方式同Serializers
    
    # 序列化方式二:
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('__all__')
    

    img

    如果只想取其中几个字段,可以进行指定:

    # 序列化方式二:
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ['id', 'title']
            # fields = ('__all__')
    
    

    img

    刚才看到__all__,序列化所有字段,查询到的数据里面publish和author都是对应id值,如果需要获取到对应publish和author的关联信息,可以在BookSer内,Meta外重新写字段,方式同serializers

    # 序列化方式二:
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # fields = ['id', 'title']
            fields = ('__all__')
        publish = serializers.CharField(source='publish.name')
        author = serializers.SerializerMethodField()
        def get_author(self, obj):
            authors = []
            for author_obj in obj.author.all():
                authors.append({'name': author_obj.name, 'age': author_obj.age})
            return authors
    
    

    img

    改进:

    class AuthorSer(serializers.Serializer):
        id = serializers.CharField()
        name = serializers.CharField()
        age = serializers.CharField()
    
    # 序列化方式二改进:
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # fields = ['id', 'title']
            fields = ('__all__')
        publish = serializers.CharField(source='publish.name')
        author = serializers.SerializerMethodField()
        def get_author(self, obj):
            ret = AuthorSer(obj.author.all(), many=True)        
            return ret.data
    
    

    img

    通过post请求新增数据:

    对数据进行新增使用反序列化实现,这里反序列化有2种情况进行新增:

    使用继承了Serializers序列化类的对象,反序列化(需重写create方法)
    from django.db import models
    
    # Create your models here.
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
        choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') )
        user_type = models.CharField(max_length=6, choices=choices, default='3')
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(decimal_places=1, max_digits=6)
        publish = models.ForeignKey(to='Publish', null=True)
        author = models.ManyToManyField(to='Author')
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=64, null=True)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
    
    class Book(APIView):
        def post(self, request):
            response = {'code': 100, 'msg': '新增成功'}
            # 使用继承了Serializers序列化类的对象,反序列化
            book = BookSer(data=request.data)
            if book.is_valid():
                # 清洗通过的数据,需要在MySer.py中重写create
                book.create(book.validated_data)
            return Response(response)
    
    
    # MySer.py
    
    class BookSer(serializers.Serializer):
        # read_only 反序列化的时候,该字段不传
        # 这里id可以不传自增,publish、author不传,当然需要在models里面把不传字段设置为null=True
        # author多对多字段不能设置null=True
        id = serializers.CharField(read_only=True) 
        title = serializers.CharField()
        price = serializers.CharField()
        publish = serializers.CharField(source='publish.id', read_only=True)
        author = serializers.SerializerMethodField(read_only=True)
        def get_author(self, obj):
            ret = AuthorSer(obj.author.all(), many=True)
            return ret.data
        # 重写create方法,才能在使用Serializer发序列化方法进行新增数据
        def create(self, validated_data):
            res = models.Book.objects.create(**validated_data)
            return res
    
    
    使用继承了ModelSerializers序列化类的对象,反序列化
    from django.db import models
    
    # Create your models here.
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
        choices = (('1', 'Super_Admin'), ('2', 'General_Admin'), ('3', 'General_User') )
        user_type = models.CharField(max_length=6, choices=choices, default='3')
    
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(decimal_places=1, max_digits=6)
        publish = models.ForeignKey(to='Publish', null=True)
        author = models.ManyToManyField(to='Author')
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        addr = models.CharField(max_length=64, null=True)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = "__all__"
    
    
    class Book(APIView):
    
        def post(self, request):
            response = {'code': 100, 'msg': '新增成功'}
    
            # 使用继承了ModelSerializers序列化类的对象,反序列化
            book_ser = BookSer(data=request.data)
            if book_ser.is_valid():
                book_ser.save()
            else:
                response['error'] = book_ser.errors['name'][0]
            return Response(response)
    
    

    使用ModelSerializer反序列化save数据后,多对多关联的那张表也会自动关联产生新的数据。

    局部校验和全局校验
    # MySer.py
    
    from rest_framework.exceptions import ValidationError
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = "__all__"
    
        def validate_title(self, value):
            if value.startswith('sb'):
                raise ValidationError('不能以sb开头')
            return value
    
        def validate(self, attrs):
            title = attrs.get('title')
            price = attrs.get('price')
            if title.startswith('禁书') or int(price) <= 15:
                raise ValidationError('书名或价格不正常')
            return attrs
    

    总结:

    -反序列化的校验
    -validate_字段名(self,value):
    -如果校验失败,抛出ValidationError(抛出的异常信息需要去bookser.errors中取)
    -如果校验通过直接return value
    -validate(self,attrs)
    -attrs所有校验通过的数据,是个字典
    -如果校验失败,抛出ValidationError
    -如果校验通过直接return attrs

  • 相关阅读:
    Pyhton 单行、多行注释方法
    laravel中不使用 remember_token时退出报错,如何解决?
    PHP实现打印出库单,有没有实现过?
    是不等号的意思
    PHP如何输出合并单元格的表
    一起谈.NET技术,.Net创建Excel文件(插入数据、修改格式、生成图表)的方法 狼人:
    一起谈.NET技术,ASP.NET MVC 通过 FileResult 向浏览器发送文件 狼人:
    一起谈.NET技术,asp.net Ajax AutoComplete控件使用 狼人:
    一起谈.NET技术,Silverlight 拖动复制控件 狼人:
    一起谈.NET技术,ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇] 狼人:
  • 原文地址:https://www.cnblogs.com/Wunsch/p/12283616.html
Copyright © 2011-2022 走看看