代码极思精致的瞬间(其一)
一,类型检查 与 request.data 配合使用!
Draft4Validator 定义了什么样的类型对应什么样的字段!比如 "type" "properties"(字典) "required"列表,只要是 post put 请求都加上

#from jsonschema import validate def json_schema_validate(schema): def valieated_func(func): def _func(self, request, *args, **kwargs): try: validate(request.data, schema) except ValidationError as e: raise_from(InvalidJsonException, e) else: return func(self, request, *args, **kwargs) return _func return valieated_func @json_schema_validate({ 'type': 'object', 'properties': { 'user': { 'type': 'string', 'minLength': 1 }, 'pass': { 'type': 'string', 'minLength': 1 }, }, }) def post(self, request): # 前端传参!{"pass": "admin","user": "admin"} pass
二,项目运行流程:
1,数据的收集 是采用 slurm 运行结果存储到 文件之中 然后读取文件(多线程)
2,首先数据是存取到 influxdb 之中的。
3,使用 selery 定时任务, 从influx 往postgres 存取数据
4,api 数据是 大部分来自于 influx , 查询的是 最新的数据
5,由于大量的查询是来自于 influx 所以采用 django自带的缓存 来缓存查询!
三 ,NodeHistoryBaseView 的封装!
1,所有的都是根据 pk 值 进行查询的 查询某一个 id的 cpu 历史 gpu 历史 network历史等等!
2,所有的子类 继承 NodeHistoryBaseView必须 重写 get_db_table(因为父类制定了是抽象方法,子类不能实例化此方法)
3, 父类是抽象类

@add_metaclass(ABCMeta) class NodeHistoryBaseView(APIView): TENDENCY_INTERVAL_TIME = { 'hour': '30s', 'day': '12m', 'week': '1h24m', 'month': '6h12m' } def get(self, request, pk, category): hostname = Node.objects.get(id=pk).hostname sql_history = self.get_history_sql(request, category, hostname) logger.info("sql: %s" % (sql_history,)) try: history = cache.get(sql_history, epoch='s') except InfluxDBServerError or InfluxDBClientError: raise InfluxDBException history = self.handle_query_data(history) sql_current = self.get_current_sql(category, hostname) logger.info("sql: %s" % (sql_current,)) current = self.get_current_data(sql_current) return self.return_success(history, current) @abstractmethod #父类制定了是抽象方法,子类不能实例化此方法 def get_db_table(self): pass @property def get_scale_data(self): ''' sql: select [sql value] ** handle_key: handle_query_data use handle_key''' return {'sql': 'last(value) as value', 'handle_key': ['value']} def get_history_sql(self, request, *args, **kwargs): category = args[0] hostname = args[1] sql = "select {field_sql} from \"{categ}\".{table} where \ host=\'{host}\'".format( field_sql=self.get_scale_data['sql'], categ=category, table=self.get_db_table(), host=hostname) sql += " and time > now() - %s" % (CATEGORY_MAPPING[category],) sql += " group by time(%s)" % (self.TENDENCY_INTERVAL_TIME[category],) return sql def get_current_sql(self, category, hostname): sql = "select last(value) from \"{categ}\".{table} where " \ "host=\'{host}\'".format(categ=category, table=self.get_db_table(), host=hostname ) return sql def get_current_data(self, sql): ret = cache.get(sql) current = 0 for p in ret.get_points(): current = p.get('last', 0) return current def handle_query_data(self, data): return list(data.get_points()) def return_success(self, history, current): return_data = {"history": history if history else [], 'current': current} return Response(return_data, status=HTTP_200_OK)
子类(视图)对抽象类的使用
class NodeHistoryCpuView(NodeHistoryBaseView): permission_classes = (AsOperatorRole,) def get_db_table(self): return 'node_cpu'
四,django 讲一个文件夹 中的文件压缩到另一个文件 api

import tarfile import uuid from glob import iglob from os import path class WebLogView(APIView): permission_classes = (AsAdminRole,) def post(self, request): #生成一个压缩文件名称 target = path.join( settings.DOWNLOAD_DIR, 'lico-log-{}.tar.bz2'.format(uuid.uuid4()) ) with tarfile.open(target, 'w:bz2') as tf: # 遍历所有的 以 log 结尾的文件 并且进行压缩! # iglob() 遍历文件夹 返回的是生成器 for f in iglob( path.join(settings.LOG_DIR, '*.log') ): tf.add(f, path.join('lico-log', path.basename(f))) # 只返回文件名称 不是路径 return Response( data={'name': path.basename(target)} )