refactor(applied treebeard model): MP_Node for menu/dictionary & AL_Node for sysconfig/dept

treebeard^2
Angelo 2022-05-18 17:46:07 +08:00
parent dcd39758df
commit 343ee86294
13 changed files with 2379 additions and 1637 deletions

View File

@ -10,7 +10,7 @@ def is_tenants_mode():
判断是否为租户模式
:return:
"""
return hasattr(connection, 'tenant') and connection.tenant.schema_name
return hasattr(connection, "tenant") and connection.tenant.schema_name
# ================================================= #
@ -18,27 +18,37 @@ def is_tenants_mode():
# ================================================= #
def _get_all_dictionary():
from dvadmin.system.models import Dictionary
queryset = Dictionary.objects.filter(status=True, is_value=False)
data = []
for instance in queryset:
data.append({
data.append(
{
"id": instance.id,
"value": instance.value,
"children": list(Dictionary.objects.filter(parent=instance.id).filter(status=1).
values('label', 'value', 'type', 'color'))
})
"children": list(
instance.get_children()
.filter(status=1)
.values("label", "value", "type", "color")
),
}
)
return {ele.get("value"): ele for ele in data}
def _get_all_system_config():
data = {}
from dvadmin.system.models import SystemConfig
system_config_obj = SystemConfig.objects.filter(status=True, parent_id__isnull=False).values(
'parent__key', 'key', 'value', 'form_item_type').order_by('sort')
system_config_obj = (
SystemConfig.objects.filter(status=True, parent__isnull=False)
.values("parent__key", "key", "value", "form_item_type")
.order_by("sort")
)
for system_config in system_config_obj:
value = system_config.get('value') or ''
if value and system_config.get('form_item_type') == 7:
value = value[0].get('url')
value = system_config.get("value") or ""
if value and system_config.get("form_item_type") == 7:
value = value[0].get("url")
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
return data
@ -51,9 +61,12 @@ def init_dictionary():
try:
if is_tenants_mode():
from django_tenants.utils import tenant_context, get_tenant_model
for tenant in get_tenant_model().objects.filter():
with tenant_context(tenant):
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
settings.DICTIONARY_CONFIG[
connection.tenant.schema_name
] = _get_all_dictionary()
else:
settings.DICTIONARY_CONFIG = _get_all_dictionary()
print("初始化字典配置完成")
@ -72,9 +85,12 @@ def init_system_config():
if is_tenants_mode():
from django_tenants.utils import tenant_context, get_tenant_model
for tenant in get_tenant_model().objects.filter():
with tenant_context(tenant):
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
settings.SYSTEM_CONFIG[
connection.tenant.schema_name
] = _get_all_system_config()
else:
settings.SYSTEM_CONFIG = _get_all_system_config()
print("初始化系统配置完成")
@ -90,9 +106,12 @@ def refresh_dictionary():
"""
if is_tenants_mode():
from django_tenants.utils import tenant_context, get_tenant_model
for tenant in get_tenant_model().objects.filter():
with tenant_context(tenant):
settings.DICTIONARY_CONFIG[connection.tenant.schema_name] = _get_all_dictionary()
settings.DICTIONARY_CONFIG[
connection.tenant.schema_name
] = _get_all_dictionary()
else:
settings.DICTIONARY_CONFIG = _get_all_dictionary()
@ -104,9 +123,12 @@ def refresh_system_config():
"""
if is_tenants_mode():
from django_tenants.utils import tenant_context, get_tenant_model
for tenant in get_tenant_model().objects.filter():
with tenant_context(tenant):
settings.SYSTEM_CONFIG[connection.tenant.schema_name] = _get_all_system_config()
settings.SYSTEM_CONFIG[
connection.tenant.schema_name
] = _get_all_system_config()
else:
settings.SYSTEM_CONFIG = _get_all_system_config()
@ -121,7 +143,9 @@ def get_dictionary_config(schema_name=None):
:return:
"""
if is_tenants_mode():
dictionary_config = settings.DICTIONARY_CONFIG[schema_name or connection.tenant.schema_name]
dictionary_config = settings.DICTIONARY_CONFIG[
schema_name or connection.tenant.schema_name
]
else:
dictionary_config = settings.DICTIONARY_CONFIG
return dictionary_config or {}
@ -165,7 +189,9 @@ def get_system_config(schema_name=None):
:return:
"""
if is_tenants_mode():
dictionary_config = settings.SYSTEM_CONFIG[schema_name or connection.tenant.schema_name]
dictionary_config = settings.SYSTEM_CONFIG[
schema_name or connection.tenant.schema_name
]
else:
dictionary_config = settings.SYSTEM_CONFIG
return dictionary_config or {}

19
backend/dev/_venv.py Normal file
View File

@ -0,0 +1,19 @@
import os
import sys
from pathlib import Path
# #################### start #######################
# AREPL for python调试导入项目依赖 (可禁用)
BASE_DIR = Path(__file__).parent.parent
VENV_DIR = Path.joinpath(BASE_DIR, "__pypackages__", "3.8", "lib") # PDM
# print(f"{BASE_DIR=}")
# 确认BASE_DIR无误后添加如下路径至系统路径
for dir in [str(BASE_DIR), str(VENV_DIR)]:
if dir not in sys.path:
sys.path.insert(1, dir)
# #################### end #########################
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
django.setup()

View File

@ -0,0 +1,118 @@
# 初始化
import json
from _venv import *
from django.core import serializers
from dvadmin.system.models import (
Dept,
Button,
Menu,
MenuButton,
Role,
Users,
Dictionary,
)
def export_data():
db_dept_data = (
Dept.objects.all().values("id", "name", "sort", "parent").order_by("id")
)
for dept in db_dept_data:
dept["parent_id"] = dept.pop("parent")
db_button_data = Button.objects.all().values("id", "name", "value").order_by("id")
db_menu_data = (
Menu.objects.all()
.values(
"id",
"name",
"sort",
"web_path",
"icon",
"is_catalog",
"visible",
"parent",
"component",
"component_name",
)
.order_by("id")
)
for menu in db_menu_data:
menu["parent_id"] = menu.pop("parent")
db_menu_button_data = (
MenuButton.objects.all()
.values("id", "menu", "name", "value", "api", "method")
.order_by("id")
)
for menu in db_menu_button_data:
menu["menu_id"] = menu.pop("menu")
db_dictionary_data = (
Dictionary.objects.all()
.values("id", "label", "value", "status", "sort")
.order_by("id")
)
db_staff_data = (
Users.objects.all()
.values(
"id",
"password",
"is_superuser",
"is_staff",
"is_active",
"username",
"name",
"email",
"mobile",
"dept",
)
.order_by("id")
)
db_role_data = (
Role.objects.all()
.values("id", "name", "key", "sort", "status", "admin", "data_range")
.order_by("id")
)
data_dict = {
"dept_data": db_dept_data,
"button_data": db_button_data,
"menu_data": db_menu_data,
"menu_button_data": db_menu_button_data,
"dictionary_data": db_dictionary_data,
}
with open("../dvadmin/system/util/init_data.py", "w", encoding="utf8") as f:
for k, item in data_dict.items():
f.write(f"{k} = [\n")
for obj in item:
f.write("\t")
f.write(str(obj))
f.write(",\n")
f.write("]\n\n")
f.write(f"role_data = [\n")
json_data = json.loads(serializers.serialize("json", Role.objects.all()))
for index, obj in enumerate(db_role_data):
obj["dept"] = json_data[index]["fields"]["dept"]
obj["menu"] = json_data[index]["fields"]["menu"]
obj["permission"] = json_data[index]["fields"]["permission"]
f.write("\t")
f.write(str(obj))
f.write(",\n")
f.write("]\n\n")
f.write(f"staff_data = [\n")
json_data = json.loads(serializers.serialize("json", Users.objects.all()))
for index, obj in enumerate(db_staff_data):
obj["dept_id"] = obj.pop("dept")
obj["role"] = json_data[index]["fields"]["role"]
f.write("\t")
f.write(str(obj))
f.write(",\n")
f.write("]\n\n")
if __name__ == "__main__":
# 生成初始化data
export_data() # 调试用, 可先禁用settings.INSTALLED_APPS中的自定义app

24
backend/dev/list2tree.py Normal file
View File

@ -0,0 +1,24 @@
import _venv
from init_data import *
from dvadmin.system.models import *
def list2tree(data_list, parent_id=None):
result = []
for item in data_list:
data_format = {}
if item["parent_id"] == parent_id:
bak = item.copy()
del bak["parent_id"]
item_id = bak.pop("id")
data_format["id"] = item_id
data_format["data"] = bak
result.append(data_format)
childs = [obj for obj in data_list if obj["parent_id"] == item_id]
children = list2tree(childs, item_id)
if childs:
data_format["children"] = children
return result
print(list2tree(system_config_data))

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
import hashlib
import os
from treebeard.mp_tree import MP_Node
from treebeard.al_tree import AL_Node
from django.contrib.auth.models import AbstractUser
from django.db import models
@ -14,62 +17,107 @@ STATUS_CHOICES = (
class Users(AbstractUser, CoreModel):
username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name='用户账号', help_text="用户账号")
email = models.EmailField(max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
mobile = models.CharField(max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话")
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
username = models.CharField(
max_length=150,
unique=True,
db_index=True,
verbose_name="用户账号",
help_text="用户账号",
)
email = models.EmailField(
max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱"
)
mobile = models.CharField(
max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话"
)
avatar = models.CharField(
max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像"
)
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
GENDER_CHOICES = (
(0, "未知"),
(1, ""),
(2, ""),
)
gender = models.IntegerField(choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True,
help_text="性别")
gender = models.IntegerField(
choices=GENDER_CHOICES,
default=0,
verbose_name="性别",
null=True,
blank=True,
help_text="性别",
)
USER_TYPE = (
(0, "后台用户"),
(1, "前台用户"),
)
user_type = models.IntegerField(choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True,
help_text="用户类型")
post = models.ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False, help_text="关联岗位")
role = models.ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False, help_text="关联角色")
dept = models.ForeignKey(to='Dept', verbose_name='所属部门', on_delete=models.PROTECT, db_constraint=False, null=True,
blank=True, help_text="关联部门")
user_type = models.IntegerField(
choices=USER_TYPE,
default=0,
verbose_name="用户类型",
null=True,
blank=True,
help_text="用户类型",
)
post = models.ManyToManyField(
to="Post", verbose_name="关联岗位", db_constraint=False, help_text="关联岗位"
)
role = models.ManyToManyField(
to="Role", verbose_name="关联角色", db_constraint=False, help_text="关联角色"
)
dept = models.ForeignKey(
to="Dept",
verbose_name="所属部门",
on_delete=models.PROTECT,
db_constraint=False,
null=True,
blank=True,
help_text="关联部门",
)
def set_password(self, raw_password):
super().set_password(hashlib.md5(raw_password.encode(encoding='UTF-8')).hexdigest())
super().set_password(
hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest()
)
class Meta:
db_table = table_prefix + "system_users"
verbose_name = '用户表'
verbose_name = "用户表"
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
ordering = ("-create_datetime",)
class Post(CoreModel):
name = models.CharField(null=False, max_length=64, verbose_name="岗位名称", help_text="岗位名称")
name = models.CharField(
null=False, max_length=64, verbose_name="岗位名称", help_text="岗位名称"
)
code = models.CharField(max_length=32, verbose_name="岗位编码", help_text="岗位编码")
sort = models.IntegerField(default=1, verbose_name="岗位顺序", help_text="岗位顺序")
STATUS_CHOICES = (
(0, "离职"),
(1, "在职"),
)
status = models.IntegerField(choices=STATUS_CHOICES, default=1, verbose_name="岗位状态", help_text="岗位状态")
status = models.IntegerField(
choices=STATUS_CHOICES, default=1, verbose_name="岗位状态", help_text="岗位状态"
)
class Meta:
db_table = table_prefix + "system_post"
verbose_name = '岗位表'
verbose_name = "岗位表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
class Role(CoreModel):
name = models.CharField(max_length=64, verbose_name="角色名称", help_text="角色名称")
key = models.CharField(max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符")
key = models.CharField(
max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符"
)
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
status = models.BooleanField(default=True, verbose_name="角色状态", help_text="角色状态")
admin = models.BooleanField(default=False, verbose_name="是否为admin", help_text="是否为admin")
admin = models.BooleanField(
default=False, verbose_name="是否为admin", help_text="是否为admin"
)
DATASCOPE_CHOICES = (
(0, "仅本人数据权限"),
(1, "本部门及以下数据权限"),
@ -77,78 +125,134 @@ class Role(CoreModel):
(3, "全部数据权限"),
(4, "自定数据权限"),
)
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围")
data_range = models.IntegerField(
default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围"
)
remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
dept = models.ManyToManyField(to='Dept', verbose_name='数据权限-关联部门', db_constraint=False, help_text="数据权限-关联部门")
menu = models.ManyToManyField(to='Menu', verbose_name='关联菜单', db_constraint=False, help_text="关联菜单")
permission = models.ManyToManyField(to='MenuButton', verbose_name='关联菜单的接口按钮', db_constraint=False,
help_text="关联菜单的接口按钮")
dept = models.ManyToManyField(
to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, help_text="数据权限-关联部门"
)
menu = models.ManyToManyField(
to="Menu", verbose_name="关联菜单", db_constraint=False, help_text="关联菜单"
)
permission = models.ManyToManyField(
to="MenuButton",
verbose_name="关联菜单的接口按钮",
db_constraint=False,
help_text="关联菜单的接口按钮",
)
class Meta:
db_table = table_prefix + 'system_role'
verbose_name = '角色表'
db_table = table_prefix + "system_role"
verbose_name = "角色表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
class Dept(CoreModel):
class Dept(AL_Node, CoreModel):
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
sort = models.IntegerField(default=1, verbose_name="显示排序", help_text="显示排序")
owner = models.CharField(max_length=32, verbose_name="负责人", null=True, blank=True, help_text="负责人")
phone = models.CharField(max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话")
email = models.EmailField(max_length=32, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
status = models.BooleanField(default=True, verbose_name="部门状态", null=True, blank=True,
help_text="部门状态")
parent = models.ForeignKey(to='Dept', on_delete=models.CASCADE, default=None, verbose_name="上级部门",
db_constraint=False, null=True, blank=True, help_text="上级部门")
owner = models.CharField(
max_length=32, verbose_name="负责人", null=True, blank=True, help_text="负责人"
)
phone = models.CharField(
max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话"
)
email = models.EmailField(
max_length=32, verbose_name="邮箱", null=True, blank=True, help_text="邮箱"
)
status = models.BooleanField(
default=True, verbose_name="部门状态", null=True, blank=True, help_text="部门状态"
)
parent = models.ForeignKey(
to="Dept",
on_delete=models.CASCADE,
default=None,
verbose_name="上级部门",
db_constraint=False,
null=True,
blank=True,
help_text="上级部门",
)
node_order_by = ["sort", "name"]
class Meta:
db_table = table_prefix + "system_dept"
verbose_name = '部门表'
verbose_name = "部门表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
class Button(CoreModel):
name = models.CharField(max_length=64, unique=True, verbose_name="权限名称", help_text="权限名称")
value = models.CharField(max_length=64, unique=True, verbose_name="权限值", help_text="权限值")
name = models.CharField(
max_length=64, unique=True, verbose_name="权限名称", help_text="权限名称"
)
value = models.CharField(
max_length=64, unique=True, verbose_name="权限值", help_text="权限值"
)
class Meta:
db_table = table_prefix + "system_button"
verbose_name = '权限标识表'
verbose_name = "权限标识表"
verbose_name_plural = verbose_name
ordering = ('-name',)
ordering = ("-name",)
class Menu(CoreModel):
parent = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name="上级菜单", null=True, blank=True,
db_constraint=False, help_text="上级菜单")
icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标")
class Menu(MP_Node, CoreModel):
icon = models.CharField(
max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标"
)
name = models.CharField(max_length=64, verbose_name="菜单名称", help_text="菜单名称")
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
sort = models.IntegerField(
default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序"
)
ISLINK_CHOICES = (
(0, ""),
(1, ""),
)
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
is_catalog = models.BooleanField(default=False, verbose_name="是否目录", help_text="是否目录")
web_path = models.CharField(max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址")
component = models.CharField(max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址")
component_name = models.CharField(max_length=50, verbose_name="组件名称", null=True, blank=True, help_text="组件名称")
status = models.BooleanField(default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态")
cache = models.BooleanField(default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存")
visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示", help_text="侧边栏中是否显示")
is_catalog = models.BooleanField(
default=False, verbose_name="是否目录", help_text="是否目录"
)
web_path = models.CharField(
max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址"
)
component = models.CharField(
max_length=128, verbose_name="组件地址", null=True, blank=True, help_text="组件地址"
)
component_name = models.CharField(
max_length=50, verbose_name="组件名称", null=True, blank=True, help_text="组件名称"
)
status = models.BooleanField(
default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态"
)
cache = models.BooleanField(
default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存"
)
visible = models.BooleanField(
default=True, blank=True, verbose_name="侧边栏中是否显示", help_text="侧边栏中是否显示"
)
def __str__(self) -> str:
return self.name
class Meta:
db_table = table_prefix + "system_menu"
verbose_name = '菜单表'
verbose_name = "菜单表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
class MenuButton(CoreModel):
menu = models.ForeignKey(to="Menu", db_constraint=False, related_name="menuPermission", on_delete=models.CASCADE,
verbose_name="关联菜单", help_text='关联菜单')
menu = models.ForeignKey(
to="Menu",
db_constraint=False,
related_name="menuPermission",
on_delete=models.CASCADE,
verbose_name="关联菜单",
help_text="关联菜单",
)
name = models.CharField(max_length=64, verbose_name="名称", help_text="名称")
value = models.CharField(max_length=64, verbose_name="权限值", help_text="权限值")
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
@ -158,78 +262,121 @@ class MenuButton(CoreModel):
(2, "PUT"),
(3, "DELETE"),
)
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法")
method = models.IntegerField(
default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法"
)
class Meta:
db_table = table_prefix + "system_menu_button"
verbose_name = '菜单权限表'
verbose_name = "菜单权限表"
verbose_name_plural = verbose_name
ordering = ('-name',)
ordering = ("-name",)
class Dictionary(CoreModel):
class Dictionary(MP_Node, CoreModel):
TYPE_LIST = (
(0, 'text'),
(1, 'number'),
(2, 'date'),
(3, 'datetime'),
(4, 'time'),
(5, 'files'),
(6, 'boolean'),
(7, 'images'),
(0, "text"),
(1, "number"),
(2, "date"),
(3, "datetime"),
(4, "time"),
(5, "files"),
(6, "boolean"),
(7, "images"),
)
label = models.CharField(
max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称"
)
value = models.CharField(
max_length=200, blank=True, null=True, verbose_name="字典编号", help_text="字典编号/实际值"
)
type = models.IntegerField(
choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型"
)
color = models.CharField(
max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色"
)
is_value = models.BooleanField(
default=False, verbose_name="是否为value值", help_text="是否为value值,用来做具体值存放"
)
label = models.CharField(max_length=100, blank=True, null=True, verbose_name="字典名称", help_text="字典名称")
value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号", help_text="字典编号/实际值")
parent = models.ForeignKey(to='self', related_name='sublist', db_constraint=False, on_delete=models.PROTECT,
blank=True, null=True, verbose_name="父级", help_text="父级")
type = models.IntegerField(choices=TYPE_LIST, default=0, verbose_name="数据值类型", help_text="数据值类型")
color = models.CharField(max_length=20, blank=True, null=True, verbose_name="颜色", help_text="颜色")
is_value = models.BooleanField(default=False, verbose_name="是否为value值", help_text="是否为value值,用来做具体值存放")
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
sort = models.IntegerField(
default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序"
)
remark = models.CharField(
max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注"
)
def __str__(self) -> str:
return self.label
class Meta:
db_table = table_prefix + 'system_dictionary'
db_table = table_prefix + "system_dictionary"
verbose_name = "字典表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
def save(
self, force_insert=False, force_update=False, using=None, update_fields=None
):
super().save(force_insert, force_update, using, update_fields)
dispatch.refresh_dictionary() # 有更新则刷新字典配置
class OperationLog(CoreModel):
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块")
request_path = models.CharField(max_length=400, verbose_name="请求地址", null=True, blank=True, help_text="请求地址")
request_body = models.TextField(verbose_name="请求参数", null=True, blank=True, help_text="请求参数")
request_method = models.CharField(max_length=8, verbose_name="请求方式", null=True, blank=True, help_text="请求方式")
request_msg = models.TextField(verbose_name="操作说明", null=True, blank=True, help_text="操作说明")
request_ip = models.CharField(max_length=32, verbose_name="请求ip地址", null=True, blank=True, help_text="请求ip地址")
request_browser = models.CharField(max_length=64, verbose_name="请求浏览器", null=True, blank=True, help_text="请求浏览器")
response_code = models.CharField(max_length=32, verbose_name="响应状态码", null=True, blank=True, help_text="响应状态码")
request_os = models.CharField(max_length=64, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
json_result = models.TextField(verbose_name="返回信息", null=True, blank=True, help_text="返回信息")
request_modular = models.CharField(
max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块"
)
request_path = models.CharField(
max_length=400, verbose_name="请求地址", null=True, blank=True, help_text="请求地址"
)
request_body = models.TextField(
verbose_name="请求参数", null=True, blank=True, help_text="请求参数"
)
request_method = models.CharField(
max_length=8, verbose_name="请求方式", null=True, blank=True, help_text="请求方式"
)
request_msg = models.TextField(
verbose_name="操作说明", null=True, blank=True, help_text="操作说明"
)
request_ip = models.CharField(
max_length=32, verbose_name="请求ip地址", null=True, blank=True, help_text="请求ip地址"
)
request_browser = models.CharField(
max_length=64, verbose_name="请求浏览器", null=True, blank=True, help_text="请求浏览器"
)
response_code = models.CharField(
max_length=32, verbose_name="响应状态码", null=True, blank=True, help_text="响应状态码"
)
request_os = models.CharField(
max_length=64, verbose_name="操作系统", null=True, blank=True, help_text="操作系统"
)
json_result = models.TextField(
verbose_name="返回信息", null=True, blank=True, help_text="返回信息"
)
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
class Meta:
db_table = table_prefix + 'system_operation_log'
verbose_name = '操作日志'
db_table = table_prefix + "system_operation_log"
verbose_name = "操作日志"
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
ordering = ("-create_datetime",)
def media_file_name(instance, filename):
h = instance.md5sum
basename, ext = os.path.splitext(filename)
return os.path.join('files', h[0:1], h[1:2], h + ext.lower())
return os.path.join("files", h[0:1], h[1:2], h + ext.lower())
class FileList(CoreModel):
name = models.CharField(max_length=50, null=True, blank=True, verbose_name="名称", help_text="名称")
name = models.CharField(
max_length=50, null=True, blank=True, verbose_name="名称", help_text="名称"
)
url = models.FileField(upload_to=media_file_name)
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
md5sum = models.CharField(
max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5"
)
def save(self, *args, **kwargs):
if not self.md5sum: # file is new
@ -240,27 +387,39 @@ class FileList(CoreModel):
super(FileList, self).save(*args, **kwargs)
class Meta:
db_table = table_prefix + 'system_file_list'
verbose_name = '文件管理'
db_table = table_prefix + "system_file_list"
verbose_name = "文件管理"
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
ordering = ("-create_datetime",)
class Area(CoreModel):
name = models.CharField(max_length=100, verbose_name="名称", help_text="名称")
code = models.CharField(max_length=20, verbose_name="地区编码", help_text="地区编码", unique=True, db_index=True)
level = models.BigIntegerField(verbose_name="地区层级(1省份 2城市 3区县 4乡级)", help_text="地区层级(1省份 2城市 3区县 4乡级)")
code = models.CharField(
max_length=20, verbose_name="地区编码", help_text="地区编码", unique=True, db_index=True
)
level = models.BigIntegerField(
verbose_name="地区层级(1省份 2城市 3区县 4乡级)", help_text="地区层级(1省份 2城市 3区县 4乡级)"
)
pinyin = models.CharField(max_length=255, verbose_name="拼音", help_text="拼音")
initials = models.CharField(max_length=20, verbose_name="首字母", help_text="首字母")
enable = models.BooleanField(default=True, verbose_name="是否启用", help_text="是否启用")
pcode = models.ForeignKey(to='self', verbose_name='父地区编码', to_field="code", on_delete=models.CASCADE,
db_constraint=False, null=True, blank=True, help_text="父地区编码")
pcode = models.ForeignKey(
to="self",
verbose_name="父地区编码",
to_field="code",
on_delete=models.CASCADE,
db_constraint=False,
null=True,
blank=True,
help_text="父地区编码",
)
class Meta:
db_table = table_prefix + "system_area"
verbose_name = '地区表'
verbose_name = "地区表"
verbose_name_plural = verbose_name
ordering = ('code',)
ordering = ("code",)
def __str__(self):
return f"{self.name}"
@ -274,89 +433,150 @@ class ApiWhiteList(CoreModel):
(2, "PUT"),
(3, "DELETE"),
)
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法")
enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True)
method = models.IntegerField(
default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法"
)
enable_datasource = models.BooleanField(
default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True
)
class Meta:
db_table = table_prefix + "api_white_list"
verbose_name = '接口白名单'
verbose_name = "接口白名单"
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
ordering = ("-create_datetime",)
class SystemConfig(CoreModel):
parent = models.ForeignKey(to='self', verbose_name='父级', on_delete=models.CASCADE,
db_constraint=False, null=True, blank=True, help_text="父级")
class SystemConfig(AL_Node, CoreModel):
parent = models.ForeignKey(
to="self",
verbose_name="父级",
on_delete=models.CASCADE,
db_constraint=False,
null=True,
blank=True,
help_text="父级",
)
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
key = models.CharField(max_length=20, verbose_name="", help_text="", db_index=True)
value = models.JSONField(max_length=100, verbose_name="", help_text="", null=True, blank=True)
key = models.CharField(
max_length=20, verbose_name="", help_text="", db_index=True
)
value = models.JSONField(
max_length=100, verbose_name="", help_text="", null=True, blank=True
)
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True)
FORM_ITEM_TYPE_LIST = (
(0, 'text'),
(1, 'datetime'),
(2, 'date'),
(3, 'textarea'),
(4, 'select'),
(5, 'checkbox'),
(6, 'radio'),
(7, 'img'),
(8, 'file'),
(9, 'switch'),
(10, 'number'),
(11, 'array'),
(12, 'imgs'),
(13, 'foreignkey'),
(14, 'manytomany'),
(15, 'time'),
data_options = models.JSONField(
verbose_name="数据options", help_text="数据options", null=True, blank=True
)
FORM_ITEM_TYPE_LIST = (
(0, "text"),
(1, "datetime"),
(2, "date"),
(3, "textarea"),
(4, "select"),
(5, "checkbox"),
(6, "radio"),
(7, "img"),
(8, "file"),
(9, "switch"),
(10, "number"),
(11, "array"),
(12, "imgs"),
(13, "foreignkey"),
(14, "manytomany"),
(15, "time"),
)
form_item_type = models.IntegerField(
choices=FORM_ITEM_TYPE_LIST,
verbose_name="表单类型",
help_text="表单类型",
default=0,
blank=True,
)
rule = models.JSONField(
null=True, blank=True, verbose_name="校验规则", help_text="校验规则"
)
placeholder = models.CharField(
max_length=50, null=True, blank=True, verbose_name="提示信息", help_text="提示信息"
)
form_item_type = models.IntegerField(choices=FORM_ITEM_TYPE_LIST, verbose_name="表单类型", help_text="表单类型", default=0,
blank=True)
rule = models.JSONField(null=True, blank=True, verbose_name="校验规则", help_text="校验规则")
placeholder = models.CharField(max_length=50, null=True, blank=True, verbose_name="提示信息", help_text="提示信息")
setting = models.JSONField(null=True, blank=True, verbose_name="配置", help_text="配置")
node_order_by = ["sort", "title", "key"]
class Meta:
db_table = table_prefix + "system_config"
verbose_name = '系统配置表'
verbose_name = "系统配置表"
verbose_name_plural = verbose_name
ordering = ('sort',)
ordering = ("sort",)
unique_together = (("key", "parent_id"),)
def __str__(self):
return f"{self.title}"
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
def save(
self, force_insert=False, force_update=False, using=None, update_fields=None
):
super().save(force_insert, force_update, using, update_fields)
dispatch.refresh_system_config() # 有更新则刷新系统配置
class LoginLog(CoreModel):
LOGIN_TYPE_CHOICES = (
(1, '普通登录'),
LOGIN_TYPE_CHOICES = ((1, "普通登录"),)
username = models.CharField(
max_length=32, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名"
)
ip = models.CharField(
max_length=32, verbose_name="登录ip", null=True, blank=True, help_text="登录ip"
)
agent = models.TextField(
verbose_name="agent信息", null=True, blank=True, help_text="agent信息"
)
browser = models.CharField(
max_length=200, verbose_name="浏览器名", null=True, blank=True, help_text="浏览器名"
)
os = models.CharField(
max_length=200, verbose_name="操作系统", null=True, blank=True, help_text="操作系统"
)
continent = models.CharField(
max_length=50, verbose_name="", null=True, blank=True, help_text=""
)
country = models.CharField(
max_length=50, verbose_name="国家", null=True, blank=True, help_text="国家"
)
province = models.CharField(
max_length=50, verbose_name="省份", null=True, blank=True, help_text="省份"
)
city = models.CharField(
max_length=50, verbose_name="城市", null=True, blank=True, help_text="城市"
)
district = models.CharField(
max_length=50, verbose_name="县区", null=True, blank=True, help_text="县区"
)
isp = models.CharField(
max_length=50, verbose_name="运营商", null=True, blank=True, help_text="运营商"
)
area_code = models.CharField(
max_length=50, verbose_name="区域代码", null=True, blank=True, help_text="区域代码"
)
country_english = models.CharField(
max_length=50, verbose_name="英文全称", null=True, blank=True, help_text="英文全称"
)
country_code = models.CharField(
max_length=50, verbose_name="简称", null=True, blank=True, help_text="简称"
)
longitude = models.CharField(
max_length=50, verbose_name="经度", null=True, blank=True, help_text="经度"
)
latitude = models.CharField(
max_length=50, verbose_name="纬度", null=True, blank=True, help_text="纬度"
)
login_type = models.IntegerField(
default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型", help_text="登录类型"
)
username = models.CharField(max_length=32, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名")
ip = models.CharField(max_length=32, verbose_name="登录ip", null=True, blank=True, help_text="登录ip")
agent = models.TextField(verbose_name="agent信息", null=True, blank=True, help_text="agent信息")
browser = models.CharField(max_length=200, verbose_name="浏览器名", null=True, blank=True, help_text="浏览器名")
os = models.CharField(max_length=200, verbose_name="操作系统", null=True, blank=True, help_text="操作系统")
continent = models.CharField(max_length=50, verbose_name="", null=True, blank=True, help_text="")
country = models.CharField(max_length=50, verbose_name="国家", null=True, blank=True, help_text="国家")
province = models.CharField(max_length=50, verbose_name="省份", null=True, blank=True, help_text="省份")
city = models.CharField(max_length=50, verbose_name="城市", null=True, blank=True, help_text="城市")
district = models.CharField(max_length=50, verbose_name="县区", null=True, blank=True, help_text="县区")
isp = models.CharField(max_length=50, verbose_name="运营商", null=True, blank=True, help_text="运营商")
area_code = models.CharField(max_length=50, verbose_name="区域代码", null=True, blank=True, help_text="区域代码")
country_english = models.CharField(max_length=50, verbose_name="英文全称", null=True, blank=True, help_text="英文全称")
country_code = models.CharField(max_length=50, verbose_name="简称", null=True, blank=True, help_text="简称")
longitude = models.CharField(max_length=50, verbose_name="经度", null=True, blank=True, help_text="经度")
latitude = models.CharField(max_length=50, verbose_name="纬度", null=True, blank=True, help_text="纬度")
login_type = models.IntegerField(default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型", help_text="登录类型")
class Meta:
db_table = table_prefix + 'system_login_log'
verbose_name = '登录日志'
db_table = table_prefix + "system_login_log"
verbose_name = "登录日志"
verbose_name_plural = verbose_name
ordering = ('-create_datetime',)
ordering = ("-create_datetime",)

View File

@ -7,6 +7,7 @@
@Remark: 字典管理
"""
from django.conf import settings
from rest_framework import serializers
from rest_framework.views import APIView
from application import dispatch
@ -34,7 +35,7 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer):
class Meta:
model = Dictionary
fields = '__all__'
fields = "__all__"
class DictionaryViewSet(CustomModelViewSet):
@ -46,30 +47,46 @@ class DictionaryViewSet(CustomModelViewSet):
retrieve:单例
destroy:删除
"""
queryset = Dictionary.objects.all()
serializer_class = DictionarySerializer
extra_filter_backends = []
search_fields = ['label']
search_fields = ["label"]
def get_queryset(self):
parent_id = self.request.query_params.get("parent", None)
if parent_id:
return self.queryset.get(id=parent_id).get_children()
return super().get_queryset()
class InitDictionaryViewSet(APIView):
"""
获取初始化配置
"""
authentication_classes = []
permission_classes = []
queryset = Dictionary.objects.all()
def get(self, request):
dictionary_key = self.request.query_params.get('dictionary_key')
dictionary_key = self.request.query_params.get("dictionary_key")
if dictionary_key:
if dictionary_key == 'all':
if dictionary_key == "all":
data = [ele for ele in dispatch.get_dictionary_config().values()]
if not data:
dispatch.refresh_dictionary()
data = [ele for ele in dispatch.get_dictionary_config().values()]
else:
data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type',
'color')
# data = self.queryset.filter(
# parent__value=dictionary_key, status=True
# ).values("label", "value", "type", "color")
data = (
Dictionary.objects.get(value=dictionary_key)
.get_children()
.filter(status=True)
.values("label", "value", "type", "color")
)
print(data)
return SuccessResponse(data=data, msg="获取成功")
return SuccessResponse(data=[], msg="获取成功")

View File

@ -10,7 +10,7 @@ from rest_framework import serializers
from rest_framework.decorators import action
from dvadmin.system.models import Menu, MenuButton, Button
from dvadmin.utils.json_response import SuccessResponse
from dvadmin.utils.json_response import SuccessResponse, DetailResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet
@ -19,10 +19,19 @@ class MenuSerializer(CustomModelSerializer):
"""
菜单表的简单序列化器
"""
parent = serializers.SerializerMethodField(read_only=True)
menuPermission = serializers.SerializerMethodField(read_only=True)
def get_parent(self, instance):
return instance.get_parent().id if instance.get_parent() else None
def get_menuPermission(self, instance):
queryset = MenuButton.objects.filter(menu=instance.id).order_by('-name').values_list('name', flat=True)
queryset = (
MenuButton.objects.filter(menu=instance.id)
.order_by("-name")
.values_list("name", flat=True)
)
if queryset:
return queryset
else:
@ -38,6 +47,7 @@ class MenuCreateSerializer(CustomModelSerializer):
"""
菜单表的创建序列化器
"""
name = serializers.CharField(required=False)
class Meta:
@ -50,18 +60,25 @@ class WebRouterSerializer(CustomModelSerializer):
"""
前端菜单路由的简单序列化器
"""
path = serializers.CharField(source="web_path")
title = serializers.CharField(source="name")
parent = serializers.SerializerMethodField(read_only=True)
menuPermission = serializers.SerializerMethodField(read_only=True)
def get_parent(self, instance):
return instance.get_parent().id if instance.get_parent() else None
def get_menuPermission(self, instance):
# 判断是否是超级管理员
if self.request.user.is_superuser:
return Button.objects.values_list('value', flat=True)
return Button.objects.values_list("value", flat=True)
else:
# 根据当前角色获取权限按钮id集合
permissionIds = self.request.user.role.values_list('permission', flat=True)
queryset = MenuButton.objects.filter(id__in=permissionIds,menu=instance.id).values_list('value', flat=True)
permissionIds = self.request.user.role.values_list("permission", flat=True)
queryset = MenuButton.objects.filter(
id__in=permissionIds, menu=instance.id
).values_list("value", flat=True)
if queryset:
return queryset
else:
@ -82,21 +99,29 @@ class MenuViewSet(CustomModelViewSet):
retrieve:单例
destroy:删除
"""
queryset = Menu.objects.all()
serializer_class = MenuSerializer
create_serializer_class = MenuCreateSerializer
update_serializer_class = MenuCreateSerializer
search_fields = ['name', 'status']
filter_fields = ['parent','name', 'status','is_link','visible','cache','is_catalog']
search_fields = ["name", "status"]
filter_fields = [
"name",
"status",
"is_link",
"visible",
"cache",
"is_catalog",
]
extra_filter_backends = []
@action(methods=['GET'], detail=True, permission_classes=[])
@action(methods=["GET"], detail=True, permission_classes=[])
def web_router(self, request):
"""用于前端获取当前角色的路由"""
user = request.user
queryset = self.queryset.filter(status=1)
if not user.is_superuser:
menuIds = user.role.values_list('menu__id', flat=True)
menuIds = user.role.values_list("menu__id", flat=True)
queryset = Menu.objects.filter(id__in=menuIds, status=1)
serializer = WebRouterSerializer(queryset, many=True, request=request)
data = serializer.data

