zoukankan      html  css  js  c++  java
  • ModelSerializer 字段验证以及序列化

    def validate_字段名(self, value),单一字段校验

    from rest_framework import serializers
    from rest_framework import exceptions
    from .. import models
    
    class BidModelSerializer(serializers.ModelSerializer):
        username = serializers.CharField(source='user.nickname', read_only=True)
        status_text = serializers.CharField(source='get_status_display', read_only=True)
    
        class Meta:
            model = models.BidRecord
            exclude = ['user', 'status', ]
    
        def validate_item(self, value):
            """ 验证是否还正在拍卖"""
            item_id = self.initial_data.get('item')
            exists = models.AuctionItem.objects.filter(id=item_id, status=3).exists()
            if not exists:
                raise exceptions.ValidationError('拍卖商品不存在或已成交')
            return value
    
        def validate_price(self, value):
            """ 验证价格
            1. 比最大的要大
            2. 是单元的倍数
            """
            from django.db.models import Max
            item_id = self.initial_data.get('item')
            item_object = models.AuctionItem.objects.filter(id=item_id).first()
            if value < item_object.start_price:
                raise exceptions.ValidationError('出价不能低于低价')
            result = models.BidRecord.objects.filter(item_id=item_id).aggregate(max_price=Max('price'))
            if not result['max_price']:
                return value
            if value <= result['max_price']:
                raise exceptions.ValidationError('已有出价更高者,请调整出价')
    

      

    重构create方法

    '''
    这里应用了Serializer与ModelSerializer的结合使用
    
    '''
    class CreateNewsTopicModelSerializer(serializers.Serializer):
        key = serializers.CharField()
        cos_path = serializers.CharField()
    
    
    class CreateNewsModelSerializer(serializers.ModelSerializer):
        imageList = CreateNewsTopicModelSerializer(many=True)
    
        class Meta:
            model = models.News
            exclude = ['user', 'viewer_count', 'comment_count']
    
        def create(self, validated_data):
            image_list = validated_data.pop('imageList')
            news_object = models.News.objects.create(**validated_data)
            data_list = models.NewsDetail.objects.bulk_create(
                [models.NewsDetail(**info, news=news_object) for info in image_list]
            )
            news_object.imageList = data_list
            if news_object.topic:
                models.Topic.objects.filter(id=news_object.topic_id).update(count=F('count') + 1)
            return news_object

     

    自定义字段,获取一张表的全部内容

    '''
    此处涉及到两个ModelSerializer类
    
    # 保证金
    deposit = serializers.SerializerMethodField()
    
    def get_deposit(self, obj):
        return PayDepositModelSerializer(instance=obj.deposit).data
    
    '''
            
    class PayDepositModelSerializer(serializers.ModelSerializer):
    
        # 支付保证金
        deposit_text = serializers.CharField(source='get_deposit_type_display')
        checked = serializers.BooleanField(default=False)
    
        class Meta:
            model = models.Collateral
            fields = ['id', 'deposit_type', 'deposit_text', 'amount', 'balance', 'checked']
    
    
    class PayModelSerializer(serializers.ModelSerializer):
    
        user_balance = serializers.IntegerField(source='user.balance')
    
        auction = serializers.CharField(source='lot.special_auction_id')
    
        # 拍品
        lot = serializers.SerializerMethodField()
    
        # 保证金
        deposit = serializers.SerializerMethodField()
    
        # 是否有优惠券
        coupon = serializers.SerializerMethodField()
    
        # 支付方式
        pay_method = serializers.SerializerMethodField()
    
        class Meta:
            model = models.Order
            exclude = ['uid', 'twenty_four_task_id', 'user']
    
        def get_deposit(self, obj):
            return Pay DepositModelSerializer(instance=obj.deposit).data
    
        def get_coupon(self, obj):
            user_object = self.context['request'].user
            exists = models.UserCoupon.objects.filter(
                user=user_object, status=1, coupon__auction=obj.lot.special_auction_id).exists()
    
            context = {
                'id': None,
                'has': exists,
                'text': '请选择优惠券' if exists else '无',
                'money': 0
            }
            return context
    
        def get_pay_method(self, obj):
            balance = self.context['request'].user.balance
            info = {
                'selected': 1,
                'choices': [
                    {'id': 1, 'text': '余额(%s)' % balance},
                    {'id': 2, 'text': '微信支付'},
                ]
            }
            return info
    
        def get_lot(self, obj):
            return {
                'title': obj.lot.name,
                'cover': obj.lot.cover.name,
                'uid': obj.lot.catalog_num
            }
    

      

    ModelSerializer序列化与反序列化(重点)

    视图类

    class UserV3APIView(APIView):
        # 单查群查
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
                if not user_obj:
                    return Response({
                        'status': 1,
                        'msg': 'pk error',
                    }, status=400)
    
                user_ser = serializers.UserModelSerializer(user_obj, many=False)
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': user_ser.data
                })
            else:
                user_query = models.User.objects.filter(is_delete=False).all()
    
                user_ser = serializers.UserModelSerializer(user_query, many=True)
    
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': user_ser.data
                })
    
        # 单增
        def post(self, request, *args, **kwargs):
            user_ser = serializers.UserModelSerializer(data=request.data)
            if user_ser.is_valid():
                # 入库
                user_obj = user_ser.save()
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': serializers.UserModelSerializer(user_obj).data
                })
            else:
                return Response({
                    'status': 1,
                    'msg': user_ser.errors,
                })
    

      

    序列化类

    """ ModelSerializer类序列化与反序列化总结
    1)序列化类继承ModelSerializer,所以需要在配置类Meta中进行配置
    2)model配置:绑定序列化相关的Model表
    3)fields配置:采用 插拔式 设置所有参与序列化与反序列化字段
    4)extra_kwargs配置:
        划分系统字段为三种:只读(read_only)、只写(write_only)、可读可写(不设置)
        字段是否必须:required
        选填字段:在extra_kwargs进行配置,但不设置required,且有默认值
    5)自定义序列化字段:
        第一种(不提倡):在序列化类中用SerializerMethodField()来实现
        第二种(提倡):在模型类中用@property来实现,可插拔
    6)自定义反序列化字段:
        同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效
        自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
    7)局部钩子,全局钩子同Serializer类
    8)不需要重写create和update方法
    """
    class UserModelSerializer(serializers.ModelSerializer):
        # 第一种自定义序列化字段:该字段必须在fields中设置
        # gender = serializers.SerializerMethodField()
        # def get_gender(self, obj):
        #     return obj.get_sex_display()
    
    
        # 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,
        #       在extra_kwargs中对其设置的无效
        # 注:自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
        re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)
    
        class Meta:
            model = models.User
            # fields采用 插拔式 设置所有参与序列化与反序列化字段
            fields = ('username', 'gender', 'icon', 'password', 'sex', 're_password')
            extra_kwargs = {
                'username': {  # 系统字段不设置read_only和write_only,默认都参加
                    'min_length': 3,
                    'max_length': 10,
                    'error_messages': {
                        'min_length': '太短',
                        'max_length': '太长'
                    }
                },
                'gender': {
                    'read_only': True,  # 自定义的序列化字段默认就是read_only,且不能修改,可以省略
                },
                'password': {
                    'write_only': True,
                },
                'sex': {  # 像sex有默认值的字段,为选填字段('required': True可以将其变为必填字段)
                    'write_only': True,
                    # 'required': True
                }
            }
    
    
        # 局部全局钩子同Serializer类,是与 Meta 同缩进的
        def validate_username(self, value):
            if 'g' in value.lower():
                raise serializers.ValidationError('名字中不能有g')
            return value
    
        def validate(self, attrs):
            password = attrs.get('password')
            re_password = attrs.pop('re_password')
            if password != re_password:
                raise serializers.ValidationError({'re_password': '两次密码不一致'})
            return attrs
    
        # create和update方法不需要再重写,ModelSerializer类已提供,且支持所有关系下的连表操作
    

      

    模型类

    from django.db import models
    
    class User(models.Model):
        SEX_CHOICES = (
            (0, '女'),
            (1, '男'),
        )
    
        username = models.CharField(max_length=64, verbose_name='用户名', blank=True, unique=True)
        password = models.CharField(max_length=64, verbose_name='密码')
        sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='性别')
        img = models.ImageField(upload_to='img', default='img/default.png', verbose_name='头像')
        # 开发中,数据不会直接删除,通过字段控制
        is_delete = models.BooleanField(default=False, verbose_name='是否注销')
        # 数据库数据入库,一般都会记录该数据第一次入库时间,有时候还会记录最后一次更新时间
        created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
        # 第二种自定义序列化字段(插拔式,提倡使用)
        @property
        def gender(self):
            return self.get_sex_display()
    
        @property
        def icon(self):
            from django.conf import settings
            return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, self.img)
    
    
        class Meta:  # 配置类,给所属类提供配置信息
            db_table = 'old_boy_user'
            verbose_name_plural = '用户表'
    
        def __str__(self):  # 不要在这里进行连表操作,比如admin页面可能会崩溃
            return self.username
    

      

     

  • 相关阅读:
    Python 类中方法的内部变量,命名加'self.'变成 self.xxx 和不加直接 xxx 的区别
    用foreach遍历 datagridView 指定列所有的内容
    treeView1.SelectedNode.Level
    YES NO 上一个 下一个
    正则 单词全字匹配查找 reg 边界查找 精确匹配 只匹配字符 不含连续的字符
    抓取2个字符串中间的字符串
    sqlite 60000行 插入到数据库只用不到2秒
    将多行文本以单行的格式保存起来 读和写 ini
    将秒转换成时间格式
    richtextbox Ctrl+V只粘贴纯文本格式
  • 原文地址:https://www.cnblogs.com/zhangzetao/p/13746432.html
Copyright © 2011-2022 走看看