refactor(applied treebeard model): MP_Node for menu/dictionary & AL_Node for sysconfig/dept
parent
dcd39758df
commit
343ee86294
|
@ -10,7 +10,7 @@ def is_tenants_mode():
|
||||||
判断是否为租户模式
|
判断是否为租户模式
|
||||||
:return:
|
: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():
|
def _get_all_dictionary():
|
||||||
from dvadmin.system.models import Dictionary
|
from dvadmin.system.models import Dictionary
|
||||||
|
|
||||||
queryset = Dictionary.objects.filter(status=True, is_value=False)
|
queryset = Dictionary.objects.filter(status=True, is_value=False)
|
||||||
data = []
|
data = []
|
||||||
for instance in queryset:
|
for instance in queryset:
|
||||||
data.append({
|
data.append(
|
||||||
"id": instance.id,
|
{
|
||||||
"value": instance.value,
|
"id": instance.id,
|
||||||
"children": list(Dictionary.objects.filter(parent=instance.id).filter(status=1).
|
"value": instance.value,
|
||||||
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}
|
return {ele.get("value"): ele for ele in data}
|
||||||
|
|
||||||
|
|
||||||
def _get_all_system_config():
|
def _get_all_system_config():
|
||||||
data = {}
|
data = {}
|
||||||
from dvadmin.system.models import SystemConfig
|
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:
|
for system_config in system_config_obj:
|
||||||
value = system_config.get('value') or ''
|
value = system_config.get("value") or ""
|
||||||
if value and system_config.get('form_item_type') == 7:
|
if value and system_config.get("form_item_type") == 7:
|
||||||
value = value[0].get('url')
|
value = value[0].get("url")
|
||||||
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
|
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -51,9 +61,12 @@ def init_dictionary():
|
||||||
try:
|
try:
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
from django_tenants.utils import tenant_context, get_tenant_model
|
from django_tenants.utils import tenant_context, get_tenant_model
|
||||||
|
|
||||||
for tenant in get_tenant_model().objects.filter():
|
for tenant in get_tenant_model().objects.filter():
|
||||||
with tenant_context(tenant):
|
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:
|
else:
|
||||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||||
print("初始化字典配置完成")
|
print("初始化字典配置完成")
|
||||||
|
@ -72,9 +85,12 @@ def init_system_config():
|
||||||
|
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
from django_tenants.utils import tenant_context, get_tenant_model
|
from django_tenants.utils import tenant_context, get_tenant_model
|
||||||
|
|
||||||
for tenant in get_tenant_model().objects.filter():
|
for tenant in get_tenant_model().objects.filter():
|
||||||
with tenant_context(tenant):
|
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:
|
else:
|
||||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||||
print("初始化系统配置完成")
|
print("初始化系统配置完成")
|
||||||
|
@ -90,9 +106,12 @@ def refresh_dictionary():
|
||||||
"""
|
"""
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
from django_tenants.utils import tenant_context, get_tenant_model
|
from django_tenants.utils import tenant_context, get_tenant_model
|
||||||
|
|
||||||
for tenant in get_tenant_model().objects.filter():
|
for tenant in get_tenant_model().objects.filter():
|
||||||
with tenant_context(tenant):
|
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:
|
else:
|
||||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||||
|
|
||||||
|
@ -104,9 +123,12 @@ def refresh_system_config():
|
||||||
"""
|
"""
|
||||||
if is_tenants_mode():
|
if is_tenants_mode():
|
||||||
from django_tenants.utils import tenant_context, get_tenant_model
|
from django_tenants.utils import tenant_context, get_tenant_model
|
||||||
|
|
||||||
for tenant in get_tenant_model().objects.filter():
|
for tenant in get_tenant_model().objects.filter():
|
||||||
with tenant_context(tenant):
|
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:
|
else:
|
||||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||||
|
|
||||||
|
@ -121,7 +143,9 @@ def get_dictionary_config(schema_name=None):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if is_tenants_mode():
|
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:
|
else:
|
||||||
dictionary_config = settings.DICTIONARY_CONFIG
|
dictionary_config = settings.DICTIONARY_CONFIG
|
||||||
return dictionary_config or {}
|
return dictionary_config or {}
|
||||||
|
@ -165,7 +189,9 @@ def get_system_config(schema_name=None):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if is_tenants_mode():
|
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:
|
else:
|
||||||
dictionary_config = settings.SYSTEM_CONFIG
|
dictionary_config = settings.SYSTEM_CONFIG
|
||||||
return dictionary_config or {}
|
return dictionary_config or {}
|
||||||
|
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
@ -1,6 +1,9 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
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.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
@ -14,62 +17,107 @@ STATUS_CHOICES = (
|
||||||
|
|
||||||
|
|
||||||
class Users(AbstractUser, CoreModel):
|
class Users(AbstractUser, CoreModel):
|
||||||
username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name='用户账号', help_text="用户账号")
|
username = models.CharField(
|
||||||
email = models.EmailField(max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
|
max_length=150,
|
||||||
mobile = models.CharField(max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话")
|
unique=True,
|
||||||
avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
|
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="姓名")
|
name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
(0, "未知"),
|
(0, "未知"),
|
||||||
(1, "男"),
|
(1, "男"),
|
||||||
(2, "女"),
|
(2, "女"),
|
||||||
)
|
)
|
||||||
gender = models.IntegerField(choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True,
|
gender = models.IntegerField(
|
||||||
help_text="性别")
|
choices=GENDER_CHOICES,
|
||||||
|
default=0,
|
||||||
|
verbose_name="性别",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="性别",
|
||||||
|
)
|
||||||
USER_TYPE = (
|
USER_TYPE = (
|
||||||
(0, "后台用户"),
|
(0, "后台用户"),
|
||||||
(1, "前台用户"),
|
(1, "前台用户"),
|
||||||
)
|
)
|
||||||
user_type = models.IntegerField(choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True,
|
user_type = models.IntegerField(
|
||||||
help_text="用户类型")
|
choices=USER_TYPE,
|
||||||
post = models.ManyToManyField(to='Post', verbose_name='关联岗位', db_constraint=False, help_text="关联岗位")
|
default=0,
|
||||||
role = models.ManyToManyField(to='Role', verbose_name='关联角色', db_constraint=False, help_text="关联角色")
|
verbose_name="用户类型",
|
||||||
dept = models.ForeignKey(to='Dept', verbose_name='所属部门', on_delete=models.PROTECT, db_constraint=False, null=True,
|
null=True,
|
||||||
blank=True, help_text="关联部门")
|
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):
|
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:
|
class Meta:
|
||||||
db_table = table_prefix + "system_users"
|
db_table = table_prefix + "system_users"
|
||||||
verbose_name = '用户表'
|
verbose_name = "用户表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-create_datetime',)
|
ordering = ("-create_datetime",)
|
||||||
|
|
||||||
|
|
||||||
class Post(CoreModel):
|
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="岗位编码")
|
code = models.CharField(max_length=32, verbose_name="岗位编码", help_text="岗位编码")
|
||||||
sort = models.IntegerField(default=1, verbose_name="岗位顺序", help_text="岗位顺序")
|
sort = models.IntegerField(default=1, verbose_name="岗位顺序", help_text="岗位顺序")
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
(0, "离职"),
|
(0, "离职"),
|
||||||
(1, "在职"),
|
(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:
|
class Meta:
|
||||||
db_table = table_prefix + "system_post"
|
db_table = table_prefix + "system_post"
|
||||||
verbose_name = '岗位表'
|
verbose_name = "岗位表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('sort',)
|
ordering = ("sort",)
|
||||||
|
|
||||||
|
|
||||||
class Role(CoreModel):
|
class Role(CoreModel):
|
||||||
name = models.CharField(max_length=64, verbose_name="角色名称", help_text="角色名称")
|
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="角色顺序")
|
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
|
||||||
status = models.BooleanField(default=True, 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 = (
|
DATASCOPE_CHOICES = (
|
||||||
(0, "仅本人数据权限"),
|
(0, "仅本人数据权限"),
|
||||||
(1, "本部门及以下数据权限"),
|
(1, "本部门及以下数据权限"),
|
||||||
|
@ -77,78 +125,134 @@ class Role(CoreModel):
|
||||||
(3, "全部数据权限"),
|
(3, "全部数据权限"),
|
||||||
(4, "自定数据权限"),
|
(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)
|
remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True)
|
||||||
dept = models.ManyToManyField(to='Dept', verbose_name='数据权限-关联部门', db_constraint=False, help_text="数据权限-关联部门")
|
dept = models.ManyToManyField(
|
||||||
menu = models.ManyToManyField(to='Menu', verbose_name='关联菜单', db_constraint=False, help_text="关联菜单")
|
to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, help_text="数据权限-关联部门"
|
||||||
permission = models.ManyToManyField(to='MenuButton', 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:
|
class Meta:
|
||||||
db_table = table_prefix + 'system_role'
|
db_table = table_prefix + "system_role"
|
||||||
verbose_name = '角色表'
|
verbose_name = "角色表"
|
||||||
verbose_name_plural = 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="部门名称")
|
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
|
||||||
sort = models.IntegerField(default=1, 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="负责人")
|
owner = models.CharField(
|
||||||
phone = models.CharField(max_length=32, verbose_name="联系电话", null=True, blank=True, help_text="联系电话")
|
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,
|
phone = models.CharField(
|
||||||
help_text="部门状态")
|
max_length=32, 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="上级部门")
|
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:
|
class Meta:
|
||||||
db_table = table_prefix + "system_dept"
|
db_table = table_prefix + "system_dept"
|
||||||
verbose_name = '部门表'
|
verbose_name = "部门表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('sort',)
|
ordering = ("sort",)
|
||||||
|
|
||||||
|
|
||||||
class Button(CoreModel):
|
class Button(CoreModel):
|
||||||
name = models.CharField(max_length=64, unique=True, verbose_name="权限名称", help_text="权限名称")
|
name = models.CharField(
|
||||||
value = models.CharField(max_length=64, unique=True, verbose_name="权限值", help_text="权限值")
|
max_length=64, unique=True, verbose_name="权限名称", help_text="权限名称"
|
||||||
|
)
|
||||||
|
value = models.CharField(
|
||||||
|
max_length=64, unique=True, verbose_name="权限值", help_text="权限值"
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + "system_button"
|
db_table = table_prefix + "system_button"
|
||||||
verbose_name = '权限标识表'
|
verbose_name = "权限标识表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-name',)
|
ordering = ("-name",)
|
||||||
|
|
||||||
|
|
||||||
class Menu(CoreModel):
|
class Menu(MP_Node, CoreModel):
|
||||||
parent = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name="上级菜单", null=True, blank=True,
|
icon = models.CharField(
|
||||||
db_constraint=False, help_text="上级菜单")
|
max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标"
|
||||||
icon = models.CharField(max_length=64, verbose_name="菜单图标", null=True, blank=True, help_text="菜单图标")
|
)
|
||||||
name = models.CharField(max_length=64, verbose_name="菜单名称", 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 = (
|
ISLINK_CHOICES = (
|
||||||
(0, "否"),
|
(0, "否"),
|
||||||
(1, "是"),
|
(1, "是"),
|
||||||
)
|
)
|
||||||
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
|
is_link = models.BooleanField(default=False, verbose_name="是否外链", help_text="是否外链")
|
||||||
is_catalog = models.BooleanField(default=False, verbose_name="是否目录", help_text="是否目录")
|
is_catalog = models.BooleanField(
|
||||||
web_path = models.CharField(max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址")
|
default=False, verbose_name="是否目录", 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="组件名称")
|
web_path = models.CharField(
|
||||||
status = models.BooleanField(default=True, blank=True, verbose_name="菜单状态", help_text="菜单状态")
|
max_length=128, verbose_name="路由地址", null=True, blank=True, help_text="路由地址"
|
||||||
cache = models.BooleanField(default=False, blank=True, verbose_name="是否页面缓存", help_text="是否页面缓存")
|
)
|
||||||
visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示", 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:
|
class Meta:
|
||||||
db_table = table_prefix + "system_menu"
|
db_table = table_prefix + "system_menu"
|
||||||
verbose_name = '菜单表'
|
verbose_name = "菜单表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('sort',)
|
ordering = ("sort",)
|
||||||
|
|
||||||
|
|
||||||
class MenuButton(CoreModel):
|
class MenuButton(CoreModel):
|
||||||
menu = models.ForeignKey(to="Menu", db_constraint=False, related_name="menuPermission", on_delete=models.CASCADE,
|
menu = models.ForeignKey(
|
||||||
verbose_name="关联菜单", help_text='关联菜单')
|
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="名称")
|
name = models.CharField(max_length=64, verbose_name="名称", help_text="名称")
|
||||||
value = 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="接口地址")
|
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
|
||||||
|
@ -158,78 +262,121 @@ class MenuButton(CoreModel):
|
||||||
(2, "PUT"),
|
(2, "PUT"),
|
||||||
(3, "DELETE"),
|
(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:
|
class Meta:
|
||||||
db_table = table_prefix + "system_menu_button"
|
db_table = table_prefix + "system_menu_button"
|
||||||
verbose_name = '菜单权限表'
|
verbose_name = "菜单权限表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-name',)
|
ordering = ("-name",)
|
||||||
|
|
||||||
|
|
||||||
class Dictionary(CoreModel):
|
class Dictionary(MP_Node, CoreModel):
|
||||||
TYPE_LIST = (
|
TYPE_LIST = (
|
||||||
(0, 'text'),
|
(0, "text"),
|
||||||
(1, 'number'),
|
(1, "number"),
|
||||||
(2, 'date'),
|
(2, "date"),
|
||||||
(3, 'datetime'),
|
(3, "datetime"),
|
||||||
(4, 'time'),
|
(4, "time"),
|
||||||
(5, 'files'),
|
(5, "files"),
|
||||||
(6, 'boolean'),
|
(6, "boolean"),
|
||||||
(7, 'images'),
|
(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="状态")
|
status = models.BooleanField(default=True, verbose_name="状态", help_text="状态")
|
||||||
sort = models.IntegerField(default=1, verbose_name="显示排序", null=True, blank=True, help_text="显示排序")
|
sort = models.IntegerField(
|
||||||
remark = models.CharField(max_length=2000, blank=True, null=True, verbose_name="备注", help_text="备注")
|
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:
|
class Meta:
|
||||||
db_table = table_prefix + 'system_dictionary'
|
db_table = table_prefix + "system_dictionary"
|
||||||
verbose_name = "字典表"
|
verbose_name = "字典表"
|
||||||
verbose_name_plural = 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)
|
super().save(force_insert, force_update, using, update_fields)
|
||||||
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
dispatch.refresh_dictionary() # 有更新则刷新字典配置
|
||||||
|
|
||||||
|
|
||||||
class OperationLog(CoreModel):
|
class OperationLog(CoreModel):
|
||||||
request_modular = models.CharField(max_length=64, verbose_name="请求模块", null=True, blank=True, help_text="请求模块")
|
request_modular = models.CharField(
|
||||||
request_path = models.CharField(max_length=400, verbose_name="请求地址", null=True, blank=True, help_text="请求地址")
|
max_length=64, 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_path = models.CharField(
|
||||||
request_msg = models.TextField(verbose_name="操作说明", null=True, blank=True, help_text="操作说明")
|
max_length=400, 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="请求浏览器")
|
request_body = models.TextField(
|
||||||
response_code = models.CharField(max_length=32, verbose_name="响应状态码", null=True, blank=True, help_text="响应状态码")
|
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_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="响应状态")
|
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + 'system_operation_log'
|
db_table = table_prefix + "system_operation_log"
|
||||||
verbose_name = '操作日志'
|
verbose_name = "操作日志"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-create_datetime',)
|
ordering = ("-create_datetime",)
|
||||||
|
|
||||||
|
|
||||||
def media_file_name(instance, filename):
|
def media_file_name(instance, filename):
|
||||||
h = instance.md5sum
|
h = instance.md5sum
|
||||||
basename, ext = os.path.splitext(filename)
|
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):
|
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)
|
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):
|
def save(self, *args, **kwargs):
|
||||||
if not self.md5sum: # file is new
|
if not self.md5sum: # file is new
|
||||||
|
@ -240,27 +387,39 @@ class FileList(CoreModel):
|
||||||
super(FileList, self).save(*args, **kwargs)
|
super(FileList, self).save(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + 'system_file_list'
|
db_table = table_prefix + "system_file_list"
|
||||||
verbose_name = '文件管理'
|
verbose_name = "文件管理"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-create_datetime',)
|
ordering = ("-create_datetime",)
|
||||||
|
|
||||||
|
|
||||||
class Area(CoreModel):
|
class Area(CoreModel):
|
||||||
name = models.CharField(max_length=100, verbose_name="名称", help_text="名称")
|
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)
|
code = models.CharField(
|
||||||
level = models.BigIntegerField(verbose_name="地区层级(1省份 2城市 3区县 4乡级)", help_text="地区层级(1省份 2城市 3区县 4乡级)")
|
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="拼音")
|
pinyin = models.CharField(max_length=255, verbose_name="拼音", help_text="拼音")
|
||||||
initials = models.CharField(max_length=20, verbose_name="首字母", help_text="首字母")
|
initials = models.CharField(max_length=20, verbose_name="首字母", help_text="首字母")
|
||||||
enable = models.BooleanField(default=True, 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,
|
pcode = models.ForeignKey(
|
||||||
db_constraint=False, null=True, blank=True, help_text="父地区编码")
|
to="self",
|
||||||
|
verbose_name="父地区编码",
|
||||||
|
to_field="code",
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
db_constraint=False,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="父地区编码",
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + "system_area"
|
db_table = table_prefix + "system_area"
|
||||||
verbose_name = '地区表'
|
verbose_name = "地区表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('code',)
|
ordering = ("code",)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.name}"
|
return f"{self.name}"
|
||||||
|
@ -274,89 +433,150 @@ class ApiWhiteList(CoreModel):
|
||||||
(2, "PUT"),
|
(2, "PUT"),
|
||||||
(3, "DELETE"),
|
(3, "DELETE"),
|
||||||
)
|
)
|
||||||
method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法")
|
method = models.IntegerField(
|
||||||
enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True)
|
default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法"
|
||||||
|
)
|
||||||
|
enable_datasource = models.BooleanField(
|
||||||
|
default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + "api_white_list"
|
db_table = table_prefix + "api_white_list"
|
||||||
verbose_name = '接口白名单'
|
verbose_name = "接口白名单"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-create_datetime',)
|
ordering = ("-create_datetime",)
|
||||||
|
|
||||||
|
|
||||||
class SystemConfig(CoreModel):
|
class SystemConfig(AL_Node, CoreModel):
|
||||||
parent = models.ForeignKey(to='self', verbose_name='父级', on_delete=models.CASCADE,
|
parent = models.ForeignKey(
|
||||||
db_constraint=False, null=True, blank=True, help_text="父级")
|
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="标题")
|
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
|
||||||
key = models.CharField(max_length=20, verbose_name="键", help_text="键", db_index=True)
|
key = models.CharField(
|
||||||
value = models.JSONField(max_length=100, verbose_name="值", help_text="值", null=True, blank=True)
|
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)
|
sort = models.IntegerField(default=0, verbose_name="排序", help_text="排序", blank=True)
|
||||||
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
|
status = models.BooleanField(default=True, verbose_name="启用状态", help_text="启用状态")
|
||||||
data_options = models.JSONField(verbose_name="数据options", help_text="数据options", null=True, blank=True)
|
data_options = models.JSONField(
|
||||||
FORM_ITEM_TYPE_LIST = (
|
verbose_name="数据options", help_text="数据options", null=True, blank=True
|
||||||
(0, 'text'),
|
)
|
||||||
(1, 'datetime'),
|
FORM_ITEM_TYPE_LIST = (
|
||||||
(2, 'date'),
|
(0, "text"),
|
||||||
(3, 'textarea'),
|
(1, "datetime"),
|
||||||
(4, 'select'),
|
(2, "date"),
|
||||||
(5, 'checkbox'),
|
(3, "textarea"),
|
||||||
(6, 'radio'),
|
(4, "select"),
|
||||||
(7, 'img'),
|
(5, "checkbox"),
|
||||||
(8, 'file'),
|
(6, "radio"),
|
||||||
(9, 'switch'),
|
(7, "img"),
|
||||||
(10, 'number'),
|
(8, "file"),
|
||||||
(11, 'array'),
|
(9, "switch"),
|
||||||
(12, 'imgs'),
|
(10, "number"),
|
||||||
(13, 'foreignkey'),
|
(11, "array"),
|
||||||
(14, 'manytomany'),
|
(12, "imgs"),
|
||||||
(15, 'time'),
|
(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="配置")
|
setting = models.JSONField(null=True, blank=True, verbose_name="配置", help_text="配置")
|
||||||
|
|
||||||
|
node_order_by = ["sort", "title", "key"]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = table_prefix + "system_config"
|
db_table = table_prefix + "system_config"
|
||||||
verbose_name = '系统配置表'
|
verbose_name = "系统配置表"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('sort',)
|
ordering = ("sort",)
|
||||||
unique_together = (("key", "parent_id"),)
|
unique_together = (("key", "parent_id"),)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.title}"
|
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)
|
super().save(force_insert, force_update, using, update_fields)
|
||||||
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
||||||
|
|
||||||
|
|
||||||
class LoginLog(CoreModel):
|
class LoginLog(CoreModel):
|
||||||
LOGIN_TYPE_CHOICES = (
|
LOGIN_TYPE_CHOICES = ((1, "普通登录"),)
|
||||||
(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:
|
class Meta:
|
||||||
db_table = table_prefix + 'system_login_log'
|
db_table = table_prefix + "system_login_log"
|
||||||
verbose_name = '登录日志'
|
verbose_name = "登录日志"
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
ordering = ('-create_datetime',)
|
ordering = ("-create_datetime",)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
@Remark: 字典管理
|
@Remark: 字典管理
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from rest_framework import serializers
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from application import dispatch
|
from application import dispatch
|
||||||
|
@ -34,7 +35,7 @@ class DictionaryCreateUpdateSerializer(CustomModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Dictionary
|
model = Dictionary
|
||||||
fields = '__all__'
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class DictionaryViewSet(CustomModelViewSet):
|
class DictionaryViewSet(CustomModelViewSet):
|
||||||
|
@ -46,30 +47,46 @@ class DictionaryViewSet(CustomModelViewSet):
|
||||||
retrieve:单例
|
retrieve:单例
|
||||||
destroy:删除
|
destroy:删除
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = Dictionary.objects.all()
|
queryset = Dictionary.objects.all()
|
||||||
serializer_class = DictionarySerializer
|
serializer_class = DictionarySerializer
|
||||||
extra_filter_backends = []
|
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):
|
class InitDictionaryViewSet(APIView):
|
||||||
"""
|
"""
|
||||||
获取初始化配置
|
获取初始化配置
|
||||||
"""
|
"""
|
||||||
|
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
queryset = Dictionary.objects.all()
|
queryset = Dictionary.objects.all()
|
||||||
|
|
||||||
def get(self, request):
|
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:
|
||||||
if dictionary_key == 'all':
|
if dictionary_key == "all":
|
||||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||||
if not data:
|
if not data:
|
||||||
dispatch.refresh_dictionary()
|
dispatch.refresh_dictionary()
|
||||||
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
data = [ele for ele in dispatch.get_dictionary_config().values()]
|
||||||
else:
|
else:
|
||||||
data = self.queryset.filter(parent__value=dictionary_key, status=True).values('label', 'value', 'type',
|
# data = self.queryset.filter(
|
||||||
'color')
|
# 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=data, msg="获取成功")
|
||||||
return SuccessResponse(data=[], msg="获取成功")
|
return SuccessResponse(data=[], msg="获取成功")
|
||||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework import serializers
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
|
||||||
from dvadmin.system.models import Menu, MenuButton, Button
|
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.serializers import CustomModelSerializer
|
||||||
from dvadmin.utils.viewset import CustomModelViewSet
|
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)
|
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):
|
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:
|
if queryset:
|
||||||
return queryset
|
return queryset
|
||||||
else:
|
else:
|
||||||
|
@ -38,6 +47,7 @@ class MenuCreateSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
菜单表的创建序列化器
|
菜单表的创建序列化器
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = serializers.CharField(required=False)
|
name = serializers.CharField(required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -50,18 +60,25 @@ class WebRouterSerializer(CustomModelSerializer):
|
||||||
"""
|
"""
|
||||||
前端菜单路由的简单序列化器
|
前端菜单路由的简单序列化器
|
||||||
"""
|
"""
|
||||||
|
|
||||||
path = serializers.CharField(source="web_path")
|
path = serializers.CharField(source="web_path")
|
||||||
title = serializers.CharField(source="name")
|
title = serializers.CharField(source="name")
|
||||||
|
parent = serializers.SerializerMethodField(read_only=True)
|
||||||
menuPermission = 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):
|
def get_menuPermission(self, instance):
|
||||||
# 判断是否是超级管理员
|
# 判断是否是超级管理员
|
||||||
if self.request.user.is_superuser:
|
if self.request.user.is_superuser:
|
||||||
return Button.objects.values_list('value', flat=True)
|
return Button.objects.values_list("value", flat=True)
|
||||||
else:
|
else:
|
||||||
# 根据当前角色获取权限按钮id集合
|
# 根据当前角色获取权限按钮id集合
|
||||||
permissionIds = self.request.user.role.values_list('permission', 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)
|
queryset = MenuButton.objects.filter(
|
||||||
|
id__in=permissionIds, menu=instance.id
|
||||||
|
).values_list("value", flat=True)
|
||||||
if queryset:
|
if queryset:
|
||||||
return queryset
|
return queryset
|
||||||
else:
|
else:
|
||||||
|
@ -82,22 +99,30 @@ class MenuViewSet(CustomModelViewSet):
|
||||||
retrieve:单例
|
retrieve:单例
|
||||||
destroy:删除
|
destroy:删除
|
||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = Menu.objects.all()
|
queryset = Menu.objects.all()
|
||||||
serializer_class = MenuSerializer
|
serializer_class = MenuSerializer
|
||||||
create_serializer_class = MenuCreateSerializer
|
create_serializer_class = MenuCreateSerializer
|
||||||
update_serializer_class = MenuCreateSerializer
|
update_serializer_class = MenuCreateSerializer
|
||||||
search_fields = ['name', 'status']
|
search_fields = ["name", "status"]
|
||||||
filter_fields = ['parent','name', 'status','is_link','visible','cache','is_catalog']
|
filter_fields = [
|
||||||
|
"name",
|
||||||
|
"status",
|
||||||
|
"is_link",
|
||||||
|
"visible",
|
||||||
|
"cache",
|
||||||
|
"is_catalog",
|
||||||
|
]
|
||||||
extra_filter_backends = []
|
extra_filter_backends = []
|
||||||
|
|
||||||
@action(methods=['GET'], detail=True, permission_classes=[])
|
@action(methods=["GET"], detail=True, permission_classes=[])
|
||||||
def web_router(self, request):
|
def web_router(self, request):
|
||||||
"""用于前端获取当前角色的路由"""
|
"""用于前端获取当前角色的路由"""
|
||||||
user = request.user
|
user = request.user
|
||||||
queryset = self.queryset.filter(status=1)
|
queryset = self.queryset.filter(status=1)
|
||||||
if not user.is_superuser:
|
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)
|
queryset = Menu.objects.filter(id__in=menuIds, status=1)
|
||||||
serializer = WebRouterSerializer(queryset, many=True, request=request)
|
serializer = WebRouterSerializer(queryset, many=True, request=request)
|
||||||
data = serializer.data
|
data = serializer.data
|
||||||
return SuccessResponse(data=data,total=len(data),msg="获取成功")
|
return SuccessResponse(data=data, total=len(data), msg="获取成功")
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# 初始化基类
|
# 初始化基类
|
||||||
from application import settings
|
from application import settings
|
||||||
|
from treebeard.mp_tree import MP_Node
|
||||||
|
|
||||||
|
|
||||||
class CoreInitialize:
|
class CoreInitialize:
|
||||||
"""
|
"""
|
||||||
使用方法:继承此类,重写 run方法,在 run 中调用 save 进行数据初始化
|
使用方法:继承此类,重写 run方法,在 run 中调用 save 进行数据初始化
|
||||||
"""
|
"""
|
||||||
|
|
||||||
creator_id = None
|
creator_id = None
|
||||||
reset = False
|
reset = False
|
||||||
|
|
||||||
|
@ -26,26 +28,33 @@ class CoreInitialize:
|
||||||
settings.INITIALIZE_RESET_LIST.append(obj)
|
settings.INITIALIZE_RESET_LIST.append(obj)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
for ele in data:
|
if MP_Node in obj.__mro__:
|
||||||
m2m_dict = {}
|
obj.load_bulk(data, None, True)
|
||||||
new_data = {}
|
else:
|
||||||
for key, value in ele.items():
|
for ele in data:
|
||||||
# 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新
|
m2m_dict = {}
|
||||||
if isinstance(value, list) and value and isinstance(value[0], int):
|
new_data = {}
|
||||||
m2m_dict[key] = value
|
for key, value in ele.items():
|
||||||
else:
|
# 判断传的 value 为 list 的多对多进行抽离,使用set 进行更新
|
||||||
new_data[key] = value
|
if isinstance(value, list) and value and isinstance(value[0], int):
|
||||||
object, _ = obj.objects.get_or_create(id=ele.get("id"), defaults=new_data)
|
m2m_dict[key] = value
|
||||||
for key, m2m in m2m_dict.items():
|
else:
|
||||||
m2m = list(set(m2m))
|
new_data[key] = value
|
||||||
if m2m and len(m2m) > 0 and m2m[0]:
|
object, _ = obj.objects.get_or_create(
|
||||||
exec(f"""
|
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"""
|
||||||
if object.{key}:
|
if object.{key}:
|
||||||
values_list = object.{key}.all().values_list('id', flat=True)
|
values_list = object.{key}.all().values_list('id', flat=True)
|
||||||
values_list = list(set(list(values_list) + {m2m}))
|
values_list = list(set(list(values_list) + {m2m}))
|
||||||
object.{key}.set(values_list)
|
object.{key}.set(values_list)
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
print(f"初始化完成[{obj._meta.label} => {name}]")
|
print(f"初始化完成[{obj._meta.label} => {name}]")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
raise NotImplementedError('.run() must be overridden')
|
raise NotImplementedError(".run() must be overridden")
|
||||||
|
|
|
@ -23,6 +23,10 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||||
(1)self.request能获取到rest_framework.request.Request对象
|
(1)self.request能获取到rest_framework.request.Request对象
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# 放空treebeard.mp_tree.MP_Node的继承字段
|
||||||
|
path = serializers.CharField(required=False)
|
||||||
|
depth = serializers.IntegerField(required=False)
|
||||||
|
|
||||||
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
||||||
modifier_field_id = "modifier"
|
modifier_field_id = "modifier"
|
||||||
modifier_name = serializers.SerializerMethodField(read_only=True)
|
modifier_name = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
|
@ -14,12 +14,19 @@ from rest_framework.decorators import action
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from dvadmin.utils.filters import DataLevelPermissionsFilter
|
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.json_response import SuccessResponse, ErrorResponse, DetailResponse
|
||||||
from dvadmin.utils.permission import CustomPermission
|
from dvadmin.utils.permission import CustomPermission
|
||||||
from django_restql.mixins import QueryArgumentsMixin
|
from django_restql.mixins import QueryArgumentsMixin
|
||||||
|
from treebeard.models import Node
|
||||||
|
|
||||||
class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixin,QueryArgumentsMixin):
|
|
||||||
|
class CustomModelViewSet(
|
||||||
|
ModelViewSet, ImportSerializerMixin, ExportSerializerMixin, QueryArgumentsMixin
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
自定义的ModelViewSet:
|
自定义的ModelViewSet:
|
||||||
统一标准的返回格式;新增,查询,修改可使用不同序列化器
|
统一标准的返回格式;新增,查询,修改可使用不同序列化器
|
||||||
|
@ -29,11 +36,12 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
||||||
(4)import_field_dict={} 导入时的字段字典 {model值: model的label}
|
(4)import_field_dict={} 导入时的字段字典 {model值: model的label}
|
||||||
(5)export_field_label = [] 导出时的字段
|
(5)export_field_label = [] 导出时的字段
|
||||||
"""
|
"""
|
||||||
|
|
||||||
values_queryset = None
|
values_queryset = None
|
||||||
ordering_fields = '__all__'
|
ordering_fields = "__all__"
|
||||||
create_serializer_class = None
|
create_serializer_class = None
|
||||||
update_serializer_class = None
|
update_serializer_class = None
|
||||||
filter_fields = '__all__'
|
filter_fields = "__all__"
|
||||||
search_fields = ()
|
search_fields = ()
|
||||||
extra_filter_backends = [DataLevelPermissionsFilter]
|
extra_filter_backends = [DataLevelPermissionsFilter]
|
||||||
permission_classes = [CustomPermission]
|
permission_classes = [CustomPermission]
|
||||||
|
@ -41,12 +49,14 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
||||||
export_field_label = []
|
export_field_label = []
|
||||||
|
|
||||||
def filter_queryset(self, queryset):
|
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)
|
queryset = backend().filter_queryset(self.request, queryset, self)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if getattr(self, 'values_queryset', None):
|
if getattr(self, "values_queryset", None):
|
||||||
return self.values_queryset
|
return self.values_queryset
|
||||||
return super().get_queryset()
|
return super().get_queryset()
|
||||||
|
|
||||||
|
@ -60,6 +70,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
serializer = self.get_serializer(data=request.data, request=request)
|
serializer = self.get_serializer(data=request.data, request=request)
|
||||||
serializer.is_valid(raise_exception=True)
|
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)
|
self.perform_create(serializer)
|
||||||
return DetailResponse(data=serializer.data, msg="新增成功")
|
return DetailResponse(data=serializer.data, msg="新增成功")
|
||||||
|
|
||||||
|
@ -78,13 +97,15 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
||||||
return DetailResponse(data=serializer.data, msg="获取成功")
|
return DetailResponse(data=serializer.data, msg="获取成功")
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
def update(self, request, *args, **kwargs):
|
||||||
partial = kwargs.pop('partial', False)
|
partial = kwargs.pop("partial", False)
|
||||||
instance = self.get_object()
|
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)
|
serializer.is_valid(raise_exception=True)
|
||||||
self.perform_update(serializer)
|
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
|
# If 'prefetch_related' has been applied to a queryset, we need to
|
||||||
# forcibly invalidate the prefetch cache on the instance.
|
# forcibly invalidate the prefetch cache on the instance.
|
||||||
instance._prefetched_objects_cache = {}
|
instance._prefetched_objects_cache = {}
|
||||||
|
@ -95,17 +116,20 @@ class CustomModelViewSet(ModelViewSet,ImportSerializerMixin,ExportSerializerMixi
|
||||||
self.perform_destroy(instance)
|
self.perform_destroy(instance)
|
||||||
return DetailResponse(data=[], msg="删除成功")
|
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(
|
||||||
@swagger_auto_schema(request_body=openapi.Schema(
|
request_body=openapi.Schema(
|
||||||
type=openapi.TYPE_OBJECT,
|
type=openapi.TYPE_OBJECT, required=["keys"], properties={"keys": keys}
|
||||||
required=['keys'],
|
),
|
||||||
properties={'keys': keys}
|
operation_summary="批量删除",
|
||||||
), operation_summary='批量删除')
|
)
|
||||||
@action(methods=['delete'],detail=False)
|
@action(methods=["delete"], detail=False)
|
||||||
def multiple_delete(self,request,*args,**kwargs):
|
def multiple_delete(self, request, *args, **kwargs):
|
||||||
request_data = request.data
|
request_data = request.data
|
||||||
keys = request_data.get('keys',None)
|
keys = request_data.get("keys", None)
|
||||||
if keys:
|
if keys:
|
||||||
self.get_queryset().filter(id__in=keys).delete()
|
self.get_queryset().filter(id__in=keys).delete()
|
||||||
return SuccessResponse(data=[], msg="删除成功")
|
return SuccessResponse(data=[], msg="删除成功")
|
||||||
|
|
|
@ -393,7 +393,7 @@ export const crudOptions = (vm) => {
|
||||||
search: {
|
search: {
|
||||||
disabled: false
|
disabled: false
|
||||||
},
|
},
|
||||||
width: 50,
|
width: 60,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
dict: {
|
dict: {
|
||||||
data: vm.dictionary('button_whether_bool')
|
data: vm.dictionary('button_whether_bool')
|
||||||
|
|
824
web/yarn.lock
824
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue