zoukankan      html  css  js  c++  java
  • drf 数据保存

    7.3.2.2 数据保存

    通过序列化器来完成数据的更新或者添加,把视图中对于模型中的操作代码移出视图中,放入到序列化器。

    前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.

    可以通过实现create()和update()两个方法来实现。

    from rest_framework import serializers
    
    # 可以把验证函数进行多次使用,提供不用的字段或者不同的序列化器里面使用
    def about_django(data):
        if "django" in data:
            raise serializers.ValidationError("对不起,图书标题不能出现关键字django")
        # 返回验证以后的数据
        return data
    
    class BookInfoSerializer(serializers.Serializer):
        # 这里声明的字段用于进行反序列化器
        # 字段名 = serializers.字段类型(验证选项)
        title = serializers.CharField(max_length=20,validators=[about_django], label="标题", help_text="标题")
        # required=True 当前字段必填
        pub_date = serializers.DateField(required=True, label="发布日期", help_text="发布日期")
        # max_length 文件的大小
        # allow_null=True 允许传递的image数据为None
        image = serializers.ImageField(required=False, allow_null=True, max_length=3*1024*1024, label="图书封面", help_text="图书封面")
        price = serializers.DecimalField(max_digits=8, decimal_places=2, required=True, label="价格", help_text="价格")
        # min_value 数值大小
        # default 设置默认值
        read  = serializers.IntegerField(min_value=0, default=0, label="阅读量", help_text="阅读量")
        comment = serializers.IntegerField(min_value=0, default=0, label="评论量", help_text="评论量")
    
        # 关于继承数据库选项
    
        # 自定义验证的代码
        # 单个字段的验证,方法名必须: validate_<字段名>(self,data)    # data 就是当前字段中客户端提交的数据
        # validate_price 会被is_valid调用
        def validate_price(self, data):
            """"""
            if data < 0:
                raise serializers.ValidationError("对不起,价格不能低于0元")
            # 验证通过以后,必须要返回验证的结果数据,否则序列化器的validated_data无法得到当前字段的结果
            return data
    
        # 多个字段的验证,必须方法名叫 "validate"
        # data 表示客户端发送过来的所有数据,字典格式
        def validate(self, data):
            # 判断图书的阅读量不能低于评论量
            read = data.get("read")
            comment = data.get("comment")
            if read < comment:
                raise serializers.ValidationError("对不起,阅读量不能低于评论量")
    
            return data
    
        # 数据库操作
        def create(self, validated_data): # 这里会在调用时,由序列化器补充验证成功以后的数据进来
            """完成添加操作"""
            print(validated_data) # 字典
            # 导入模型
            from .models import BookInfo
            # 添加数据
            book = BookInfo.objects.create(
                title=validated_data.get("title"),
                price=validated_data.get("price"),
                pub_date=validated_data.get("pub_date"),
                read=validated_data.get("read"),
                comment=validated_data.get("comment"),
            )
    
            return book
    
        # instance就是要修改的模型,系统会自动从对象初始化时的instance提取过来
        # validated_data 就是经过验证以后的客户端提交的数据
        def update(self, instance, validated_data):
            """更新操作"""
            instance.title = validated_data.get('title')
            instance.pub_date = validated_data.get('pub_date')
            instance.comment = validated_data.get('comment')
            instance.price = validated_data.get('price')
            instance.read = validated_data.get('read')
            instance.save()
    
            return instance
    
    

    视图代码:

    # Create your views here.
    from django.views import View
    from django.http.response import HttpResponse
    from .serializers import BookInfoSerializer
    class BookInfoView(View):
        # ...
        def get(self,request):
            """保存数据[更新]"""
            # 客户端提交数据过来
            id = 2
            data = { # 模拟客户端发送过来的数据
                "title": "东游记",
                "pub_date": "1998-10-01",
                "price": 19.98,
                "read": 330,
                "comment": 100,
            }
            from .models import BookInfo
            book = BookInfo.objects.get(pk=id)
    
            # 使用序列化器验证数据[如果是更新操作,需要传入2个参数,分别是instance和data]
            serializer = BookInfoSerializer(instance=book,data=data)
            serializer.is_valid()
            book = serializer.save() # 此时,我们必须在序列化器中预先声明update方法
            """
            serailzier对象调用的save方法是什么?怎么做到自动调用update和create?
            1. 这里的save不是数据库ORM模型对象的save,是BaseSerializer定义的。
            2. save方法中根据实例化serializer时是否传入instance参数来判断执行update还是create的
               当传入instance时,则instance.save调用的就是update方法
               没有传入instance,则instance.save调用的就是create方法
            3. serializer.save使用前提是必须在序列化器中声明create或者update方法,否则报错!!!
            """
            print(book)
            """打印结果:
            BookInfo object (2)
            """
            return HttpResponse("ok")
    

    在序列化器实现了create和update两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了

    book = serializer.save()
    

    如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

    serailzier对象调用的save方法是什么?怎么做到自动调用update和create?
    1. 这里的save不是数据库ORM模型对象的save,是BaseSerializer定义的。
    2. save方法中根据实例化serializer时是否传入instance参数来判断执行update还是create的
    当传入instance时,则instance.save调用的就是update方法
    没有传入instance,则instance.save调用的就是create方法
    3. serializer.save使用前提是必须在序列化器中声明create或者update方法,否则报错!!!
    

    BaseSerializer中定义的save方法源码:

    1582086563954

    7.3.2.3 附加参数说明

    1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

    # 可以传递任意参数到数据保存方法中
    # 例如:request.user 是django中记录当前登录用户的模型对象
    serializer.save(owner=request.user)
    

    2)默认序列化器必须传递所有必填字段[required=True],否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

    # Update `BookInfo` with partial data
    # partial=True 设置序列化器只是针对客户端提交的字段进行验证,没有提交的字段,即便有验证选项或方法也不进行验证。
    serializer = BookInfoSerializer(book, data=data, partial=True)
    

    7.3.3 模型类序列化器

    如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

    ModelSerializer与常规的Serializer相同,但提供了:

    • 基于模型类自动生成一系列序列化器字段
    • 基于模型类自动为Serializer生成validators,比如unique_together
    • 包含默认的create()和update()的实现

    7.3.3.1 定义

    比如我们创建一个BookInfoSerializer

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = '__all__'
    
    • model 指明参照哪个模型类
    • fields 指明为模型类的哪些字段生成

    我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现

    >>> from booktest.serializers import BookInfoSerializer
    >>> serializer = BookInfoSerializer()
    >>> serializer
    BookInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        title = CharField(label='名称', max_length=20)
        pub_date = DateField(allow_null=True, label='发布日期', required=False)
        read = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
        comment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
        image = ImageField(allow_null=True, label='图片', max_length=100, required=False)
    

    7.3.3.2 指定字段

    1. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date')
    
    1. 使用exclude可以明确排除掉哪些字段
    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            exclude = ['image',]
    
    1. 显示指明字段,如:
    class HeroInfoSerializer(serializers.ModelSerializer):
        book = BookInfoSerializer()
    
        class Meta:
            model = HeroInfo
            fields = ('id', 'name', 'sex', 'comment', 'book')
    
    1. 指明只读字段

    可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'title', 'pub_date', 'read', 'comment')
            read_only_fields = ('id', 'read', 'comment')
    

    7.3.3.3 添加额外参数

    我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'title', 'pub_date', 'read', 'comment')
            extra_kwargs = {
                'read': {'min_value': 0, 'required': True},
                'comment': {'min_value': 0, 'required': True},
            }
    
    # BookInfoSerializer():
    #    id = IntegerField(label='ID', read_only=True)
    #    title = CharField(label='名称', max_length=20)
    #    pub_date = DateField(allow_null=True, label='发布日期', required=False)
    #    read = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True)
    #    comment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
    

    作业

    在django项目中实现5个基本的图书信息的API接口,返回json格式数据提供给客户端。
      1. 使用基本序列化器 Serializer。
      2. 基于模型序列化器来实现5个api接口  ModelSerializer
      
    
    图书模型:
    
    class BookInfo(models.Model):
        """图书信息"""
        title = models.CharField(max_length=20, verbose_name='标题')
        pub_date = models.DateField(verbose_name='发布日期')
        image = models.ImageField(verbose_name='图书封面')
        price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="价格")
        read = models.IntegerField(verbose_name='阅读量')
        comment = models.IntegerField(verbose_name='评论量')
        class Meta:
            # db_table = "表名"
            db_table = "tb_book_info"
            verbose_name = "图书"
            verbose_name_plural = verbose_name
    
  • 相关阅读:
    视图
    使用navicat for sqlserver 把excel中的数据导入到sqlserver数据库
    sql去重
    SQLserver连接本地服务器
    html中去掉文本框(input type="text")的边框或只显示下边框
    用户控件与页面间相互给各自的控件赋值
    easyui datagrid 去掉 全选checkbox
    ZebraDatepicker中文显示
    实现在点击asp:button按钮后,不刷新当前页面
    (转)ASP.NET(C#)FileUpload实现上传限定类型和大小的文件到服务器
  • 原文地址:https://www.cnblogs.com/ch2020/p/14968636.html
Copyright © 2011-2022 走看看