美文网首页Metis
django rest framework序列化的细节

django rest framework序列化的细节

作者: 万州客 | 来源:发表于2020-12-17 22:28 被阅读0次

    这几天,在编码过程中,发现了几处DRF序列化的细节之处,作一记录。

    一,样例Model

    老样的时序异常检测的Attr指标,外键接ViewSet指标集和训练的模型文件。

    from django.db import models
    from django.contrib.auth import get_user_model
    from .view_set_models import ViewSet
    from .task_models import Task
    
    User = get_user_model()
    
    
    # 指标
    class Attr(models.Model):
        attr_id = models.CharField(max_length=64,
                                   unique=True,
                                   verbose_name='指标id')
        attr_name = models.CharField(max_length=64,
                                     unique=True,
                                     verbose_name='指标名称')
        view_set = models.ForeignKey(ViewSet,
                                     null=True,
                                     blank=True,
                                     related_name='ra_attr',
                                     on_delete=models.DO_NOTHING,
                                     verbose_name='指标集')
        description = models.CharField(max_length=1024,
                                       null=True,
                                       blank=True,
                                       verbose_name='指标描述')
        model = models.ForeignKey(Task,
                                  null=True,
                                  blank=True,
                                  related_name='ra_attr',
                                  on_delete=models.DO_NOTHING,
                                  verbose_name='关联模型')
        security_token = models.CharField(max_length=64,
                                          null=True,
                                          blank=True,
                                          verbose_name='连接token')
        check_security = models.BooleanField(default=False,
                                             verbose_name='启用token保护')
        url = models.CharField(max_length=1024,
                               null=True,
                               blank=True,
                               verbose_name='监控url')
        create_user = models.ForeignKey(User,
                                        null=True,
                                        blank=True,
                                        related_name='ra_attr',
                                        on_delete=models.DO_NOTHING,
                                        verbose_name='创建者')
        create_date = models.DateTimeField(auto_now_add=True, verbose_name='新建时间')
        update_date = models.DateTimeField(auto_now=True, verbose_name='更新时间')
        status = models.BooleanField(default=True, verbose_name='状态')
    
        @property
        def username(self):
            return self.create_user.username
    
        @property
        def view_set_name(self):
            return self.view_set.view_set_name
    
        # 特别注意,此处的model_name的名称,不能和字段定义中的model名称相同。如果相同,则同名字段不能合进数据库。
        @property
        def model_name(self):
            return self.model.model_name
    
        def __str__(self):
            return self.attr_name
    
        class Meta:
            db_table = 'Attr'
            ordering = ('-update_date',)
    
    

    二,序列化时,我们可以依据新建和更新的不同,建立不同的序列化类

    from rest_framework import serializers
    from MetisModels.attr_models import Attr
    
    # 依据不同的功能,建立不同的序列化类。新建指标和更新指标时,字段不同,就可以分列出来
    class AttrCreateSerializer(serializers.ModelSerializer):
        class Meta:
            model = Attr
            # fields = '__all__'
            fields = ['attr_id', 'attr_name', 'description', 'view_set', 'model',
                      'security_token', 'check_security', 'url',
                      'create_user']
    
    
    class AttrUpdateSerializer(serializers.ModelSerializer):
        class Meta:
            model = Attr
            # fields = '__all__'
            fields = ['attr_id', 'attr_name', 'description', 'view_set_id', 'model_id',
                      'security_token', 'check_security', 'url']
    

    在新建时,序列化时是指定 'view_set', 'model',而更新时,是指定的'view_set_id', 'model_id'。

    三,在实现新建和更新指标时,绑定不同的序列化类

    class AttrCreateView(CreateAPIView):
        serializer_class = AttrCreateSerializer
    
        def post(self, request):
            req_data = request.data
            print(req_data)
            data = dict()
            data['attr_id'] = req_data['attrId']
            data['attr_name'] = req_data['attrName']
            data['description'] = req_data['description']
            data['view_set'] = req_data['viewSetId']
            data['model'] = req_data['modelId']
            data['security_token'] = req_data['securityToken']
            data['check_security'] = req_data['checkSecurity']
            data['url'] = req_data['url']
            # 从drf的request中获取用户(对django的request作了扩展的)
            data['create_user'] = request.user.id
            serializer = AttrCreateSerializer(data=data)
            if serializer.is_valid() is False:
                return_dict = build_ret_data(THROW_EXP, str(serializer.errors))
                return render_json(return_dict)
            data = serializer.validated_data
            try:
                Attr.objects.create(**data)
                return_dict = build_ret_data(OP_SUCCESS, serializer.data)
                return render_json(return_dict)
            except Exception as e:
                print(e)
                return_dict = build_ret_data(THROW_EXP, str(e))
                return render_json(return_dict)
    
    
    class AttrUpdateView(UpdateAPIView):
        """
            url获取pk,修改时指定序列化类和query_set
        """
        model = Attr
        serializer_class = AttrUpdateSerializer
        queryset = model.objects.all()
    
        # 前端使用patch方法,到达这里
        def patch(self, request, *args, **kwargs):
            req_data = request.data
            print(req_data, "####")
            aid = req_data['id']
            attr_id = req_data['attrId']
            attr_name = req_data['attrName']
            description = req_data['description']
            view_set_id = req_data['viewSetId']
            view_set = ViewSet.objects.get(id=view_set_id)
            model_id = req_data['modelId']
            model = Task.objects.get(id=model_id)
            security_token = req_data['securityToken']
            check_security = req_data['checkSecurity']
            url = req_data['url']
            # 这样更新,可以把那些update_date字段自动更新,而使用filter().update()则是不会
            try:
                _a = Attr.objects.get(id=aid)
                _a.attr_id = attr_id
                _a.attr_name = attr_name
                _a.description = description
                _a.model = model
                _a.view_set = view_set
                _a.security_token = security_token
                _a.check_security = check_security
                _a.url = url
                _a.save()
                return_dict = build_ret_data(OP_SUCCESS, str(req_data))
                return render_json(return_dict)
            except Exception as e:
                print(e)
                return_dict = build_ret_data(THROW_EXP, str(e))
                return render_json(return_dict)
    
    

    在新建时,序列化时是指定 'view_set', 'model',调用AttrCreateSerializer()成功后,直接更新id外键,就可以新建一个指标了。

    而更新时,是指定的'view_set_id', 'model_id',获取后id后,还需要调用ViewSet.objects.get(),得到实例,再用来更新相关字段。

    这两种方式,可灵活运用,手工程序高,细节处才可把握好。

    四,前端送来的数据样例

    新建时

    {
        'attrId': '1653456', 
        'attrName': '测试指标',
        'description': '用于简书示例',
        'viewSetId': 1,
        'modelId': 1, 
        'securityToken': '87Mk5vNX3nAJS3BD',
        'checkSecurity': True, 
        'url': 'http://demo.prometheus.com/js/'
    }
    

    更新时

    {
        'id': 13,
        'attrId': '1653456', 
        'attrName': '测试指标',
        'description': '用于简书示例',
        'viewSetId': 5,
        'modelId': 2, 
        'securityToken': 'QrDLTkX7fQwr3VwPZy',
        'checkSecurity': False,
        'url': 'http://demo.prometheus.com/js2nd/'
    }
    

    五,前端axios请求示例

    /**
     * 新建指标
     */
    export async function createAttr(data) {
        console.log(data)
        const attrId = data['attrId']
        const attrName = data['attrName']
        const description = data['description']
        const viewSetId = data['viewSetId']
        const modelId = data['modelId']
        const securityToken = data['securityToken']
        const checkSecurity = data['checkSecurity']
        const url = data['url']
      return request(ATTR_CREATE, METHOD.POST, {
        attrId,
        attrName,
        description,
            viewSetId,
            modelId,
            securityToken,
            checkSecurity,
            url
      })
    }
    
    /**
     * 获取所有指标
     */
    export async function getAttrList(data) {
        const pageSize = data['pageSize']
        const currentPage = data['currentPage']
        const ordering = data['ordering']
        const attrId = data['searchKey']['attrId']
        const attrName = data['searchKey']['attrName']
        const viewSetId = data['searchKey']['viewSetId']
      return request(ATTR_LIST, METHOD.GET, {
            pageSize,
            currentPage,
            ordering, 
            'attr_id': attrId,
            'attr_name': attrName,
            'view_set_id': viewSetId
        })
    }
    
    /**
     * 编辑指标
     */
    export async function updateAttr(data) {
        console.log(data)
        const id = data.id
        const attrId = data['attrId']
        const attrName = data['attrName']
        const description = data['description']
        const viewSetId = data['viewSetId']
        const modelId = data['modelId']
        const securityToken = data['securityToken']
        const checkSecurity = data['checkSecurity']
        const url = data['url']
        // 传给DjangoRestFramework的edit的URL需要带pk(id)参数,在这里组合一下
        const ATTR_UPDATE_PATH = ATTR_UPDATE + id + '/'
      return request(ATTR_UPDATE_PATH, METHOD.PATCH, {
              id,
                attrId,
                attrName,
                description,
                viewSetId,
                modelId,
                securityToken,
                checkSecurity,
                url
        })
    }
    

    感觉大多数字段都相同,还可以精简合并,但,不是说过早优化不好么?
    一个一个功能分开来,感觉维护性会更好点。
    六,欣赏进度


    2020-12-17 22_24_45-.png 2020-12-17 22_20_34-.png

    相关文章

      网友评论

        本文标题:django rest framework序列化的细节

        本文链接:https://www.haomeiwen.com/subject/qestnktx.html