Files
VDES_Backend/code/system/management/commands/generator.py

261 lines
10 KiB
Python
Raw Normal View History

2026-07-13 15:37:05 +08:00
import json
import logging
import os
import shutil
from django.core.management.base import BaseCommand
from fuadmin.settings import BASE_DIR
logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
创建App命令:
python manage.py createapp app名
python manage.py createapp app01 app02 ...
python manage.py createapp 一级文件名/app01 ... # 支持多级目录建app
"""
def add_arguments(self, parser):
parser.add_argument('app_info', nargs='*', type=str, )
def handle(self, *args, **options):
app_info = options.get('app_info')
for name in app_info:
app = json.loads(name)
name = app.get('app_name')
names = name.split('/')
dnames = ".".join(names)
app_path = os.path.join(BASE_DIR, "dvadmin", *names)
# 判断app是否存在
if os.path.exists(app_path):
print(f"App {name} 已存在!")
# break
else:
source_path = os.path.join(BASE_DIR, "dvadmin", "utils", "template")
target_path = app_path
if not os.path.exists(target_path):
# 如果目标路径不存在原文件夹的话就创建
os.makedirs(target_path)
if os.path.exists(source_path):
# 如果目标路径存在原文件夹的话就先删除
shutil.rmtree(target_path)
shutil.copytree(source_path, target_path)
# 注册app到 settings.py 中
injection(os.path.join(BASE_DIR, "application", "settings.py"), f" 'dvadmin.{dnames}',\n",
"INSTALLED_APPS",
"]")
# 注册app到 urls.py 中
injection(os.path.join(BASE_DIR, "application", "urls.py"),
f" path(r'api/{name}/', include('dvadmin.{dnames}.urls')),\n", "urlpatterns = [",
"]")
# 修改app中的apps 内容
app_content = f"""
from django.apps import AppConfig
class {name.capitalize()}Config(AppConfig):
name = 'dvadmin.{dnames}'
verbose_name = "{names[-1]}App"
"""
with open(os.path.join(app_path, "apps.py"), 'w', encoding='UTF-8') as f:
f.write(app_content)
# 修改Model的内容
table_name = app.get('table_name')
model_name = app.get('model_name')
# app中所有不重复的字段
app_fields = app.get('fields')
field_content = ''
# app中所有不重复的字段type
fields_type = set()
# app中所有的字段name
fields_name = set()
for field in app_fields:
fields_type.add(field['type'])
fields_name.add(field['name'])
if field['type'] == 'CharField':
field_content = f"""{field_content}
{field['name']} = {field['type']}(max_length={field['max_length']}, verbose_name='{field['name']}', help_text='{field['description']}')"""
elif field['type'] == 'TextField':
field_content = f"""{field_content}
{field['name']} = {field['type']}(verbose_name='{field['name']}', help_text='{field['description']}')"""
model_content = f"""
from django.db.models import {','.join(fields_type)}
from dvadmin.utils.models import CoreModel
class {model_name}(CoreModel):
{field_content}
class Meta:
verbose_name = '{model_name}'
verbose_name_plural = verbose_name
def __str__(self):
return self.{fields_name.pop()}
"""
with open(os.path.join(app_path, "models", f"{table_name}.py"), 'w', encoding='UTF-8') as f:
f.write(model_content)
# 修改 model init文件
model_init_content = f"from dvadmin.{name}.models.{table_name} import {model_name}"
with open(os.path.join(app_path, "models", "__init__.py"), 'a', encoding='UTF-8') as f:
f.write(model_init_content)
f.write('\n')
# 修改filters的内容
filter_content = f"""
import django_filters
from dvadmin.{name}.models import {model_name}
class {model_name}Filter(django_filters.rest_framework.FilterSet):
# 通过 lookup_expr 可进行模糊查询,其他配置可自行百度
# name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = {model_name}
fields = '__all__'
"""
with open(os.path.join(app_path, "filters", f"{table_name}_filter.py"), 'w', encoding='UTF-8') as f:
f.write(filter_content)
# 修改 filters init文件
filter_init_content = f"from .{table_name}_filter import {model_name}Filter"
with open(os.path.join(app_path, "filters", "__init__.py"), 'a', encoding='UTF-8') as f:
f.write(filter_init_content)
f.write('\n')
# 修改serializers的内容
serializer_content = f"""
from rest_framework import serializers
from dvadmin.{name}.models import {model_name}
from dvadmin.utils.serializers import CustomModelSerializer
class {model_name}Serializer(CustomModelSerializer):
class Meta:
model = {model_name}
fields = '__all__'
class {model_name}CreateUpdateSerializer(CustomModelSerializer):
# 此处可写定制的 创建/更新 内容
def validate(self, attrs: dict):
return super().validate(attrs)
class Meta:
model = {model_name}
fields = '__all__'
class {model_name}ImportSerializer(CustomModelSerializer):
class Meta:
model = {model_name}
fields = '__all__'
class {model_name}ExportSerializer(CustomModelSerializer):
class Meta:
model = {model_name}
fields = '__all__'
"""
with open(os.path.join(app_path, 'serializers', f'{table_name}_serializer.py'), 'w', encoding='UTF-8') as f:
f.write(serializer_content)
# 修改 serializers init文件
serializer_init_content = f"from .{table_name}_serializer import {model_name}Serializer, " \
f"{model_name}CreateUpdateSerializer, " \
f"{model_name}ImportSerializer, " \
f"{model_name}ExportSerializer"
with open(os.path.join(app_path, "serializers", "__init__.py"), 'a', encoding='UTF-8') as f:
f.write(serializer_init_content)
f.write('\n')
# 修改view内容
view_content = f"""
from dvadmin.utils.filters import DataLevelPermissionsFilter
from dvadmin.utils.viewset import CustomModelViewSet
from dvadmin.{name}.models import {model_name}
from dvadmin.{name}.filters import {model_name}Filter
from dvadmin.{name}.serializers import {model_name}Serializer, {model_name}CreateUpdateSerializer, {model_name}ImportSerializer, {model_name}ExportSerializer
class {model_name}ModelViewSet(CustomModelViewSet):
queryset = {model_name}.objects.all()
serializer_class = {model_name}Serializer # 序列化器
create_serializer_class = {model_name}CreateUpdateSerializer # 创建/更新时的列化器
update_serializer_class = {model_name}CreateUpdateSerializer # 创建/更新时的列化器
filter_class = {model_name}Filter # 过滤器
extra_filter_backends = [DataLevelPermissionsFilter] # 数据权限类,不需要可注释掉
# ordering = ['create_datetime'] # 默认排序
# 导出
export_field_data = [] # 导出
export_serializer_class = {model_name}ExportSerializer # 导出序列化器
# 导入
import_field_data = []
import_serializer_class = {model_name}ImportSerializer
"""
with open(os.path.join(app_path, 'views', f'{table_name}_view.py'), 'w', encoding='UTF-8') as f:
f.write(view_content)
# 修改 views init文件
view_init_content = f"from .{table_name}_view import {model_name}ModelViewSet"
with open(os.path.join(app_path, "views", "__init__.py"), 'a', encoding='UTF-8') as f:
f.write(view_init_content)
f.write('\n')
# 修改 url文件
url_package = f"from dvadmin.{name}.views import {model_name}ModelViewSet"
injection(os.path.join(app_path, "urls.py"),
f"{url_package}\n", "from rest_framework.routers import DefaultRouter",
"router = DefaultRouter()")
url_path = f"router.register(r'{table_name}', {model_name}ModelViewSet)"
injection(os.path.join(app_path, "urls.py"),
f"{url_path}\n", "router = DefaultRouter()",
"urlpatterns = [")
export_import_url = f""" # 导出项目
path('{table_name}/export/', {model_name}ModelViewSet.as_view({{'get': 'export', }})),
# 项目导入模板下载及导入
path('{table_name}/importTemplate/', {model_name}ModelViewSet.as_view({{'get': 'importTemplate', 'post': 'importTemplate'}}))"""
injection(os.path.join(app_path, "urls.py"),
f"{export_import_url}\n", "urlpatterns = [", "]")
print(f"创建 {name} App成功")
def injection(file_path, insert_content, startswith, endswith):
with open(file_path, "r+", encoding="utf-8") as f:
data = f.readlines()
with open(file_path, 'w', encoding='UTF-8') as f1:
is_INSTALLED_APPS = False
is_insert = False
for content in data:
# 判断文件是否 INSTALLED_APPS 开头
if not is_insert and content.startswith(startswith):
is_INSTALLED_APPS = True
if not is_insert and content.startswith(endswith) and is_INSTALLED_APPS:
# 给前一行插入数据
content = insert_content + content
is_insert = True
f1.writelines(content)