前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >day91-day92-DjangoRestFrameWork序列化&反序列化的使用

day91-day92-DjangoRestFrameWork序列化&反序列化的使用

原创
作者头像
少年包青菜
修改2020-10-29 11:13:46
9620
修改2020-10-29 11:13:46
举报
文章被收录于专栏:Python 学习Python 学习

1.安装DjangoRestFrameWork

pip install...

2.settings 里面注册APP

3.settings最下面添加,具体看实际报错是否需要添加,可百度

代码语言:javascript
复制
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": []
}

4.DjangoRestFrameWork使用

1.在APP下面新建一个serializers.py的文件

2.第一版(初始版)

2.1 models.py的代码如下(对比参考)

代码语言:javascript
复制
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=32)
    CHOICES = ((1, 'Python'), (2, 'Linux'), (3, 'GoLang'))
    category = models.IntegerField(choices=CHOICES)
    pub_time = models.DateField()
    publisher = models.ForeignKey(to='Publisher', on_delete=models.DO_NOTHING, null=True)  # 书籍外键指向出版社
    authors = models.ManyToManyField(to='Author') # 书籍多对多指向作者 
    
class Publisher(models.Model):
    publisher_name = models.CharField(max_length=32)

class Author(models.Model):
    author_name = models.CharField(max_length=32)

2.2 serializers.py的代码如下

2.2.1 from rest_framework import serializers

2.2.2 继承 serializers.Serializer

2.2.3 序列化类的字段名和models的字段名必须一样,只是models.xxx变成了serializers.xxx,

可以定义 error_messages 或者 required,跟form表单类似

2.2.4 注意models里面的CHOICE字段这里变成CharField,指定source参数,参数跟随的是ORM的操作,

这里主要注意 "get_CHOICE字段名_display" 方法的使用

2.2.5 主外键关系:主表字段名 = 外键类(),多对多关系时注意指定many=True参数

2.2.6 -- required=False 只序列化不走校验 -- read_only=True 只序列化用 -- write_only=True 只反序列化用

2.2.7 可以自定义字段名,自定义字段一般只用于反序列化

2.2.8 创建数据要重写 create() 方法,更新数据要重写 update() 方法,函数里面是ORM的操作

2.2.9 -- 可自定义校验函数 my_validate(),权重最高,第一个校验,校验函数可以是多个,

在序列化字段里面注意指定 validators=[my_validate, ],将校验函数添加进参数列表

-- 对单个序列化字段的校验函数,权重第二,第二个校验,validate_字段名()

-- 对反序列化的字段进行联合校验,权重第三,第三个校验 ,validate()

代码语言:javascript
复制
from rest_framework import serializers
from DjangoDemo import models
from rest_framework.exceptions import ValidationError


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    publisher_name = serializers.CharField(max_length=32)

class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)


# 定义自己的字段反序列化校验器
# 校验顺序第一
def my_validate(value):
    if 'python' in value.lower():
        return raise ValidationError({'title': '标题含有敏感字'})
    return value

