# base-v3 **Repository Path**: dtcloud360/base-v3 ## Basic Information - **Project Name**: base-v3 - **Description**: 基础底层框架 - **Primary Language**: Python - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2024-06-02 - **Last Updated**: 2025-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # z包简介 * 目录介绍 * 模块功能介绍 * 使用示例 v1.0功能: 1. 新增restapi调度器,按照restful规范定义接口传入和返回值 2. 新增ModelMixin基类,继承AbstractModel,重写底层ORM方法,新增ORM方法,新增跨库操作方法 3. 新增通用基类的封装 4. 新增业务基类的封装 5. 新增通用方法的封装 6. 新增基础模块的支撑 ## 一、目录介绍 ``` z ├─ addons #--------------------------------------------------------------基础功能模块 │ ├─ dtcloud_style #-----------------------------------------------dtcloud皮肤 │ ├─ system_data_log #---------------------------------------------日志 │ ├─ system_dict #-------------------------------------------------数据字典 │ ├─ system_file #-------------------------------------------------系统文件 │ ├─ system_mobile_message #---------------------------------------手机短信 │ ├─ system_variable #---------------------------------------------缓存 │ ├─ xcj_db_constraint #-------------------------------------------db外键 │ ├─ xcj_form #----------------------------------------------------表单引擎 │ └─ xcj_system #---------------------------------------------------系统用户 ├─ common #--------------------------------------------------------------通用方法 ├─ tools #---------------------------------------------------------------工具 ├─ utils #---------------------------------------------------------------基类 ├─ http.py #-------------------------------------------------------------api调度器 ├─ models.py #-----------------------------------------------------------ModelMixin ├─ README.md #-----------------------------------------------------------模块指南 └─ requirements.txt #---------------------------------------------------依赖包名 ``` ## 二、模块功能介绍 z包的作用主要有三个, 1. 规范代码,方便代码移交。 2. 提高开发效率,省去相同且驳杂的事务,让程序和服务代替程序员完成一些简单工作,程序员重点着眼于业务功能的实现。 3. 封装基础功能,如登录、用户体系、系统参数、文件操作等等,后续开发直接调用现有的。 ## 三、使用示例 controllers层 ```python # -*- coding: utf-8 -*- import time from dtcloud import http from z.common.func import M, page_options, config from z.common.result import R from z.http import restapi_route # noinspection PyTypeChecker fields_ = ['id', 'name', 'type_id', 'type_name', 'covers', 'cover', 'covers_url', 'category_id', 'category_name', 'progress', 'planned_amount', 'square', 'address', 'coordinates', 'approval_type_id', 'approval_type_name', 'construction_id', 'agent_id', 'agent_name', 'investment_type_id', 'investment_type_name', 'leader_id', 'milestone_template_id', 'description'] class ProjectController(http.Controller): model = "project" @restapi_route('/project', methods=['POST']) def create_project(self, **kwargs): """ 创建记录 :return: data """ return R.ok(M(self.model).c(kwargs).id) @restapi_route('/project', methods=['GET']) def get_project(self, **kwargs): """ 获取记录 :return: 列表及总数量 """ # 搜索项 ---------------------------------------------------------------- name = kwargs.get('name', '').strip() type_id = int(kwargs.get('type_id', 0)) domain = [] if name: domain.append(('name', 'ilike', name)) if type_id: domain.append(('type_id', '=', type_id)) # 搜索项 ---------------------------------------------------------------- return R.data(M(self.model).pagination(domain=domain, fields=fields_, load='', **page_options())) @restapi_route('/project/kv', methods=['GET']) def get_project_vk(self, **kwargs): """ 获取key=>value形式数据 :return: 列表及总数量 """ # 搜索项 ---------------------------------------------------------------- q = kwargs.get('q', '').strip() type_id = int(kwargs.get('type_id', 0)) ids = kwargs.get('ids', '') ids = ids.split(',') if ids else [] # 去重 ids = list(set(ids)) domain = [] if q: domain.append(('name', 'ilike', q)) if type_id: domain.append(('type_id', '=', type_id)) if ids: domain.append(('id', 'in', ids)) limit = len(ids) if ids else None # 响应形式 type_ = kwargs.get('type', 'list') # 搜索项 ---------------------------------------------------------------- res = M(self.model).pagination(domain=domain, fields=['id', 'name'], load='', **page_options(limit=limit)) res = {'item': {str(item['id']): item['name'] for item in res['item']}, 'count': res['count']} \ if 'json' == type_ else res return R.data(res) @restapi_route('/project/', methods=['GET']) def get_single_project(self, pk): """ 获取单条记录 :param pk: 主键 :return: 单条记录 """ res = M(self.model).browse(pk) res.ensure_one(f'数据不存在:{pk}') return R.data(res.read_one(fields_, load='')) @restapi_route('/project/', methods=['PUT']) def update_project(self, pk, **kwargs): """ 编辑记录 :param pk: 主键 :param edit_info: 编辑信息 必填 :return: 返回编辑结果 """ return R.ok(M(self.model).u(pk, kwargs)) @restapi_route('/project/', methods=['DELETE']) def delete_project(self, pk: int): """ 删除 :param pk: 主键 :return: """ return R.ok(M(self.model).d(pk)) @restapi_route('/project/batch', methods=['DELETE']) def batch_delete_project(self, pks: list): """ 删除多条 :param pks: 主键列表 :return: 返回删除结果 """ return R.ok(M(self.model).d(ids=pks)) @restapi_route('/project//members', methods=['POST']) def set_project_members(self, pk: int, **kwargs): """ 设置项目成员 :param pk: 项目id :return: """ members = kwargs.get('members', []) M('project').set_members(pk, members) return R.ok() @restapi_route('/project//members', methods=['GET']) def get_project_members(self, pk: int): """ 获取项目成员 :param pk: 项目id :return: """ res = M('project').get_members(pk) return R.ok(res) @restapi_route('/project/test', methods=['GET']) def project_test(self): """ 获取项目成员 :param pk: 项目id :return: """ res = M('project.test').c( {"name": "项目名称", "test": '123', "type_id": 1, "category_id": 1, "square": 10000, "address": "test", "coordinates": "adsf", "leader_id": 12, "milestone_template_id": 33}) return R.ok(res) ``` models层 ```python # -*- coding: utf-8 -*- from dtcloud import fields from dtcloud.exceptions import ValidationError from dtcloud.http import request from z.common.func import M, random_str, page_options, xint from z.models import ModelMixin class Project(ModelMixin): _name = "project" _table = "gk2_project" _description = "项目" _order = 'id desc' name = fields.Char(string="名称", required=True) code = fields.Char(string='项目编号', required=True, index=True) type_id = fields.Many2one(string="项目类型", comodel_name="system.dict.option", db_constraint=False, required=True) type_name = fields.Char(string='项目类型名称', related='type_id.name', depends=['type_id']) category_id = fields.Many2one(string="项目分类", comodel_name="system.dict.option", db_constraint=False, required=True, default=0) category_name = fields.Char(string='项目分类名称', related='category_id.name', depends=['category_id']) progress = fields.Float(string='项目进展', default=0) planned_amount = fields.Float(string="计划总投资额") square = fields.Float(string="建成规模") address = fields.Char(string="工程地址", required=True) coordinates = fields.Json(string="地图坐标") covers = fields.Json(string='项目封面') covers_url = fields.Json(string='项目封面URL', compute='_convert') cover = fields.Char(string='默认封面', compute='_convert') approval_type_id = fields.Many2one(string="审批类型", comodel_name="system.dict.option", db_constraint=False, default=0) approval_type_name = fields.Char(string='审批类型名称', related='approval_type_id.name', depends=['approval_type_id']) construction_id = fields.Many2one(string="建设单位", comodel_name="system.dict.option", db_constraint=False, default=0) construction_name = fields.Char(string='建设单位名称', related='construction_id.name', depends=['construction_id']) agent_id = fields.Many2one(string="代建单位", comodel_name="system.dict.option", db_constraint=False, default=0) agent_name = fields.Char(string='代建单位名称', related='agent_id.name', depends=['agent_id']) investment_type_id = fields.Many2one(string="投资类型", comodel_name="system.dict.option", db_constraint=False, default=0) investment_type_name = fields.Char(string='投资类型名称', related='investment_type_id.name', depends=['investment_type_id']) leader_id = fields.Many2one(string='项目负责人', comodel_name="res.users", db_constraint=False) milestone_template_id = fields.Integer(string="里程碑模版", default=0) description = fields.Char(string="简要说明", default='') def _convert(self): # cover_entities = [] # for rec in self: # cover_entities += rec.covers or [] # covers = {str(res): M('system.file').get_url(res) for res in cover_entities} # for rec in self: # rec.cover = covers[str(rec.covers[0])] if rec.covers and len(rec.covers) >= 1 and str(rec.covers[0]) in covers else None # rec.covers_url = [] # # rec.covers_url = [{"id": id_, "url": covers[str(id_)]} for id_ in rec.covers] for rec in self: rec.cover = rec.covers[0]['url'] if type(rec.covers) == 'list' and len(rec.covers) >=1 else '' rec.covers_url = [] def _format_data(self, data, entity=None): # 必填项 name = data.get('name') type_id = xint(data.get('type_id', 0)) category_id = xint(data.get('category_id', 0)) square = float(data.get('square', 0)) address = data.get('address') coordinates = data.get('coordinates') leader_id = xint(data.get('leader_id', 0)) milestone_template_id = xint(data.get('milestone_template_id', 0)) investment_type_id = xint(data.get('investment_type_id', 0)) description = data.get('description') if not name: raise ValidationError('请输入名称') if not type_id: raise ValidationError('请选择项目类型') if not category_id: raise ValidationError('请选择项目分类') if not square: raise ValidationError('请输入建成规模') if not address: raise ValidationError('请输入项目地址') if not coordinates: raise ValidationError('请选择项目坐标') if not leader_id: raise ValidationError('请选择项目负责人') if not milestone_template_id: raise ValidationError('请选择里程碑模版') # 选填项 planned_amount = float(data.get('planned_amount', 0)) covers = data.get('covers') approval_type_id = xint(data.get('approval_type_id', 0)) construction_id = xint(data.get('construction_id', 0)) agent_id = xint(data.get('agent_id', 0)) # 新增时创建code code = self._create_code() return {"name": name, "code": code, "type_id": type_id, "category_id": category_id, "square": square, "address": address, "coordinates": coordinates, "leader_id": leader_id, "milestone_template_id": milestone_template_id, "planned_amount": planned_amount, "covers": covers, "approval_type_id": approval_type_id, "construction_id": construction_id, "agent_id": agent_id, "description": description, "investment_type_id": investment_type_id} def _create_code(self): code = random_str(16) if self.search(domain=[('code', '=', code)]).exists(): return self._create_code() return code def set_members(self, project_id, members): # 先删除项目成员 M('project.members').delete(domain=[('project_id', '=', project_id)]) # 添加项目成员 if type(members) == str: members = members.split(',') data = [{"project_id": project_id, "user_id": int(member)} for member in members] M('project.members').c(data) def get_members(self, project_id): return M('project.members').search(domain=[('project_id', '=', project_id)]) ```