Metis

django rest framework序列化的细节

2020-12-17  本文已影响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
上一篇 下一篇

猜你喜欢

热点阅读