# Book 主类
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate, ])  # 指定校验器
    "不再是InterField,CHOICE 改成 CharFiled,指定 source 跟随 ORM 操作"
    "get_字段_display,直接获得 choice 后面的值"
    category = serializers.CharField(
        source='get_category_display', 
        read_only=True, 
        error_messages={'required': '分类不能为空'}
    )

    "定义新的反序列化字段为了跟 category 区分开来,write_only"
    post_category_id = serializers.IntegerField(write_only=True)
    pub_time = serializers.DateField(
        error_messages={'required': '出版时间不能为空', 'invalid': '时间格式错误'}
    )

    "外键"
    "对该出版社和作者只行进get只读的序列化"
    publisher = PublisherSerializer(read_only=True)
    "外键,书籍和作者之间多对多"
    authors = AuthorSerializer(many=True, read_only=True)

    "定义id只写入,反序列化字段必须和传输字段一样!"
    publisher_id = serializers.IntegerField(write_only=True)
    author_list = serializers.ListField(write_only=True)

    ############################################################################

    # 创建数据需要重新写create方法
    def create(self, validated_data):
        "validated_data就是校验之后的数据"
        "准备对校验过的数据进行ORM的操作"
        created_book_obj = models.Book.objects.create(
            title=validated_data['title'],
            pub_time=validated_data['pub_time'],
            category=validated_data['post_category_id'],
            publisher_id=validated_data['publisher_id']
        )
        created_book_obj.authors.add(*validated_data['author_list'])

        "return 完才算真正创建完这个对象"
        return created_book_obj

    # 更新数据需要重写update方法
    def update(self, instance, validated_data):
        "validated_data就是校验之后的数据"
        instance.title = validated_data.get('title', instance.title)
        instance.pub_time = validated_data.get('pub_time', instance.pub_time)
        instance.category = validated_data.get('post_category_id', instance.category)
        instance.publisher_id = validated_data.get('publisher_id', instance.publisher_id)
        if validated_data.get('author_list'):
            instance.authors.set(validated_data.get('author_list'))
        instance.save()

        return instance
        
    #############################################################################

    # 固定用法,validate_XXX,代表对该字段进行校验
    # 校验顺序第二
    @staticmethod
    def validate_title(value):
        if 'python' in value.lower():
            raise ValidationError({'title': '包含敏感关键字'})
        return value

    # 使用该方法对反序列化的字段进行联合校验
    # attrs代表的是传过来的所有的字段
    # 校验顺序第三
    def validate(self, attrs):
        author_list = attrs.get('author_list')
        if 校验 author_list 失败:
            raise ValidationError({'authors': '作者不存在'})
        return attrs

3.第二版(最终版)

3.1 继承 serializers.ModelSerializer

3.2 自定义字段 + serializers.SerializerMethodField() 方法字段的使用,一般自定义参数展示指定 read_only=True

3.3 get_XXX 自定义字段名称,该函数的返回值会返回给该自定义字段

3.4 obj 就是序列化的每一个表类对象

3.5 注意 class Meta 里面的参数设置 model ,fields,exclude,extra_kwargs

3.6 这里同样可以写单个字段的校验和联合校验,validate_字段名(),校验单个字段,validate(),对反序列化的字段

进行联合校验,同样单个字段校验权重最高,联合校验权重最低

3.7 批量更新的时候在 class Meta 中定义list_serializer_class

代码语言:javascript
复制
class BookSerializer(serializers.ModelSerializer):
    # 指定的方法字段,可以对字段进行自定义重写
    category_info = serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors_info = serializers.SerializerMethodField(read_only=True)

    # obj 就是序列化的每一个Book对象
    # get_XXX 自定义字段名称,该函数的返回值会返回给该自定义字段
    @staticmethod
    def get_category_info(obj):
        return obj.get_category_display()

    @staticmethod
    def get_publisher_info(obj):
        publisher_obj = obj.publisher
        return {'id': publisher_obj.id, 'publisher_name': publisher_obj.publisher_name}

    @staticmethod
    def get_authors_info(obj):
        # 拿到所有的作者对象,列表推导式
        authors_queryset = obj.authors.all()
        return [{'id': author.id, 'author\'s name': author.name} for author in authors_queryset]
    
    # 校验 title 字段
    @staticmethod
    def validate_title(value):
        if 'python' in value.lower():
            raise ValidationError({'title': '包含敏感关键字'})
        return value

    # 使用该方法对反序列化的字段进行联合校验
    def validate(self, attrs):
        author_list = attrs.get('author_list')
        if 校验 author_list 失败:
            raise ValidationError({'authors': '作者不存在'})
        return attrs

    class Meta:
        # 用于更新多条数据
        class MultiUpdateSerializer(serializers.ListSerializer):
            def update(self, instance, validated_data):
                # 这里的instance代表的是对象模型列表, validated_data 是数据列表
                # child 代表每一个更新对象
                # child 调用的 update 是每一个 BookSerializer 的对象
                return [self.child.update(instance[i], validated_data[i]) for i in range(len(validated_data))]

        # 当存在多条更新的时候
        list_serializer_class = MultiUpdateSerializer
        model = models.Book
        # 这里代表的是默认拿到这张表的所有的字段
        fields = '__all__'

        # exclude=['id']

        # 将该字段设置为只写,将不会给前端传递该字段的参数
        extra_kwargs = {
            'title': {
                'write_only': True,
                'min_length': 2,
                'error_messages': {
                    'min_length': '标题最小长度不能低于2',
                }
            },

            'publisher': {
                'write_only': True,
                'required': True,
                'error_messages': {
                    'required': '出版社id不能为空',
                    'incorrect_type': '错误的出版社格式'  # 外键类型
                    'does_not_exist': '不存在的出版社'
                }
            },

            'pub_time': {'error_messages': {
                'invalid': '参数类型不合法'
            }},

            'authors': {
                'write_only': True,
                'error_messages': {
                    'required': '作者字段不能为空',
                    'not_a_list': '不合法的作者序列',  # 列表类型
                    'does_not_exist': '不存在的作者',
                }
            },

            'category': {
                'write_only': True,

            },
        }

