编写后端api实际上就是解析前端请求request,处理数据,构造响应response返回前端的过程(推荐先读廖海峰python教程)。在环境搭建环节,我们已经建立好了一个后端工程的模板,根据对需求的分析,后端api应当设计成多个功能模块,每个功能模块的信息管理功能尽量独立,例如,人员信息管理模块负责管理人员相关信息、考核信息管理模块负责管理考核相关信息。完成模块分解后,具体到django工程上来就可以创建相应的app,可以在pycharm的“tools->run manage.py task”菜单栏打开manage.py终端,使用命令“startapp模块名称”即可在当前模板工程中创建新的模块,每个被创建的新模块会在工程根目录下以模块名称创建一个文件夹,里面包含如下文件:
mrations文件夹:存放自动生成的迁移脚本代码
__init__.py:模块初始化脚本,一般情况用不到
admin.py:使用django自带的管理后台时使用,对于rest api项目而言用不到
apps.py:模块自注册代码,也可以存放全局对象
models.py:将需要迁移到数据库中的表结构以类的方式写在此文件中
test.py:单元测试代码文件
views.py:视图文件,在rest api项目中作为书写接口的文件
该功能模块还需要在settings.py中进行挂接,代码如下所示:
INSTALLED_APPS = [
……
####自定义app
'StandardModule',
]
接下来就是要设计实现功能模块相关的数据表以及业务逻辑了,基于django提供的后端框架,配合django rest framework,能够很自然的为每一个后端模块设计为如下结构,该结构每一层次的具体实现,下面将分别进行说明。
1)实现数据层和序列化层
数据层用于实现从django.db.models.Model类继承过来的关系表类,如以下代码所示
from django.db import models
class Standard(models.Model):
item_id = models.IntegerField()
to_sexy = models.CharField(max_length=5,default='男')
to_age_min = models.IntegerField(default=18)
to_age_max = models.IntegerField(default=80)
pass_value_min = models.FloatField(default=0.0)
pass_value_max = models.FloatField(default=-1.0)
pass_score = models.IntegerField(default=100)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'standard' #####关系表名
ordering = ['-created_at',] ####返回数据集按照created_at逆序排列
从以上代码可看出,该类实际上就是将数据库关系表的另一种形式,所需的数据类型及参数可以参考django官方文档。将涉及一个功能模块相关的关系表全部以上类的方式写到models.py文件中,然后在manage.py终端中输入命令“makemigrations 模块名称”即可生成该将models.py中的类转变成关系表的迁移脚本,然后再使用“migrate 模块名称”即可在settings.py文件中连接的mysql数据库中生成关系表。在数据库中生成表之后,即可使用定义的关系表类来增、删、改、查数据,其中,查询数据是利用关系表类的一个聚合类Queryset来实现的,具体可查看django官方文档。
直接通过Model的子类操作数据是可以的,而且对于查询时是必须的,但对于有些场景,需要将查询到的数据进行形式转换或者延伸查询相关数据,以及在存储数据前需要检查数据的有效性等,这些代码如果分散在后端实现中可能造成维护困难和不一致,此时就需要使用序列化层来集中做这些事情。
序列化层是django
rest framework提供的统一处理数据读取表示和数据存入检验的机制,可以在功能模块根目录下建立serializers.py文件来编码序列化层,如下代码提供了一个序列化层的实例:
from rest_framework import serializers
from .models import Item, Standard
class StandardSerializer(serializers.ModelSerializer):
class Meta:
model = Standard
fields = ('id', 'item_id','to_sexy','to_age_min', 'to_age_max', 'pass_value_min', 'pass_value_max', 'pass_score')
####数据有效性检测
def validate(self, attrs):
if attrs.__contains__('to_sexy'):
if attrs['to_sexy']not in ['男', '女']:
raise serializers.ValidationError('适用性别取值不正确')
if attrs.__contains__('to_age_min')and attrs.__contains__('to_age_max'):
if attrs['to_age_min']> attrs['to_age_max']:
raise serializers.ValidationError('年龄范围取值不正确')
if attrs.__contains__('item_id'):
try:
Item.objects.get(id=attrs['item_id'])
except Item.DoesNotExist:
raise serializers.ValidationError('考核项目不存在')
return attrs
####数据显示
def to_representation(self,instance):
ret = super().to_representation(instance)
item = Item.objects.get(id=ret['item_id'])
ret['item_name'] = item.name
ret['pass_value_min_label']= getValueLabel(ret['pass_value_min'], item.unit)
if ret['pass_value_max']== -1:
ret['pass_value_max_label']= '无上限'
else:
ret['pass_value_max_label']= getValueLabel(ret['pass_value_max'], item.unit)
ret['score_count'] = Score.objects.filter(standard_id=ret['id']).count()
return ret
####数据存储
def to_internal_value(self,data):
data = data.copy()
if data.__contains__('pass_value_min_label')and data.__contains__('item_id'):
item = Item.objects.get(id=data['item_id'])
value = getValueFromLabel(data['pass_value_min_label'],item.unit)
if value > 0:
data['pass_value_min']= value
if data.__contains__('pass_value_max_label')and data.__contains__('item_id'):
if data['pass_value_max_label']!= '无上限':
item = Item.objects.get(id=data['item_id'])
value = getValueFromLabel(data['pass_value_max_label'],item.unit)
if value > 0:
data['pass_value_max']= value
return super().to_internal_value(data)
从上面代码实例可以看出,序列化类要通常由4部分组成:
a)class Meta部分,设置序列化类对应的Model子类和向序列化暴露的数据项fields;
b)重载validate方法,用于检验序列化参数的正确性,在调用serializer的is_valid方法时被调用,is_valid方法通常用于保存数据到数据库前判断数据是否有效,本实例中判定了年龄范围的上下界是否有效(下界不能大于上界)等;
c)重载to_representation方法,用于将查询到的关系表数据转换为所需的形式,这在使用数据字典、显示数据格式化和关联其它数据时非常有用,本实例中关联查询了item_name等信息;
d)重载to_internal_value方法,用于将序列化参数转换成关系表中的数据形式,这在使用数据字典和显示数据格式化时非常有用,本实例将序列化参数中的字符串类型value_label转换成了数值类型value存储到关系表中。
实现了数据层和序列化层之后,数据管理就十分方便了,往数据库中新增一条记录的代码示例如下:
ser = StandardSerializer(data=data) ####这里的data包含了想要存储的各个数据项
if ser.is_valid(): ####会自动调用validate方法
ser.save()
批量增加记录的代码示例如下:
ser = PersonSerializer(data=persons, many=True) ####初始化为listserializer
if ser.is_valid():
ser.save()
查询并转化为待处理数据的代码示例如下:
rows = Standard.objects.all() ####返回所有数据
standards = StandardSerializer(rows, many=True)
do_something(standards.data) #### standards.data是一个包含待处理数据的列表