View File

@ -1,11 +1,13 @@
# 初始化基类
from application import settings
from treebeard.mp_tree import MP_Node
class CoreInitialize:
"""
使用方法继承此类重写 run方法 run 中调用 save 进行数据初始化
"""
creator_id = None
reset = False
@ -26,6 +28,9 @@ class CoreInitialize:
settings.INITIALIZE_RESET_LIST.append(obj)
except Exception:
pass
if MP_Node in obj.__mro__:
obj.load_bulk(data, None, True)
else:
for ele in data:
m2m_dict = {}
new_data = {}
@ -35,17 +40,21 @@ class CoreInitialize:
m2m_dict[key] = value
else:
new_data[key] = value
object, _ = obj.objects.get_or_create(id=ele.get("id"), defaults=new_data)
object, _ = obj.objects.get_or_create(
id=ele.get("id"), defaults=new_data
)
for key, m2m in m2m_dict.items():
m2m = list(set(m2m))
if m2m and len(m2m) > 0 and m2m[0]:
exec(f"""
exec(
f"""
if object.{key}:
values_list = object.{key}.all().values_list('id', flat=True)
values_list = list(set(list(values_list) + {m2m}))
object.{key}.set(values_list)
""")
"""
)
print(f"初始化完成[{obj._meta.label} => {name}]")
def run(self):
raise NotImplementedError('.run() must be overridden')
raise NotImplementedError(".run() must be overridden")

