#!/bin/python #coding: utf-8 # +------------------------------------------------------------------- # | django-vue-lyadmin 专业版 # +------------------------------------------------------------------- # | Author: lybbn # +------------------------------------------------------------------- # | QQ: 1042594286 # +------------------------------------------------------------------- # | Date: 2023-11-07 # +------------------------------------------------------------------- # | version: v1.5 # +------------------------------------------------------------------- # ------------------------------ # 表单构建 # ------------------------------ import os import sys import json from django.conf import settings from django.core import management from django.utils import autoreload from mysystem.models import Menu,MenuButton from utils.lyformbuilder.template.lymodels import lyGenerateModels from utils.lyformbuilder.template.lyviewset import lyGenerateViewSet from utils.lyformbuilder.template.lyurls import lyGenerateUrls from utils.lyformbuilder.template.element.indexvue_lytable import lyGenerateIndexVue class GenerateCode: def __init__(self): pass def generate(self,objects,mount=False,menu_instance=None,is_delete_file=False): """ is_delete_file:是否同时删除文件和相关菜单权限等 """ data = [] object = {}#处理后的需要的后台字段 object['formConfig'] = objects['formConfig'] object['widgetList'] = self.filterFormField(objects['widgetList']) if len(object['widgetList']) <1: raise ValueError("暂无可生成的CRUD配置") models = lyGenerateModels(object) data.append({ 'code':models, 'file':'models.py', }) viewset = lyGenerateViewSet(object) data.append({ 'code': viewset, 'file': 'views.py' }) url_route_name = object['formConfig']['modelClassName'] base_url_path = "/api/lyformbuilder/"+url_route_name+"/" api_list = [base_url_path,base_url_path,base_url_path+"{id}/",base_url_path+"{id}/",base_url_path+"{id}/",base_url_path+"export/"] urls = lyGenerateUrls(object) data.append({ 'code': urls, 'file': 'urls.py' }) VueIndexName = 'lyFormBuilder%s'%object['formConfig']['modelClassName'] indexvue = lyGenerateIndexVue(json.dumps(objects),object,VueIndexName) data.append({ 'code': indexvue, 'file': '%s.vue'%VueIndexName }) if not mount:#预览代码 return data if not settings.DEBUG: raise ValueError("当前非debug状态,不支持生成") # modles检测是否存在新生成的目标文件 models_path = self.generate_backend_filepath("models") models_name = "models_%s.py" % objects['class_name'] models_name_old = "models_%s.py" % objects['file_name_old'] self.check_exists_filename(models_path,models_name,objects) # views检测是否存在新生成的目标文件 viewset_path = self.generate_backend_filepath("views") viewset_name = "views_%s.py" % objects['class_name'] viewset_name_old = "views_%s.py" % objects['file_name_old'] self.check_exists_filename(viewset_path,viewset_name, objects) # urls检测是否存在新生成的目标文件 urls_path = self.generate_backend_filepath("urls") urls_name = "urls_%s.py" % objects['class_name'] urls_name_old = "urls_%s.py" % objects['file_name_old'] self.check_exists_filename(urls_path,urls_name, objects) # 前端vue检测是否存在新生成的目标文件 indexvue_path = self.generate_frontend_filepath() indexvue_name = '%s.vue' % VueIndexName indexvue_name_old = "lyFormBuilder%s.vue" % objects['file_name_old'] self.check_exists_filename(indexvue_path,indexvue_name, objects) if is_delete_file: self.delete_menu_button(menu_instance) self.delete_file(urls_path,urls_name) self.delete_file(viewset_path,viewset_name) self.delete_file(models_path,models_name) self.delete_file(indexvue_path,indexvue_name) self.delete_migrations(objects) return True #modles创建文件 self.check_update_filename(models_path,models_name,models_name_old,objects) self.generate_file(models_path,models_name,models) #views创建文件 self.check_update_filename(viewset_path,viewset_name, viewset_name_old, objects) self.generate_file(viewset_path,viewset_name,viewset) #urls创建文件 self.check_update_filename(urls_path,urls_name, urls_name_old, objects) self.generate_file(urls_path,urls_name,urls) #前端vue创建文件 self.check_update_filename(indexvue_path,indexvue_name, indexvue_name_old, objects) self.generate_file(indexvue_path,indexvue_name,indexvue) #配置路由菜单(外层已配置) #配置按钮权限 if menu_instance: self.create_update_menu_button(menu_instance,api_list) # #同步数据库 # self.sync_db() return True #过滤form字段 def filterFormField(self,obj,data_list=None): if data_list is None: data_list = [] for o in obj: if o.get('type',None) == 'grid' and o.get('category',None) == 'container': for c in o['cols']: if c.get('formItemFlag',False) and c.get('options').get('isFormField'): data_list.append(c) continue else: self.filterFormField([c],data_list) elif o.get('type',None) == 'grid-col' and o.get('category',None) == 'container': for c in o['widgetList']: if c.get('formItemFlag',False) and c.get('options').get('isFormField'): data_list.append(c) continue else: self.filterFormField([c],data_list) elif o.get('type',None) == 'table' and o.get('category',None) == 'container': for c in o['rows']: if len(c)>0: for cc in c['cols']: if len(cc)>0: for w in cc['widgetList']: if w.get('formItemFlag',False) and w.get('options').get('isFormField'): data_list.append(w) continue else: self.filterFormField([w],data_list) elif o.get('type',None) == 'tab' and o.get('category',None) == 'container': for c in o['tabs']: if len(c)>0: for w in c['widgetList']: if w.get('formItemFlag',False) and w.get('options').get('isFormField'): data_list.append(w) continue else: self.filterFormField([w],data_list) elif o.get('type',None) == 'card' and o.get('category',None) == 'container': for w in o['widgetList']: if w.get('formItemFlag',False) and w.get('options').get('isFormField'): data_list.append(w) continue else: self.filterFormField([w],data_list) else: if o.get('formItemFlag',False) and o.get('options').get('isFormField'): data_list.append(o) return data_list def generate_backend_filepath(self,moduleName): autoCodePath = os.path.join(settings.BASE_DIR, 'apps', 'lyFormBuilder', moduleName) return autoCodePath def generate_frontend_filepath(self): autoCodePath = os.path.join(os.path.abspath(os.path.join(settings.BASE_DIR,"..")),'frontend','src','views','lyFormBuilderManage') return autoCodePath def check_exists_filename(self,path,filename,object): """ filename 新文件名 filename_old 原文件名 """ if not object['file_name_old']: raise ValueError("field file_name_old error") if not object['class_name'] == object['file_name_old']: if os.path.exists(os.path.join(path, filename)): raise ValueError("检测生成文件错误,已存在%s文件" % filename) def check_update_filename(self,path,filename,filename_old,object): """ filename 新文件名 filename_old 原文件名 """ if not object['file_name_old']: raise ValueError("field file_name_old error") if not object['class_name'] == object['file_name_old']: if os.path.exists(os.path.join(path, filename)): raise ValueError("生成文件错误,已存在%s文件" % filename) if os.path.exists(os.path.join(path, filename_old)): os.rename(os.path.join(path, filename_old),os.path.join(path, filename)) def generate_file(self,path,filename,content): # 创建app文件夹 if not os.path.exists(path): # 如果目标路径不存在就创建 os.makedirs(path) with open(os.path.join(path, filename), 'w', encoding='UTF-8') as f:#w覆盖,a追加 f.write(content) def create_update_menu_button(self,menu,api_list): button_name_list = ["查询", "新增", "编辑", "删除", "单例","导出"] # (0, "GET"),(1, "POST"),(2, "PUT"),(3, "DELETE") crud_button = ['Search','Create','Update','Delete','Retrieve',"Export"] button_name_num_list = [0, 1, 2, 3, 0] menubutton_queryset = MenuButton.objects.filter(menu=menu,name__in=button_name_list) if menubutton_queryset.count() == 0: intance_list = [] for index,value in enumerate(button_name_list): obj = MenuButton(menu=menu, name=value, value=crud_button[index],method=button_name_num_list[index],api=api_list[index]) intance_list.append(obj) MenuButton.objects.bulk_create(intance_list) else: for m in menubutton_queryset: for i,c in enumerate(crud_button): if m.value == c: m.api = api_list[i] m.save() #删除菜单、按钮、权限 def delete_menu_button(self,menu): print('删除文件>>> 删除菜单、按钮、权限') if menu: Menu.objects.filter(id=menu.id).delete() def delete_file(self,path,filename): try: print('删除文件>>> ', filename) os.remove(os.path.join(path, filename)) except: pass def get_file_list(self,directory): return [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))] #删除迁移相关 def delete_migrations(self,object): class_name = object['class_name'] db_table = object['formConfig']['modelDbTable'] lower_class_name = class_name.lower() contains_str = "_"+lower_class_name from django.db import connection with connection.cursor() as cursor: print('删除表和迁移数据>>> ', db_table) cursor.execute("DELETE FROM django_migrations WHERE app='lyFormBuilder' AND name LIKE '%s'"%("%"+contains_str+"%")) cursor.execute("DROP TABLE IF EXISTS %s"%db_table) migrationsPath = self.generate_backend_filepath("migrations") files = self.get_file_list(migrationsPath) for file_k in files: if file_k != '__init__.py' and contains_str in file_k: dst_file = os.path.join(migrationsPath, file_k) try: print('删除文件>>> ', dst_file) os.remove(dst_file) except: pass #重载 def reload_server(self): autoreload.restart_with_reloader() def sync_db(self): if settings.DEBUG: os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(["manage.py","makemigrations","--noinput",'lyFormBuilder']) execute_from_command_line(["manage.py","migrate","--noinput","lyFormBuilder"]) def syncdb(self): try: management.call_command("makemigrations","--noinput",'lyFormBuilder') management.call_command("migrate","--noinput","lyFormBuilder") return True except Exception as e: print("表单构建【同步数据库】出现异常,异常内容:%s"%e) return False