• 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('已有出价更高者,请调整出价')
            return value
    

    重构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
     
  • 相关阅读:
    Java中,由this关键字引发的问题
    Spring3.2.11与Quartz2.2.1整合时内存泄漏的问题的解决
    使用Nexus管理Maven仓库时,上传带依赖的第三方jar
    ActiveMQ5.10.2版本配置JMX
    JAVA的Hashtable在遍历时的迭代器线程问题
    关于JAVA中String类型的最大长度
    新增了某个模组后VS编译不过,报错说找不到头文件
    重写Overlap事件
    cmd端口占用查看和关闭端口
    转---详细的Android开发环境搭建教程
  • 原文地址:https://www.cnblogs.com/ngngng/p/13745826.html
Copyright © 2020-2023  润新知