View File

@ -23,6 +23,10 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
(1)self.request能获取到rest_framework.request.Request对象
"""
# 放空treebeard.mp_tree.MP_Node的继承字段
path = serializers.CharField(required=False)
depth = serializers.IntegerField(required=False)
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
modifier_field_id = "modifier"
modifier_name = serializers.SerializerMethodField(read_only=True)

View File

@ -14,12 +14,19 @@ from rest_framework.decorators import action
from rest_framework.viewsets import ModelViewSet
from dvadmin.utils.filters import DataLevelPermissionsFilter
from dvadmin.utils.import_export_mixin import ExportSerializerMixin, ImportSerializerMixin
from dvadmin.utils.import_export_mixin import (
ExportSerializerMixin,
ImportSerializerMixin,
)
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
from dvadmin.utils.permission import CustomPermission
from django_restql.mixins import QueryArgumentsMixin
from treebeard.models import Node
class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixin,QueryArgumentsMixin):
class CustomModelViewSet(
ModelViewSet, ImportSerializerMixin, ExportSerializerMixin, QueryArgumentsMixin
):
"""
自定义的ModelViewSet:
统一标准的返回格式;新增,查询,修改可使用不同序列化器
@ -29,11 +36,12 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
(4)import_field_dict={} 导入时的字段字典 {model值: model的label}
(5)export_field_label = [] 导出时的字段
"""
values_queryset = None
ordering_fields = '__all__'
ordering_fields = "__all__"
create_serializer_class = None
update_serializer_class = None
filter_fields = '__all__'
filter_fields = "__all__"
search_fields = ()
extra_filter_backends = [DataLevelPermissionsFilter]
permission_classes = [CustomPermission]
@ -41,12 +49,14 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
export_field_label = []
def filter_queryset(self, queryset):
for backend in set(set(self.filter_backends) | set(self.extra_filter_backends or [])):
for backend in set(
set(self.filter_backends) | set(self.extra_filter_backends or [])
):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
def get_queryset(self):
if getattr(self, 'values_queryset', None):
if getattr(self, "values_queryset", None):
return self.values_queryset
return super().get_queryset()
@ -60,6 +70,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, request=request)
serializer.is_valid(raise_exception=True)
if Node in self.queryset.model.__mro__:
parent_id = request.data.get("parent")
data = serializer.validated_data
if parent_id is None:
self.queryset.model.add_root(**data)
else:
parent = self.queryset.model.objects.filter(pk=parent_id).first()
parent.add_child(**data)
return DetailResponse(data=data, msg="新增成功")
self.perform_create(serializer)
return DetailResponse(data=serializer.data, msg="新增成功")
@ -78,13 +97,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
return DetailResponse(data=serializer.data, msg="获取成功")
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
partial = kwargs.pop("partial", False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, request=request, partial=partial)
serializer = self.get_serializer(
instance, data=request.data, request=request, partial=partial
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
if getattr(instance, "_prefetched_objects_cache", None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
@ -95,17 +116,20 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
self.perform_destroy(instance)
return DetailResponse(data=[], msg="删除成功")
keys = openapi.Schema(
description="主键列表", type=openapi.TYPE_ARRAY, items=openapi.TYPE_STRING
)
keys = openapi.Schema(description='主键列表',type=openapi.TYPE_ARRAY,items=openapi.TYPE_STRING)
@swagger_auto_schema(request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['keys'],
properties={'keys': keys}
), operation_summary='批量删除')
@action(methods=['delete'],detail=False)
@swagger_auto_schema(
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT, required=["keys"], properties={"keys": keys}
),
operation_summary="批量删除",
)
@action(methods=["delete"], detail=False)
def multiple_delete(self, request, *args, **kwargs):
request_data = request.data
keys = request_data.get('keys',None)
keys = request_data.get("keys", None)
if keys:
self.get_queryset().filter(id__in=keys).delete()
return SuccessResponse(data=[], msg="删除成功")

View File

@ -393,7 +393,7 @@ export const crudOptions = (vm) => {
search: {
disabled: false
},
width: 50,
width: 60,
type: 'radio',
dict: {
data: vm.dictionary('button_whether_bool')

File diff suppressed because it is too large Load Diff