这几天,在编码过程中,发现了几处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
网友评论