4.视图中

4.0 from rest_framework.views import APIView, Response

4.1 from SerDemo.serializers import BookSerializer,导入自己写的序列化器

4.2 这里的类继承的 APIView,不是 View

4.3 这里返回的是 Response,不是HTTPResponse

4.4 知道接口传递过来的参数在 request.data 里面

4.5 get 请求直接传 queryset,post 请求是 data=XXX

4.6 无论是 queryset 还是单个 obj,或者是 接口的 request.data,都要入参给 XxxSerializers

4.7 在传 queryset 的时候,注意指定 many=True 参数

4.8 注意 save

4.9 成功返回 ser_obj.data

代码语言:javascript
复制
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializers import BookSerializer
from . import models
from rest_framework.request import Request

class TestView(APIView):
    @classmethod
    def get(cls, request: Request):
        """查询"""
        book_queryset = models.Book.objects.all()
        ser_obj = BookSerializer(book_queryset, many=True)
        return Response(ser_obj.data)

    @classmethod
    def post(cls, request: Request):
        """新增"""
        book_obj = request.data
        ser_obj = BookSerializer(data=book_obj, many=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)

    @classmethod
    def put(cls, request: Request):
        """修改"""
        """注释部分是单条修改"""
        # book_obj = models.Book.objects.filter(id=request.data.get('id')).first()
        # ser_obj = BookSerializer(instance=book_obj, data=request.data)
        # print('是否校验通过-->', ser_obj.is_valid())
        # if ser_obj.is_valid():
        #     ser_obj.save()
        #     return Response(ser_obj.data)
        # return Response(ser_obj.errors)

        update_list = request.data
        book_model_list = [
            models.Book.objects.filter(id=item['id']).first() for item in update_list
        ]
        ser_obj = BookSerializer(instance=book_model_list, data=request.data, many=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)

    @classmethod
    def delete(cls, request: Request):
        """删除"""
        id_list = request.data.get('id_list')
        delete_queryset = models.Book.objects.filter(id__in=id_list)
        if delete_queryset.count() != len(id_list):
            return Response('不存在的id')
        delete_queryset.delete()
        return Response('操作成功')

代码语言:javascript
复制
 # 数据结构 post 或者 delete,post 不用传 id
 [
    {
        "id":35,
        "title": "日bbbb",
        "category": 1,
        "pub_time": "2020-02-29",
        "publisher": 2,
        "authors": [1,2]
    }
]

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.安装DjangoRestFrameWork
  • 2.settings 里面注册APP
  • 3.settings最下面添加,具体看实际报错是否需要添加,可百度
  • 4.DjangoRestFrameWork使用
    • 1.在APP下面新建一个serializers.py的文件
      • 2.第一版(初始版)
        • 2.1 models.py的代码如下(对比参考)
        • 2.2 serializers.py的代码如下
      • 3.第二版(最终版)
        • 4.视图中
    相关产品与服务
    文件存储
    文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档