init
This commit is contained in:
commit
345da7ed48
5
application/__init__.py
Normal file
5
application/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
BIN
application/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
application/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/celery.cpython-311.pyc
Normal file
BIN
application/__pycache__/celery.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/dispatch.cpython-311.pyc
Normal file
BIN
application/__pycache__/dispatch.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/settings.cpython-311.pyc
Normal file
BIN
application/__pycache__/settings.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/sse_views.cpython-311.pyc
Normal file
BIN
application/__pycache__/sse_views.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/urls.cpython-311.pyc
Normal file
BIN
application/__pycache__/urls.cpython-311.pyc
Normal file
Binary file not shown.
BIN
application/__pycache__/wsgi.cpython-311.pyc
Normal file
BIN
application/__pycache__/wsgi.cpython-311.pyc
Normal file
Binary file not shown.
21
application/asgi.py
Normal file
21
application/asgi.py
Normal file
@ -0,0 +1,21 @@
|
||||
"""
|
||||
ASGI config for application project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
from channels.routing import ProtocolTypeRouter
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
http_application = get_asgi_application()
|
||||
|
||||
application = ProtocolTypeRouter({
|
||||
"http": http_application,
|
||||
})
|
||||
51
application/celery.py
Normal file
51
application/celery.py
Normal file
@ -0,0 +1,51 @@
|
||||
import functools
|
||||
import os
|
||||
|
||||
from celery.signals import task_postrun
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
|
||||
from django.conf import settings
|
||||
from celery import platforms
|
||||
|
||||
# 租户模式
|
||||
if "django_tenants" in settings.INSTALLED_APPS:
|
||||
from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp
|
||||
|
||||
app = TenantAwareCeleryApp()
|
||||
else:
|
||||
from celery import Celery
|
||||
|
||||
app = Celery(f"application")
|
||||
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
||||
platforms.C_FORCE_ROOT = True
|
||||
|
||||
|
||||
def retry_base_task_error():
|
||||
"""
|
||||
celery 失败重试装饰器
|
||||
:return:
|
||||
"""
|
||||
|
||||
def wraps(func):
|
||||
@app.task(bind=True, retry_delay=180, max_retries=3)
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as exc:
|
||||
raise self.retry(exc=exc)
|
||||
|
||||
return wrapper
|
||||
|
||||
return wraps
|
||||
|
||||
|
||||
@task_postrun.connect
|
||||
def add_periodic_task_name(sender, task_id, task, args, kwargs, **extras):
|
||||
periodic_task_name = kwargs.get('periodic_task_name')
|
||||
if periodic_task_name:
|
||||
from django_celery_results.models import TaskResult
|
||||
# 更新 TaskResult 表中的 periodic_task_name 字段
|
||||
TaskResult.objects.filter(task_id=task_id).update(periodic_task_name=periodic_task_name)
|
||||
275
application/dispatch.py
Normal file
275
application/dispatch.py
Normal file
@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
from django.core.cache import cache
|
||||
from dvadmin.utils.validator import CustomValidationError
|
||||
|
||||
dispatch_db_type = getattr(settings, 'DISPATCH_DB_TYPE', 'memory') # redis
|
||||
|
||||
|
||||
def is_tenants_mode():
|
||||
"""
|
||||
判断是否为租户模式
|
||||
:return:
|
||||
"""
|
||||
return hasattr(connection, "tenant") and connection.tenant.schema_name
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 初始化 ******************** #
|
||||
# ================================================= #
|
||||
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(
|
||||
{
|
||||
"id": instance.id,
|
||||
"value": instance.value,
|
||||
"children": list(
|
||||
Dictionary.objects.filter(parent=instance.id)
|
||||
.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(parent_id__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", "")
|
||||
if value and system_config.get("form_item_type") == 7:
|
||||
value = value[0].get("url")
|
||||
if value and system_config.get("form_item_type") == 11:
|
||||
new_value = []
|
||||
for ele in value:
|
||||
new_value.append({
|
||||
"key": ele.get('key'),
|
||||
"title": ele.get('title'),
|
||||
"value": ele.get('value'),
|
||||
})
|
||||
new_value.sort(key=lambda s: s["key"])
|
||||
value = new_value
|
||||
data[f"{system_config.get('parent__key')}.{system_config.get('key')}"] = value
|
||||
return data
|
||||
|
||||
|
||||
def init_dictionary():
|
||||
"""
|
||||
初始化字典配置
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if dispatch_db_type == 'redis':
|
||||
cache.set(f"init_dictionary", _get_all_dictionary())
|
||||
return
|
||||
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()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
except Exception as e:
|
||||
print("请先进行数据库迁移!")
|
||||
return
|
||||
|
||||
|
||||
def init_system_config():
|
||||
"""
|
||||
初始化系统配置
|
||||
:param name:
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
if dispatch_db_type == 'redis':
|
||||
cache.set(f"init_system_config", _get_all_system_config())
|
||||
return
|
||||
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()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
except Exception as e:
|
||||
print("请先进行数据库迁移!")
|
||||
return
|
||||
|
||||
|
||||
def refresh_dictionary():
|
||||
"""
|
||||
刷新字典配置
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
cache.set(f"init_dictionary", _get_all_dictionary())
|
||||
return
|
||||
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()
|
||||
else:
|
||||
settings.DICTIONARY_CONFIG = _get_all_dictionary()
|
||||
|
||||
|
||||
def refresh_system_config():
|
||||
"""
|
||||
刷新系统配置
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
cache.set(f"init_system_config", _get_all_system_config())
|
||||
return
|
||||
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()
|
||||
else:
|
||||
settings.SYSTEM_CONFIG = _get_all_system_config()
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 字典管理 ******************** #
|
||||
# ================================================= #
|
||||
def get_dictionary_config(schema_name=None):
|
||||
"""
|
||||
获取字典所有配置
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
init_dictionary_data = cache.get(f"init_dictionary")
|
||||
if not init_dictionary_data:
|
||||
refresh_dictionary()
|
||||
return cache.get(f"init_dictionary") or {}
|
||||
if not settings.DICTIONARY_CONFIG:
|
||||
refresh_dictionary()
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.DICTIONARY_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
else:
|
||||
dictionary_config = settings.DICTIONARY_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
||||
|
||||
def get_dictionary_values(key, schema_name=None):
|
||||
"""
|
||||
获取字典数据数组
|
||||
:param key: 对应字典配置的key值(字典编号)
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
dictionary_config = cache.get(f"init_dictionary")
|
||||
if not dictionary_config:
|
||||
refresh_dictionary()
|
||||
dictionary_config = cache.get(f"init_dictionary")
|
||||
return dictionary_config.get(key)
|
||||
dictionary_config = get_dictionary_config(schema_name)
|
||||
return dictionary_config.get(key)
|
||||
|
||||
|
||||
def get_dictionary_label(key, name, schema_name=None):
|
||||
"""
|
||||
获取获取字典label值
|
||||
:param key: 字典管理中的key值(字典编号)
|
||||
:param name: 对应字典配置的value值
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
res = get_dictionary_values(key, schema_name) or []
|
||||
for ele in res.get('children'):
|
||||
if ele.get("value") == str(name):
|
||||
return ele.get("label")
|
||||
return ""
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 系统配置 ******************** #
|
||||
# ================================================= #
|
||||
def get_system_config(schema_name=None):
|
||||
"""
|
||||
获取系统配置中所有配置
|
||||
1.只传父级的key,返回全部子级,{ "父级key.子级key" : "值" }
|
||||
2."父级key.子级key",返回子级值
|
||||
:param schema_name: 对应字典配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
init_dictionary_data = cache.get(f"init_system_config")
|
||||
if not init_dictionary_data:
|
||||
refresh_system_config()
|
||||
return cache.get(f"init_system_config") or {}
|
||||
if not settings.SYSTEM_CONFIG:
|
||||
refresh_system_config()
|
||||
if is_tenants_mode():
|
||||
dictionary_config = settings.SYSTEM_CONFIG[schema_name or connection.tenant.schema_name]
|
||||
else:
|
||||
dictionary_config = settings.SYSTEM_CONFIG
|
||||
return dictionary_config or {}
|
||||
|
||||
|
||||
def get_system_config_values(key, schema_name=None):
|
||||
"""
|
||||
获取系统配置数据数组
|
||||
:param key: 对应系统配置的key值(字典编号)
|
||||
:param schema_name: 对应系统配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
if dispatch_db_type == 'redis':
|
||||
system_config = cache.get(f"init_system_config")
|
||||
if not system_config:
|
||||
refresh_system_config()
|
||||
system_config = cache.get(f"init_system_config")
|
||||
return system_config.get(key)
|
||||
system_config = get_system_config(schema_name)
|
||||
return system_config.get(key)
|
||||
|
||||
|
||||
def get_system_config_values_to_dict(key, schema_name=None):
|
||||
"""
|
||||
获取系统配置数据并转换为字典 **仅限于数组类型系统配置
|
||||
:param key: 对应系统配置的key值(字典编号)
|
||||
:param schema_name: 对应系统配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
values_dict = {}
|
||||
config_values = get_system_config_values(key, schema_name)
|
||||
if not isinstance(config_values, list):
|
||||
raise CustomValidationError("该方式仅限于数组类型系统配置")
|
||||
for ele in get_system_config_values(key, schema_name):
|
||||
values_dict[ele.get('key')] = ele.get('value')
|
||||
return values_dict
|
||||
|
||||
|
||||
def get_system_config_label(key, name, schema_name=None):
|
||||
"""
|
||||
获取获取系统配置label值
|
||||
:param key: 系统配置中的key值(字典编号)
|
||||
:param name: 对应系统配置的value值
|
||||
:param schema_name: 对应系统配置的租户schema_name值
|
||||
:return:
|
||||
"""
|
||||
children = get_system_config_values(key, schema_name) or []
|
||||
for ele in children:
|
||||
if ele.get("value") == str(name):
|
||||
return ele.get("label")
|
||||
return ""
|
||||
425
application/settings.py
Normal file
425
application/settings.py
Normal file
@ -0,0 +1,425 @@
|
||||
"""
|
||||
Django settings for application project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.2.3.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import timedelta
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 动态配置 ******************** #
|
||||
# ================================================= #
|
||||
|
||||
from conf.env import *
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "django-insecure--z8%exyzt7e_%i@1+#1mm=%lb5=^fx_57=1@a+_y7bg5-w%)sm"
|
||||
# 初始化plugins插件路径到环境变量中
|
||||
PLUGINS_PATH = os.path.join(BASE_DIR, "plugins")
|
||||
sys.path.insert(0, os.path.join(PLUGINS_PATH))
|
||||
|
||||
[
|
||||
sys.path.insert(0, os.path.join(PLUGINS_PATH, ele))
|
||||
for ele in os.listdir(PLUGINS_PATH)
|
||||
if os.path.isdir(os.path.join(PLUGINS_PATH, ele)) and not ele.startswith("__")
|
||||
]
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = locals().get("DEBUG", True)
|
||||
ALLOWED_HOSTS = locals().get("ALLOWED_HOSTS", ["*"])
|
||||
|
||||
# 列权限需要排除的App应用
|
||||
COLUMN_EXCLUDE_APPS = ['channels', 'captcha'] + locals().get("COLUMN_EXCLUDE_APPS", [])
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_comment_migrate",
|
||||
"rest_framework",
|
||||
"django_filters",
|
||||
"corsheaders", # 注册跨域app
|
||||
"drf_yasg",
|
||||
"captcha",
|
||||
"channels",
|
||||
"dvadmin.system",
|
||||
# "django_tenants",
|
||||
]
|
||||
|
||||
My_Apps = [
|
||||
'crud_book', #新的应用写在这里
|
||||
]
|
||||
|
||||
INSTALLED_APPS += My_Apps
|
||||
|
||||
MIDDLEWARE = [
|
||||
"dvadmin.utils.middleware.HealthCheckMiddleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"corsheaders.middleware.CorsMiddleware", # 跨域中间件
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"dvadmin.utils.middleware.ApiLoggingMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "application.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [os.path.join(BASE_DIR, "templates")],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "application.wsgi.application"
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": DATABASE_ENGINE,
|
||||
"NAME": DATABASE_NAME,
|
||||
"USER": DATABASE_USER,
|
||||
"PASSWORD": DATABASE_PASSWORD,
|
||||
"HOST": DATABASE_HOST,
|
||||
"PORT": DATABASE_PORT,
|
||||
}
|
||||
}
|
||||
AUTH_USER_MODEL = "system.Users"
|
||||
USERNAME_FIELD = "username"
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "zh-hans"
|
||||
|
||||
TIME_ZONE = "Asia/Shanghai"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = False
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_URL = "/static/"
|
||||
# # 设置django的静态文件目录
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, "static"),
|
||||
]
|
||||
|
||||
MEDIA_ROOT = "media" # 项目下的目录
|
||||
MEDIA_URL = "/media/" # 跟STATIC_URL类似,指定用户可以通过这个url找到文件
|
||||
|
||||
#添加以下代码以后就不用写{% load staticfiles %},可以直接引用
|
||||
STATICFILES_FINDERS = (
|
||||
"django.contrib.staticfiles.finders.FileSystemFinder",
|
||||
"django.contrib.staticfiles.finders.AppDirectoriesFinder"
|
||||
)
|
||||
# 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
|
||||
# python manage.py collectstatic
|
||||
# STATIC_ROOT=os.path.join(BASE_DIR,'static')
|
||||
|
||||
# ================================================= #
|
||||
# ******************* 跨域的配置 ******************* #
|
||||
# ================================================= #
|
||||
|
||||
# 全部允许配置
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
# 允许cookie
|
||||
CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中,后端是否支持对cookie的操作
|
||||
|
||||
# ===================================================== #
|
||||
# ********************* channels配置 ******************* #
|
||||
# ===================================================== #
|
||||
ASGI_APPLICATION = 'application.asgi.application'
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "channels.layers.InMemoryChannelLayer"
|
||||
}
|
||||
}
|
||||
# CHANNEL_LAYERS = {
|
||||
# 'default': {
|
||||
# 'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||
# 'CONFIG': {
|
||||
# "hosts": [('127.0.0.1', 6379)], #需修改
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
|
||||
|
||||
# ================================================= #
|
||||
# ********************* 日志配置 ******************* #
|
||||
# ================================================= #
|
||||
# # log 配置部分BEGIN #
|
||||
SERVER_LOGS_FILE = os.path.join(BASE_DIR, "logs", "server.log")
|
||||
ERROR_LOGS_FILE = os.path.join(BASE_DIR, "logs", "error.log")
|
||||
LOGS_FILE = os.path.join(BASE_DIR, "logs")
|
||||
if not os.path.exists(os.path.join(BASE_DIR, "logs")):
|
||||
os.makedirs(os.path.join(BASE_DIR, "logs"))
|
||||
|
||||
# 格式:[2020-04-22 23:33:01][micoservice.apps.ready():16] [INFO] 这是一条日志:
|
||||
# 格式:[日期][模块.函数名称():行号] [级别] 信息
|
||||
STANDARD_LOG_FORMAT = (
|
||||
"[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s"
|
||||
)
|
||||
CONSOLE_LOG_FORMAT = (
|
||||
"[%(asctime)s][%(name)s.%(funcName)s():%(lineno)d] [%(levelname)s] %(message)s"
|
||||
)
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"formatters": {
|
||||
"standard": {"format": STANDARD_LOG_FORMAT},
|
||||
"console": {
|
||||
"format": CONSOLE_LOG_FORMAT,
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
"file": {
|
||||
"format": CONSOLE_LOG_FORMAT,
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "INFO",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": SERVER_LOGS_FILE,
|
||||
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||
"backupCount": 5, # 最多备份5个
|
||||
"formatter": "standard",
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
"error": {
|
||||
"level": "ERROR",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": ERROR_LOGS_FILE,
|
||||
"maxBytes": 1024 * 1024 * 100, # 100 MB
|
||||
"backupCount": 3, # 最多备份3个
|
||||
"formatter": "standard",
|
||||
"encoding": "utf-8",
|
||||
},
|
||||
"console": {
|
||||
"level": "INFO",
|
||||
"class": "logging.StreamHandler",
|
||||
"formatter": "console",
|
||||
},
|
||||
|
||||
},
|
||||
"loggers": {
|
||||
"": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO",
|
||||
},
|
||||
"django": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO",
|
||||
"propagate": False,
|
||||
},
|
||||
'django.db.backends': {
|
||||
'handlers': ["console", "error", "file"],
|
||||
'propagate': False,
|
||||
'level': "INFO"
|
||||
},
|
||||
"uvicorn.error": {
|
||||
"level": "INFO",
|
||||
"handlers": ["console", "error", "file"],
|
||||
},
|
||||
"uvicorn.access": {
|
||||
"handlers": ["console", "error", "file"],
|
||||
"level": "INFO"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# ================================================= #
|
||||
# *************** REST_FRAMEWORK配置 *************** #
|
||||
# ================================================= #
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PARSER_CLASSES': (
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.MultiPartParser',
|
||||
),
|
||||
"DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
|
||||
"DATE_FORMAT": "%Y-%m-%d",
|
||||
"DEFAULT_FILTER_BACKENDS": (
|
||||
# 'django_filters.rest_framework.DjangoFilterBackend',
|
||||
"dvadmin.utils.filters.CustomDjangoFilterBackend",
|
||||
"rest_framework.filters.SearchFilter",
|
||||
"rest_framework.filters.OrderingFilter",
|
||||
),
|
||||
"DEFAULT_PAGINATION_CLASS": "dvadmin.utils.pagination.CustomPagination", # 自定义分页
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
),
|
||||
"DEFAULT_PERMISSION_CLASSES": [
|
||||
"rest_framework.permissions.IsAuthenticated", # 只有经过身份认证确定用户身份才能访问
|
||||
],
|
||||
"EXCEPTION_HANDLER": "dvadmin.utils.exception.CustomExceptionHandler", # 自定义的异常处理
|
||||
}
|
||||
# ================================================= #
|
||||
# ******************** 登录方式配置 ******************** #
|
||||
# ================================================= #
|
||||
|
||||
AUTHENTICATION_BACKENDS = ["dvadmin.utils.backends.CustomBackend"]
|
||||
# ================================================= #
|
||||
# ****************** simplejwt配置 ***************** #
|
||||
# ================================================= #
|
||||
SIMPLE_JWT = {
|
||||
# token有效时长
|
||||
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=1440),
|
||||
# token刷新后的有效时间
|
||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
|
||||
# 设置前缀
|
||||
"AUTH_HEADER_TYPES": ("JWT",),
|
||||
"ROTATE_REFRESH_TOKENS": True,
|
||||
}
|
||||
|
||||
# ====================================#
|
||||
# ****************swagger************#
|
||||
# ====================================#
|
||||
SWAGGER_SETTINGS = {
|
||||
# 基础样式
|
||||
"SECURITY_DEFINITIONS": {"basic": {"type": "basic"}},
|
||||
# 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
|
||||
"LOGIN_URL": "apiLogin/",
|
||||
# 'LOGIN_URL': 'rest_framework:login',
|
||||
"LOGOUT_URL": "rest_framework:logout",
|
||||
# 'DOC_EXPANSION': None,
|
||||
# 'SHOW_REQUEST_HEADERS':True,
|
||||
# 'USE_SESSION_AUTH': True,
|
||||
# 'DOC_EXPANSION': 'list',
|
||||
# 接口文档中方法列表以首字母升序排列
|
||||
"APIS_SORTER": "alpha",
|
||||
# 如果支持json提交, 则接口文档中包含json输入框
|
||||
"JSON_EDITOR": True,
|
||||
# 方法列表字母排序
|
||||
"OPERATIONS_SORTER": "alpha",
|
||||
"VALIDATOR_URL": None,
|
||||
"AUTO_SCHEMA_TYPE": 2, # 分组根据url层级分,0、1 或 2 层
|
||||
"DEFAULT_AUTO_SCHEMA_CLASS": "dvadmin.utils.swagger.CustomSwaggerAutoSchema",
|
||||
}
|
||||
|
||||
# ================================================= #
|
||||
# **************** 验证码配置 ******************* #
|
||||
# ================================================= #
|
||||
CAPTCHA_IMAGE_SIZE = (160, 46) # 设置 captcha 图片大小
|
||||
CAPTCHA_LENGTH = 4 # 字符个数
|
||||
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
|
||||
CAPTCHA_OUTPUT_FORMAT = "%(image)s %(text_field)s %(hidden_field)s "
|
||||
CAPTCHA_FONT_SIZE = 36 # 字体大小
|
||||
CAPTCHA_FOREGROUND_COLOR = "#64DAAA" # 前景色
|
||||
CAPTCHA_BACKGROUND_COLOR = "#F5F7F4" # 背景色
|
||||
CAPTCHA_NOISE_FUNCTIONS = (
|
||||
"captcha.helpers.noise_arcs", # 线
|
||||
# "captcha.helpers.noise_dots", # 点
|
||||
)
|
||||
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #字母验证码
|
||||
CAPTCHA_CHALLENGE_FUNCT = "captcha.helpers.math_challenge" # 加减乘除验证码
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 其他配置 ******************** #
|
||||
# ================================================= #
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
API_LOG_ENABLE = True
|
||||
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
|
||||
API_LOG_METHODS = ["POST", "UPDATE", "DELETE", "PUT"] # ['POST', 'DELETE']
|
||||
API_MODEL_MAP = {
|
||||
"/token/": "登录模块",
|
||||
"/api/login/": "登录模块",
|
||||
"/api/plugins_market/plugins/": "插件市场",
|
||||
}
|
||||
|
||||
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||
CELERY_TIMEZONE = "Asia/Shanghai" # celery 时区问题
|
||||
# 静态页面压缩
|
||||
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"
|
||||
|
||||
ALL_MODELS_OBJECTS = [] # 所有app models 对象
|
||||
|
||||
# 初始化需要执行的列表,用来初始化后执行
|
||||
INITIALIZE_LIST = []
|
||||
INITIALIZE_RESET_LIST = []
|
||||
# 表前缀
|
||||
TABLE_PREFIX = locals().get('TABLE_PREFIX', "")
|
||||
# 系统配置
|
||||
SYSTEM_CONFIG = {}
|
||||
# 字典配置
|
||||
DICTIONARY_CONFIG = {}
|
||||
|
||||
# ================================================= #
|
||||
# ******************** 插件配置 ******************** #
|
||||
# ================================================= #
|
||||
# 租户共享app
|
||||
TENANT_SHARED_APPS = []
|
||||
# 普通租户独有app
|
||||
TENANT_EXCLUSIVE_APPS = []
|
||||
# 插件 urlpatterns
|
||||
PLUGINS_URL_PATTERNS = []
|
||||
# 所有模式有的
|
||||
SHARED_APPS = []
|
||||
# ********** 一键导入插件配置开始 **********
|
||||
# 例如:
|
||||
# from dvadmin_upgrade_center.settings import * # 升级中心
|
||||
from dvadmin3_celery.settings import * # celery 异步任务
|
||||
# from dvadmin_third.settings import * # 第三方用户管理
|
||||
# from dvadmin_ak_sk.settings import * # 秘钥管理管理
|
||||
# from dvadmin_tenants.settings import * # 租户管理
|
||||
#from dvadmin_social_auth.settings import *
|
||||
#from dvadmin_uniapp.settings import *
|
||||
# ...
|
||||
# ********** 一键导入插件配置结束 **********
|
||||
33
application/sse_views.py
Normal file
33
application/sse_views.py
Normal file
@ -0,0 +1,33 @@
|
||||
# views.py
|
||||
import time
|
||||
|
||||
import jwt
|
||||
from django.http import StreamingHttpResponse
|
||||
|
||||
from application import settings
|
||||
from dvadmin.system.models import MessageCenterTargetUser
|
||||
from django.core.cache import cache
|
||||
|
||||
|
||||
def event_stream(user_id):
|
||||
last_sent_time = 0
|
||||
|
||||
while True:
|
||||
# 从 Redis 中获取最后数据库变更时间
|
||||
last_db_change_time = cache.get('last_db_change_time', 0)
|
||||
# 只有当数据库发生变化时才检查总数
|
||||
if last_db_change_time and last_db_change_time > last_sent_time:
|
||||
count = MessageCenterTargetUser.objects.filter(users=user_id, is_read=False).count()
|
||||
yield f"data: {count}\n\n"
|
||||
last_sent_time = time.time()
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def sse_view(request):
|
||||
token = request.GET.get('token')
|
||||
decoded = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
|
||||
user_id = decoded.get('user_id')
|
||||
response = StreamingHttpResponse(event_stream(user_id), content_type='text/event-stream')
|
||||
response['Cache-Control'] = 'no-cache'
|
||||
return response
|
||||
135
application/urls.py
Normal file
135
application/urls.py
Normal file
@ -0,0 +1,135 @@
|
||||
"""backend URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/3.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.conf.urls.static import static
|
||||
from django.urls import path, include, re_path
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.views import get_schema_view
|
||||
from rest_framework import permissions
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenRefreshView,
|
||||
)
|
||||
|
||||
from application import dispatch
|
||||
from application import settings
|
||||
from application.sse_views import sse_view
|
||||
from dvadmin.system.views.dictionary import InitDictionaryViewSet
|
||||
from dvadmin.system.views.login import (
|
||||
LoginView,
|
||||
CaptchaView,
|
||||
ApiLogin,
|
||||
LogoutView,
|
||||
LoginTokenView
|
||||
)
|
||||
from dvadmin.system.views.system_config import InitSettingsViewSet
|
||||
from dvadmin.utils.swagger import CustomOpenAPISchemaGenerator
|
||||
|
||||
# =========== 初始化系统配置 =================
|
||||
dispatch.init_system_config()
|
||||
dispatch.init_dictionary()
|
||||
# =========== 初始化系统配置 =================
|
||||
|
||||
permission_classes = [permissions.AllowAny, ] if settings.DEBUG else [permissions.IsAuthenticated, ]
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(
|
||||
title="Snippets API",
|
||||
default_version="v1",
|
||||
description="Test description",
|
||||
terms_of_service="https://www.google.com/policies/terms/",
|
||||
contact=openapi.Contact(email="contact@snippets.local"),
|
||||
license=openapi.License(name="BSD License"),
|
||||
),
|
||||
public=True,
|
||||
permission_classes=permission_classes,
|
||||
generator_class=CustomOpenAPISchemaGenerator,
|
||||
)
|
||||
# 前端页面映射
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import render
|
||||
import mimetypes
|
||||
import os
|
||||
|
||||
|
||||
def web_view(request):
|
||||
return render(request, 'web/index.html')
|
||||
|
||||
|
||||
def serve_web_files(request, filename):
|
||||
# 设定文件路径
|
||||
filepath = os.path.join(settings.BASE_DIR, 'templates', 'web', filename)
|
||||
|
||||
# 检查文件是否存在
|
||||
if not os.path.exists(filepath):
|
||||
raise Http404("File does not exist")
|
||||
|
||||
# 根据文件扩展名,确定 MIME 类型
|
||||
mime_type, _ = mimetypes.guess_type(filepath)
|
||||
|
||||
# 打开文件并读取内容
|
||||
with open(filepath, 'rb') as f:
|
||||
response = HttpResponse(f.read(), content_type=mime_type)
|
||||
return response
|
||||
|
||||
|
||||
urlpatterns = (
|
||||
[
|
||||
re_path(
|
||||
r"^swagger(?P<format>\.json|\.yaml)$",
|
||||
schema_view.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path(
|
||||
"",
|
||||
schema_view.with_ui("swagger", cache_timeout=0),
|
||||
name="schema-swagger-ui",
|
||||
),
|
||||
path(
|
||||
r"redoc/",
|
||||
schema_view.with_ui("redoc", cache_timeout=0),
|
||||
name="schema-redoc",
|
||||
),
|
||||
path("api/system/", include("dvadmin.system.urls")),
|
||||
path("api/login/", LoginView.as_view(), name="token_obtain_pair"),
|
||||
path("api/logout/", LogoutView.as_view(), name="token_obtain_pair"),
|
||||
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
re_path(
|
||||
r"^api-auth/", include("rest_framework.urls", namespace="rest_framework")
|
||||
),
|
||||
path("api/captcha/", CaptchaView.as_view()),
|
||||
path("api/init/dictionary/", InitDictionaryViewSet.as_view()),
|
||||
path("api/init/settings/", InitSettingsViewSet.as_view()),
|
||||
path("apiLogin/", ApiLogin.as_view()),
|
||||
|
||||
# 仅用于开发,上线需关闭
|
||||
path("api/token/", LoginTokenView.as_view()),
|
||||
# 前端页面映射
|
||||
path('web/', web_view, name='web_view'),
|
||||
path('web/<path:filename>', serve_web_files, name='serve_web_files'),
|
||||
# sse
|
||||
path('sse/', sse_view, name='sse'),
|
||||
]
|
||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
+ static(settings.STATIC_URL, document_root=settings.STATIC_URL)
|
||||
+ [re_path(ele.get('re_path'), include(ele.get('include'))) for ele in settings.PLUGINS_URL_PATTERNS]
|
||||
)
|
||||
|
||||
#就是添加如下内容,把自己的路由单独写出来,这样方便与dvadmin3的官方路由作区分
|
||||
My_Urls = (
|
||||
[ #这里的crud_book是指django创建的应用名称crud_book
|
||||
path('',include('crud_book.urls')),]
|
||||
)
|
||||
|
||||
# 这里把自己的路径单独出来,后面再追加在一起
|
||||
urlpatterns += My_Urls
|
||||
17
application/wsgi.py
Normal file
17
application/wsgi.py
Normal file
@ -0,0 +1,17 @@
|
||||
"""
|
||||
WSGI config for backend project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
application = get_wsgi_application()
|
||||
BIN
booksdata/Hamlet/pg1524-h.zip
Normal file
BIN
booksdata/Hamlet/pg1524-h.zip
Normal file
Binary file not shown.
BIN
booksdata/Hamlet/pg1524-images.epub
Normal file
BIN
booksdata/Hamlet/pg1524-images.epub
Normal file
Binary file not shown.
BIN
booksdata/Hamlet/pg1524.cover.medium.jpg
Normal file
BIN
booksdata/Hamlet/pg1524.cover.medium.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
conf/__pycache__/env.cpython-311.pyc
Normal file
BIN
conf/__pycache__/env.cpython-311.pyc
Normal file
Binary file not shown.
50
conf/env.example.py
Normal file
50
conf/env.example.py
Normal file
@ -0,0 +1,50 @@
|
||||
import os
|
||||
|
||||
from application.settings import BASE_DIR
|
||||
|
||||
# ================================================= #
|
||||
# *************** mysql数据库 配置 *************** #
|
||||
# ================================================= #
|
||||
# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
|
||||
# sqlite3 设置
|
||||
# DATABASE_ENGINE = "django.db.backends.sqlite3"
|
||||
# DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3")
|
||||
|
||||
# 使用mysql时,改为此配置
|
||||
DATABASE_ENGINE = "django.db.backends.mysql"
|
||||
DATABASE_NAME = 'django-vue3-admin' # mysql 时使用
|
||||
|
||||
# 数据库地址 改为自己数据库地址
|
||||
DATABASE_HOST = '127.0.0.1'
|
||||
# # 数据库端口
|
||||
DATABASE_PORT = 3306
|
||||
# # 数据库用户名
|
||||
DATABASE_USER = "root"
|
||||
# # 数据库密码
|
||||
DATABASE_PASSWORD = 'DVADMIN3'
|
||||
|
||||
# 表前缀
|
||||
TABLE_PREFIX = "dvadmin_"
|
||||
# ================================================= #
|
||||
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||
# ================================================= #
|
||||
REDIS_DB = 1
|
||||
CELERY_BROKER_DB = 3
|
||||
REDIS_PASSWORD = 'DVADMIN3'
|
||||
REDIS_HOST = '127.0.0.1'
|
||||
REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6379'
|
||||
# ================================================= #
|
||||
# ****************** 功能 启停 ******************* #
|
||||
# ================================================= #
|
||||
DEBUG = True
|
||||
# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
|
||||
ENABLE_LOGIN_ANALYSIS_LOG = True
|
||||
# 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
||||
LOGIN_NO_CAPTCHA_AUTH = True
|
||||
# ================================================= #
|
||||
# ****************** 其他 配置 ******************* #
|
||||
# ================================================= #
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
# 列权限中排除App应用
|
||||
COLUMN_EXCLUDE_APPS = []
|
||||
50
conf/env.py
Normal file
50
conf/env.py
Normal file
@ -0,0 +1,50 @@
|
||||
import os
|
||||
|
||||
from application.settings import BASE_DIR
|
||||
|
||||
# ================================================= #
|
||||
# *************** mysql数据库 配置 *************** #
|
||||
# ================================================= #
|
||||
# 数据库 ENGINE ,默认演示使用 sqlite3 数据库,正式环境建议使用 mysql 数据库
|
||||
# sqlite3 设置
|
||||
DATABASE_ENGINE = "django.db.backends.sqlite3"
|
||||
DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3")
|
||||
|
||||
# 使用mysql时,改为此配置
|
||||
#DATABASE_ENGINE = "django.db.backends.mysql"
|
||||
#DATABASE_NAME = 'django-vue3-admin' # mysql 时使用
|
||||
|
||||
# 数据库地址 改为自己数据库地址
|
||||
DATABASE_HOST = '127.0.0.1'
|
||||
# # 数据库端口
|
||||
DATABASE_PORT = 3306
|
||||
# # 数据库用户名
|
||||
DATABASE_USER = "root"
|
||||
# # 数据库密码
|
||||
DATABASE_PASSWORD = 'DVADMIN3'
|
||||
|
||||
# 表前缀
|
||||
TABLE_PREFIX = "dvadmin_"
|
||||
# ================================================= #
|
||||
# ******** redis配置,无redis 可不进行配置 ******** #
|
||||
# ================================================= #
|
||||
REDIS_DB = 1
|
||||
CELERY_BROKER_DB = 3
|
||||
REDIS_PASSWORD = 'DVADMIN3'
|
||||
REDIS_HOST = '127.0.0.1'
|
||||
REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6379'
|
||||
# ================================================= #
|
||||
# ****************** 功能 启停 ******************* #
|
||||
# ================================================= #
|
||||
DEBUG = True
|
||||
# 启动登录详细概略获取(通过调用api获取ip详细地址。如果是内网,关闭即可)
|
||||
ENABLE_LOGIN_ANALYSIS_LOG = True
|
||||
# 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消
|
||||
LOGIN_NO_CAPTCHA_AUTH = True
|
||||
# ================================================= #
|
||||
# ****************** 其他 配置 ******************* #
|
||||
# ================================================= #
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
# 列权限中排除App应用
|
||||
COLUMN_EXCLUDE_APPS = []
|
||||
0
crud_book/__init__.py
Normal file
0
crud_book/__init__.py
Normal file
BIN
crud_book/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
crud_book/__pycache__/apps.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/apps.cpython-311.pyc
Normal file
Binary file not shown.
BIN
crud_book/__pycache__/models.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/models.cpython-311.pyc
Normal file
Binary file not shown.
BIN
crud_book/__pycache__/serializers.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/serializers.cpython-311.pyc
Normal file
Binary file not shown.
BIN
crud_book/__pycache__/urls.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/urls.cpython-311.pyc
Normal file
Binary file not shown.
BIN
crud_book/__pycache__/views.cpython-311.pyc
Normal file
BIN
crud_book/__pycache__/views.cpython-311.pyc
Normal file
Binary file not shown.
3
crud_book/admin.py
Normal file
3
crud_book/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
crud_book/apps.py
Normal file
6
crud_book/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CrudBookConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'crud_book'
|
||||
52
crud_book/migrations/0001_initial.py
Normal file
52
crud_book/migrations/0001_initial.py
Normal file
@ -0,0 +1,52 @@
|
||||
# Generated by Django 4.2.14 on 2025-10-17 00:21
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CrudBookModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('title', models.CharField(max_length=255, verbose_name='书名')),
|
||||
('sub_title', models.CharField(max_length=255, verbose_name='副标题')),
|
||||
('series', models.CharField(max_length=255, verbose_name='系列丛书')),
|
||||
('author', models.CharField(max_length=255, verbose_name='作者')),
|
||||
('translator', models.CharField(max_length=255, verbose_name='译者')),
|
||||
('subject', models.CharField(max_length=255, verbose_name='学科')),
|
||||
('publisher', models.CharField(max_length=255, verbose_name='出版社')),
|
||||
('abstract', models.CharField(max_length=255, verbose_name='内容摘要')),
|
||||
('language', models.CharField(max_length=255, verbose_name='语种')),
|
||||
('edition', models.IntegerField(verbose_name='版次')),
|
||||
('isbn', models.IntegerField(verbose_name='ISBN')),
|
||||
('create_time', models.DateField(verbose_name='创建时间')),
|
||||
('create_by', models.DateField(verbose_name='创建者编号')),
|
||||
('update_time', models.DateField(verbose_name='更新时间')),
|
||||
('update_by', models.IntegerField(verbose_name='更新用户编号')),
|
||||
('image', models.ImageField(upload_to='', verbose_name='封面')),
|
||||
('location', models.CharField(max_length=255, verbose_name='存放位置')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '图书表',
|
||||
'verbose_name_plural': '图书表',
|
||||
'db_table': 'books',
|
||||
'ordering': ('-create_time',),
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,63 @@
|
||||
# Generated by Django 4.2.14 on 2025-10-19 23:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('crud_book', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='abstract',
|
||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='内容摘要'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='create_by',
|
||||
field=models.IntegerField(default=1, verbose_name='创建者编号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='edition',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='版次'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='封面'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='isbn',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='ISBN'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='location',
|
||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='存放位置'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='series',
|
||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='系列丛书'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='translator',
|
||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='译者'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='update_by',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='更新用户编号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='crudbookmodel',
|
||||
name='update_time',
|
||||
field=models.DateField(blank=True, null=True, verbose_name='更新时间'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.2.14 on 2025-10-20 20:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('crud_book', '0002_alter_crudbookmodel_abstract_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='crudbookmodel',
|
||||
options={'ordering': ('-create_datetime',), 'verbose_name': '图书表', 'verbose_name_plural': '图书表'},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='crudbookmodel',
|
||||
name='create_by',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='crudbookmodel',
|
||||
name='create_time',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='crudbookmodel',
|
||||
name='update_by',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='crudbookmodel',
|
||||
name='update_time',
|
||||
),
|
||||
]
|
||||
0
crud_book/migrations/__init__.py
Normal file
0
crud_book/migrations/__init__.py
Normal file
BIN
crud_book/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
crud_book/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
crud_book/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
crud_book/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
30
crud_book/models.py
Normal file
30
crud_book/models.py
Normal file
@ -0,0 +1,30 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
from dvadmin.utils.models import CoreModel
|
||||
|
||||
|
||||
class CrudBookModel(CoreModel):
|
||||
title = models.CharField(max_length=255, verbose_name="书名")
|
||||
sub_title = models.CharField(max_length=255, verbose_name="副标题")
|
||||
series = models.CharField(max_length=255, verbose_name="系列丛书", null=True, blank=True)
|
||||
author = models.CharField(max_length=255, verbose_name="作者")
|
||||
translator = models.CharField(max_length=255, verbose_name="译者", null=True, blank=True)
|
||||
subject = models.CharField(max_length=255, verbose_name="学科")
|
||||
publisher = models.CharField(max_length=255, verbose_name="出版社")
|
||||
abstract = models.CharField(max_length=255, verbose_name="内容摘要", null=True, blank=True)
|
||||
language = models.CharField(max_length=255, verbose_name="语种")
|
||||
edition = models.IntegerField(verbose_name="版次", null=True, blank=True)
|
||||
isbn = models.IntegerField(verbose_name="ISBN", null=True, blank=True)
|
||||
# create_time = models.DateField(verbose_name="创建时间")
|
||||
# create_by = models.IntegerField(verbose_name="创建者编号", default=1)
|
||||
# update_time = models.DateField(verbose_name="更新时间", null=True, blank=True)
|
||||
# update_by = models.IntegerField(verbose_name="更新用户编号", null=True, blank=True)
|
||||
image = models.ImageField(verbose_name="封面", null=True, blank=True)
|
||||
location = models.CharField(max_length=255, verbose_name="存放位置", null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "books"
|
||||
verbose_name = '图书表'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('-create_datetime',)
|
||||
24
crud_book/serializers.py
Normal file
24
crud_book/serializers.py
Normal file
@ -0,0 +1,24 @@
|
||||
#backend/crud_demo/serializers.py
|
||||
|
||||
from crud_book.models import CrudBookModel
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
|
||||
|
||||
class CrudBookModelSerializer(CustomModelSerializer):
|
||||
"""
|
||||
序列化器
|
||||
"""
|
||||
#这里是进行了序列化模型及所有的字段
|
||||
class Meta:
|
||||
model = CrudBookModel
|
||||
fields = "__all__"
|
||||
|
||||
#这里是创建/更新时的列化器
|
||||
class CrudBookModelCreateUpdateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
创建/更新时的列化器
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = CrudBookModel
|
||||
fields = '__all__'
|
||||
3
crud_book/tests.py
Normal file
3
crud_book/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
13
crud_book/urls.py
Normal file
13
crud_book/urls.py
Normal file
@ -0,0 +1,13 @@
|
||||
#backend/crud_demo/urls.py
|
||||
|
||||
from rest_framework.routers import SimpleRouter
|
||||
|
||||
from .views import CrudBookModelViewSet
|
||||
|
||||
router = SimpleRouter()
|
||||
# 这里进行注册路径,并把视图关联上,这里的api地址以视图名称为后缀,这样方便记忆api/CrudBookModelViewSet
|
||||
router.register("api/CrudBookModelViewSet", CrudBookModelViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
]
|
||||
urlpatterns += router.urls
|
||||
18
crud_book/views.py
Normal file
18
crud_book/views.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Create your views here.
|
||||
from crud_book.models import CrudBookModel
|
||||
from crud_book.serializers import CrudBookModelSerializer, CrudBookModelCreateUpdateSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
|
||||
class CrudBookModelViewSet(CustomModelViewSet):
|
||||
"""
|
||||
list:查询
|
||||
create:新增
|
||||
update:修改
|
||||
retrieve:单例
|
||||
destroy:删除
|
||||
"""
|
||||
queryset = CrudBookModel.objects.all()
|
||||
serializer_class = CrudBookModelSerializer
|
||||
create_serializer_class = CrudBookModelCreateUpdateSerializer
|
||||
update_serializer_class = CrudBookModelCreateUpdateSerializer
|
||||
BIN
db.sqlite3
Normal file
BIN
db.sqlite3
Normal file
Binary file not shown.
15
del_migrations.py
Normal file
15
del_migrations.py
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
|
||||
exclude = ["venv", ".venv"] # 需要排除的文件目录
|
||||
for root, dirs, files in os.walk('.'):
|
||||
dirs[:] = list(set(dirs) - set(exclude))
|
||||
if 'migrations' in dirs:
|
||||
dir = dirs[dirs.index('migrations')]
|
||||
for root_j, dirs_j, files_j in os.walk(os.path.join(root, dir)):
|
||||
for file_k in files_j:
|
||||
if file_k != '__init__.py':
|
||||
dst_file = os.path.join(root_j, file_k)
|
||||
print('删除文件>>> ', dst_file)
|
||||
os.remove(dst_file)
|
||||
5
docker_start.sh
Executable file
5
docker_start.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
# python manage.py makemigrations
|
||||
# python manage.py migrate
|
||||
# python manage.py init -y
|
||||
uvicorn application.asgi:application --port 8000 --host 0.0.0.0 --workers 4
|
||||
1
dvadmin/__init__.py
Normal file
1
dvadmin/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
BIN
dvadmin/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
0
dvadmin/system/__init__.py
Normal file
0
dvadmin/system/__init__.py
Normal file
BIN
dvadmin/system/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/__pycache__/apps.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/apps.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/__pycache__/models.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/models.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/__pycache__/signals.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/signals.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/__pycache__/tasks.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/tasks.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/__pycache__/urls.cpython-311.pyc
Normal file
BIN
dvadmin/system/__pycache__/urls.cpython-311.pyc
Normal file
Binary file not shown.
3
dvadmin/system/admin.py
Normal file
3
dvadmin/system/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
10
dvadmin/system/apps.py
Normal file
10
dvadmin/system/apps.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SystemConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'dvadmin.system'
|
||||
|
||||
def ready(self):
|
||||
# 注册信号
|
||||
import dvadmin.system.signals # 确保路径正确
|
||||
0
dvadmin/system/fixtures/__init__.py
Normal file
0
dvadmin/system/fixtures/__init__.py
Normal file
BIN
dvadmin/system/fixtures/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/system/fixtures/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
dvadmin/system/fixtures/__pycache__/initialize.cpython-311.pyc
Normal file
BIN
dvadmin/system/fixtures/__pycache__/initialize.cpython-311.pyc
Normal file
Binary file not shown.
415
dvadmin/system/fixtures/initSerializer.py
Normal file
415
dvadmin/system/fixtures/initSerializer.py
Normal file
@ -0,0 +1,415 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
import django
|
||||
|
||||
django.setup()
|
||||
from dvadmin.system.models import (
|
||||
Role, Dept, Users, Menu, MenuButton,
|
||||
ApiWhiteList, Dictionary, SystemConfig,
|
||||
RoleMenuPermission, RoleMenuButtonPermission, MenuField
|
||||
)
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
|
||||
|
||||
class UsersInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
role_key = serializers.SerializerMethodField()
|
||||
dept_key = serializers.SerializerMethodField()
|
||||
|
||||
def get_dept_key(self, obj):
|
||||
if obj.dept:
|
||||
return obj.dept.key
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_role_key(self, obj):
|
||||
if obj.role.all():
|
||||
return [role.key for role in obj.role.all()]
|
||||
else:
|
||||
return []
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
role_key = self.initial_data.get('role_key', [])
|
||||
role_ids = Role.objects.filter(key__in=role_key).values_list('id', flat=True)
|
||||
instance.role.set(role_ids)
|
||||
dept_key = self.initial_data.get('dept_key', None)
|
||||
dept_id = Dept.objects.filter(key=dept_key).first()
|
||||
instance.dept = dept_id
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Users
|
||||
fields = ["username", "email", 'mobile', 'avatar', "name", 'gender', 'user_type', "dept", 'user_type',
|
||||
'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'creator', 'dept_belong_id',
|
||||
'password', 'last_login', 'is_superuser', 'role_key' ,'dept_key']
|
||||
read_only_fields = ['id']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class MenuButtonInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化菜单按钮-序列化器
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = MenuButton
|
||||
fields = ['id', 'name', 'value', 'api', 'method', 'menu']
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class MenuFieldInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化列权限-序列化器
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = MenuField
|
||||
fields = ['id', 'menu', 'field_name', 'title', 'model']
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class MenuInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
递归深度获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
name = serializers.CharField(required=False)
|
||||
children = serializers.SerializerMethodField()
|
||||
menu_button = serializers.SerializerMethodField()
|
||||
menu_field = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Menu):
|
||||
data = []
|
||||
instance = Menu.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = MenuInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def get_menu_button(self, obj: Menu):
|
||||
data = []
|
||||
instance = obj.menuPermission.order_by('method')
|
||||
if instance:
|
||||
data = list(instance.values('name', 'value', 'api', 'method'))
|
||||
return data
|
||||
|
||||
def get_menu_field(self, obj: Menu):
|
||||
data = []
|
||||
instance = obj.menufield_set.order_by('field_name')
|
||||
if instance:
|
||||
data = list(instance.values('field_name', 'title', 'model'))
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
menu_button = self.initial_data.get('menu_button')
|
||||
menu_field = self.initial_data.get('menu_field')
|
||||
# 菜单表
|
||||
if children:
|
||||
for menu_data in children:
|
||||
menu_data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"name": menu_data['name'],
|
||||
"web_path": menu_data['web_path'],
|
||||
"component": menu_data['component'],
|
||||
"component_name": menu_data['component_name'],
|
||||
}
|
||||
instance_obj = Menu.objects.filter(**filter_data).first()
|
||||
if instance_obj and not self.initial_data.get('reset'):
|
||||
continue
|
||||
serializer = MenuInitSerializer(instance_obj, data=menu_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
# 菜单按钮
|
||||
if menu_button:
|
||||
for menu_button_data in menu_button:
|
||||
menu_button_data['menu'] = instance.id
|
||||
filter_data = {
|
||||
"menu": menu_button_data['menu'],
|
||||
"value": menu_button_data['value']
|
||||
}
|
||||
instance_obj = MenuButton.objects.filter(**filter_data).first()
|
||||
serializer = MenuButtonInitSerializer(instance_obj, data=menu_button_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
# 列权限
|
||||
if menu_field:
|
||||
for field_data in menu_field:
|
||||
field_data['menu'] = instance.id
|
||||
filter_data = {
|
||||
'menu': field_data['menu'],
|
||||
'field_name': field_data['field_name'],
|
||||
'model': field_data['model']
|
||||
}
|
||||
instance_obj = MenuField.objects.filter(**filter_data).first()
|
||||
serializer = MenuFieldInitSerializer(instance_obj, data=field_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ['name', 'icon', 'sort', 'is_link', 'is_catalog', 'web_path', 'component', 'component_name', 'status',
|
||||
'cache', 'visible', 'parent', 'children', 'menu_button', 'menu_field', 'creator', 'dept_belong_id']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
read_only_fields = ['id', 'children']
|
||||
|
||||
|
||||
class RoleInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
fields = ['name', 'key', 'sort', 'status',
|
||||
'creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class RoleMenuInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化角色菜单(用于生成初始化json文件)
|
||||
"""
|
||||
role__key = serializers.CharField(source='role.key')
|
||||
menu__web_path = serializers.CharField(source='menu.web_path')
|
||||
menu__component_name = serializers.CharField(source='menu.component_name', allow_blank=True)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_id = Menu.objects.filter(web_path=init_data['menu__web_path'], component_name=init_data['menu__component_name']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu'] = menu_id
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
def create(self, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_id = Menu.objects.filter(web_path=init_data['menu__web_path'], component_name=init_data['menu__component_name']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu'] = menu_id
|
||||
return super().create(validated_data)
|
||||
|
||||
class Meta:
|
||||
model = RoleMenuPermission
|
||||
fields = ['role__key', 'menu__web_path', 'menu__component_name','creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'role': {'required': False},
|
||||
'menu': {'required': False},
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class RoleMenuButtonInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化角色菜单按钮(用于生成初始化json文件)
|
||||
"""
|
||||
role__key = serializers.CharField(source='role.key')
|
||||
menu_button__value = serializers.CharField(source='menu_button.value')
|
||||
data_range = serializers.CharField(max_length=100, required=False)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_button_id = MenuButton.objects.filter(value=init_data['menu_button__value']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu_button'] = menu_button_id
|
||||
instance = super().create(validated_data)
|
||||
instance.dept.set([])
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def create(self, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_button_id = MenuButton.objects.filter(value=init_data['menu_button__value']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu_button'] = menu_button_id
|
||||
instance = super().create(validated_data)
|
||||
instance.dept.set([])
|
||||
return instance
|
||||
|
||||
def save(self, **kwargs):
|
||||
if not self.instance or self.initial_data.get('reset'):
|
||||
return super().save(**kwargs)
|
||||
return self.instance
|
||||
|
||||
class Meta:
|
||||
model = RoleMenuButtonPermission
|
||||
fields = ['role__key', 'menu_button__value', 'data_range', 'dept', 'creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'role': {'required': False},
|
||||
'menu': {'required': False},
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class ApiWhiteListInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = ApiWhiteList
|
||||
fields = ['url', 'method', 'enable_datasource', 'creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class DeptInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
递归深度获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Dept):
|
||||
data = []
|
||||
instance = Dept.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = DeptInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
if children:
|
||||
for menu_data in children:
|
||||
menu_data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"name": menu_data['name'],
|
||||
"parent": menu_data['parent'],
|
||||
"key": menu_data['key']
|
||||
}
|
||||
instance_obj = Dept.objects.filter(**filter_data).first()
|
||||
if instance_obj and not self.initial_data.get('reset'):
|
||||
continue
|
||||
serializer = DeptInitSerializer(instance_obj, data=menu_data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Dept
|
||||
fields = ['name', 'sort', 'owner', 'phone', 'email', 'status', 'parent', 'creator', 'dept_belong_id',
|
||||
'children', 'key']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
read_only_fields = ['id', 'children']
|
||||
|
||||
|
||||
class DictionaryInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: Dictionary):
|
||||
data = []
|
||||
instance = Dictionary.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = DictionaryInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
# 菜单表
|
||||
if children:
|
||||
for data in children:
|
||||
data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"value": data['value'],
|
||||
"parent": data['parent']
|
||||
}
|
||||
instance_obj = Dictionary.objects.filter(**filter_data).first()
|
||||
if instance_obj and not self.initial_data.get('reset'):
|
||||
continue
|
||||
serializer = DictionaryInitSerializer(instance_obj, data=data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Dictionary
|
||||
fields = ['label', 'value', 'parent', 'type', 'color', 'is_value', 'status', 'sort', 'remark', 'creator',
|
||||
'dept_belong_id', 'children']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class SystemConfigInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
children = serializers.SerializerMethodField()
|
||||
|
||||
def get_children(self, obj: SystemConfig):
|
||||
data = []
|
||||
instance = SystemConfig.objects.filter(parent_id=obj.id)
|
||||
if instance:
|
||||
serializer = SystemConfigInitSerializer(instance=instance, many=True)
|
||||
data = serializer.data
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
children = self.initial_data.get('children')
|
||||
# 菜单表
|
||||
if children:
|
||||
for data in children:
|
||||
data['parent'] = instance.id
|
||||
filter_data = {
|
||||
"key": data['key'],
|
||||
"parent": data['parent']
|
||||
}
|
||||
instance_obj = SystemConfig.objects.filter(**filter_data).first()
|
||||
if instance_obj and not self.initial_data.get('reset'):
|
||||
continue
|
||||
serializer = SystemConfigInitSerializer(instance_obj, data=data, request=self.request)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = SystemConfig
|
||||
fields = ['parent', 'title', 'key', 'value', 'sort', 'status', 'data_options', 'form_item_type', 'rule',
|
||||
'placeholder', 'setting', 'creator', 'dept_belong_id', 'children']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
'dept_belong_id': {'write_only': True}
|
||||
}
|
||||
7
dvadmin/system/fixtures/init_apiwhitelist.json
Normal file
7
dvadmin/system/fixtures/init_apiwhitelist.json
Normal file
@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"url": "/api/system/dept_lazy_tree/",
|
||||
"method": 0,
|
||||
"enable_datasource": true
|
||||
}
|
||||
]
|
||||
36
dvadmin/system/fixtures/init_dept.json
Normal file
36
dvadmin/system/fixtures/init_dept.json
Normal file
@ -0,0 +1,36 @@
|
||||
[
|
||||
{
|
||||
"name": "DVAdmin团队",
|
||||
"key": "dvadmin",
|
||||
"sort": 1,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": null,
|
||||
"children": [
|
||||
{
|
||||
"name": "运营部",
|
||||
"key": "",
|
||||
"sort": 2,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": 1,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"name": "技术部",
|
||||
"key": "technology",
|
||||
"sort": 1,
|
||||
"owner": "",
|
||||
"phone": "",
|
||||
"email": "",
|
||||
"status": true,
|
||||
"parent": 3,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
595
dvadmin/system/fixtures/init_dictionary.json
Normal file
595
dvadmin/system/fixtures/init_dictionary.json
Normal file
@ -0,0 +1,595 @@
|
||||
[
|
||||
{
|
||||
"label": "启用/禁用-布尔值",
|
||||
"value": "button_status_bool",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "启用",
|
||||
"value": "true",
|
||||
"parent": 1,
|
||||
"type": 6,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "禁用",
|
||||
"value": "false",
|
||||
"parent": 1,
|
||||
"type": 6,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "系统按钮",
|
||||
"value": "system_button",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "新增",
|
||||
"value": "Create",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "编辑",
|
||||
"value": "Update",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "primary",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "删除",
|
||||
"value": "Delete",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "详情",
|
||||
"value": "Retrieve",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "info",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "查询",
|
||||
"value": "Search",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "warning",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "保存",
|
||||
"value": "Save",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "导入",
|
||||
"value": "Import",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "primary",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "导出",
|
||||
"value": "Export",
|
||||
"parent": 4,
|
||||
"type": 0,
|
||||
"color": "warning",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "启用/禁用-数字值",
|
||||
"value": "button_status_number",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "启用",
|
||||
"value": "1",
|
||||
"parent": 13,
|
||||
"type": 1,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "禁用",
|
||||
"value": "0",
|
||||
"parent": 13,
|
||||
"type": 1,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "是/否-布尔值",
|
||||
"value": "button_whether_bool",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "是",
|
||||
"value": "true",
|
||||
"parent": 16,
|
||||
"type": 6,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "否",
|
||||
"value": "false",
|
||||
"parent": 16,
|
||||
"type": 6,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "是/否-数字值",
|
||||
"value": "button_whether_number",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "是",
|
||||
"value": "1",
|
||||
"parent": 19,
|
||||
"type": 1,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "否",
|
||||
"value": "2",
|
||||
"parent": 19,
|
||||
"type": 1,
|
||||
"color": "danger",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "用户类型",
|
||||
"value": "user_type",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "后台用户",
|
||||
"value": "0",
|
||||
"parent": 22,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "前台用户",
|
||||
"value": "1",
|
||||
"parent": 22,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "表单类型",
|
||||
"value": "config_form_type",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "text",
|
||||
"value": "0",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "textarea",
|
||||
"value": "3",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "number",
|
||||
"value": "10",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "datetime",
|
||||
"value": "1",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "date",
|
||||
"value": "2",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "time",
|
||||
"value": "15",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "select",
|
||||
"value": "4",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 4,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "checkbox",
|
||||
"value": "5",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 5,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "radio",
|
||||
"value": "6",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "switch",
|
||||
"value": "9",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 6,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "文件附件",
|
||||
"value": "8",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 7,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "图片(单张)",
|
||||
"value": "7",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "图片(多张)",
|
||||
"value": "12",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 9,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "数组",
|
||||
"value": "11",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 11,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "关联表",
|
||||
"value": "13",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 13,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "关联表(多选)",
|
||||
"value": "14",
|
||||
"parent": 25,
|
||||
"type": 1,
|
||||
"color": "",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 14,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "性别",
|
||||
"value": "gender",
|
||||
"parent": null,
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 8,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "未知",
|
||||
"value": "0",
|
||||
"parent": 42,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 0,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "男",
|
||||
"value": "1",
|
||||
"parent": 42,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "女",
|
||||
"value": "2",
|
||||
"parent": 42,
|
||||
"type": 1,
|
||||
"color": null,
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "文件存储引擎",
|
||||
"value": "file_engine",
|
||||
"type": 0,
|
||||
"color": null,
|
||||
"is_value": false,
|
||||
"status": true,
|
||||
"sort": 9,
|
||||
"remark": null,
|
||||
"children": [
|
||||
{
|
||||
"label": "本地",
|
||||
"value": "local",
|
||||
"type": 0,
|
||||
"color": "primary",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 1,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "阿里云oss",
|
||||
"value": "oss",
|
||||
"type": 0,
|
||||
"color": "success",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 2,
|
||||
"remark": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"label": "腾讯cos",
|
||||
"value": "cos",
|
||||
"type": 0,
|
||||
"color": "warning",
|
||||
"is_value": true,
|
||||
"status": true,
|
||||
"sort": 3,
|
||||
"remark": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
1463
dvadmin/system/fixtures/init_menu.json
Normal file
1463
dvadmin/system/fixtures/init_menu.json
Normal file
File diff suppressed because it is too large
Load Diff
16
dvadmin/system/fixtures/init_role.json
Normal file
16
dvadmin/system/fixtures/init_role.json
Normal file
@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"name": "管理员",
|
||||
"key": "admin",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"remark": null
|
||||
},
|
||||
{
|
||||
"name": "用户",
|
||||
"key": "public",
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"remark": null
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"role__key": "admin",
|
||||
"menu_button__value": "menu:Search",
|
||||
"data_range": 0
|
||||
}
|
||||
]
|
||||
12
dvadmin/system/fixtures/init_rolemenupermission.json
Normal file
12
dvadmin/system/fixtures/init_rolemenupermission.json
Normal file
@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"role__key": "admin",
|
||||
"menu__web_path": "/system",
|
||||
"menu__component_name": ""
|
||||
},
|
||||
{
|
||||
"role__key": "admin",
|
||||
"menu__web_path": "/menu",
|
||||
"menu__component_name": "menu"
|
||||
}
|
||||
]
|
||||
486
dvadmin/system/fixtures/init_systemconfig.json
Normal file
486
dvadmin/system/fixtures/init_systemconfig.json
Normal file
@ -0,0 +1,486 @@
|
||||
[
|
||||
{
|
||||
"parent": null,
|
||||
"title": "基础配置",
|
||||
"key": "base",
|
||||
"value": null,
|
||||
"sort": 0,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": null,
|
||||
"placeholder": null,
|
||||
"setting": null,
|
||||
"children": [
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "网页标题",
|
||||
"key": "web_title",
|
||||
"value": "DVAdmin",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请输入网站标题",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "网站小图标",
|
||||
"key": "web_favicon",
|
||||
"value": "",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请输入网站小图标",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "开启验证码",
|
||||
"key": "captcha_state",
|
||||
"value": true,
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 9,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请选择",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 10,
|
||||
"title": "创建用户默认密码",
|
||||
"key": "default_password",
|
||||
"value": "admin123456",
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入默认密码",
|
||||
"setting": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"parent": null,
|
||||
"title": "登录页配置",
|
||||
"key": "login",
|
||||
"value": null,
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": null,
|
||||
"placeholder": null,
|
||||
"setting": null,
|
||||
"children": [
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "网站标题",
|
||||
"key": "site_title",
|
||||
"value": "Dvadmin",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请输入网站标题",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "网站名称",
|
||||
"key": "site_name",
|
||||
"value": "企业级后台管理系统",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入网站名称",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "登录网站logo",
|
||||
"key": "site_logo",
|
||||
"value": null,
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 7,
|
||||
"rule": [],
|
||||
"placeholder": "请上传网站logo",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "登录页背景图",
|
||||
"key": "login_background",
|
||||
"value": null,
|
||||
"sort": 3,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 7,
|
||||
"rule": [],
|
||||
"placeholder": "请上传登录背景页",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "版权信息",
|
||||
"key": "copyright",
|
||||
"value": "2021-2024 django-vue-admin.com 版权所有",
|
||||
"sort": 4,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入版权信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "备案信息",
|
||||
"key": "keep_record",
|
||||
"value": "晋ICP备18005113号-3",
|
||||
"sort": 5,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"message": "必填项不能为空",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入备案信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "帮助链接",
|
||||
"key": "help_url",
|
||||
"value": "https://django-vue-admin.com",
|
||||
"sort": 6,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": "",
|
||||
"placeholder": "请输入帮助信息",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "隐私链接",
|
||||
"key": "privacy_url",
|
||||
"value": "/api/system/clause/privacy.html",
|
||||
"sort": 7,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请填写隐私链接",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"parent": 1,
|
||||
"title": "条款链接",
|
||||
"key": "clause_url",
|
||||
"value": "/api/system/clause/terms_service.html",
|
||||
"sort": 8,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [],
|
||||
"placeholder": "请输入条款链接",
|
||||
"setting": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "文件存储配置",
|
||||
"key": "file_storage",
|
||||
"value": null,
|
||||
"sort": 0,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": null,
|
||||
"placeholder": null,
|
||||
"setting": null,
|
||||
"children": [
|
||||
{
|
||||
"title": "存储引擎",
|
||||
"key": "file_engine",
|
||||
"value": "local",
|
||||
"sort": 1,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 4,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请选择存储引擎",
|
||||
"setting": "file_engine",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "文件是否备份",
|
||||
"key": "file_backup",
|
||||
"value": false,
|
||||
"sort": 2,
|
||||
"status": true,
|
||||
"data_options": null,
|
||||
"form_item_type": 9,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "启用云存储时,文件是否备份到本地",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "阿里云-AccessKey",
|
||||
"key": "aliyun_access_key",
|
||||
"value": null,
|
||||
"sort": 3,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入AccessKey",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "阿里云-Secret",
|
||||
"key": "aliyun_access_secret",
|
||||
"value": null,
|
||||
"sort": 4,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入Secret",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "阿里云-Endpoint",
|
||||
"key": "aliyun_endpoint",
|
||||
"value": null,
|
||||
"sort": 5,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入Endpoint",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "阿里云-上传路径",
|
||||
"key": "aliyun_path",
|
||||
"value": "/media/",
|
||||
"sort": 5,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入上传路径",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "阿里云-Bucket",
|
||||
"key": "aliyun_bucket",
|
||||
"value": null,
|
||||
"sort": 7,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入Bucket",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},{
|
||||
"title": "阿里云-cdn地址",
|
||||
"key": "aliyun_cdn_url",
|
||||
"value": null,
|
||||
"sort": 7,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入cdn地址",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "腾讯云-SecretId",
|
||||
"key": "tencent_secret_id",
|
||||
"value": null,
|
||||
"sort": 8,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入SecretId",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "腾讯云-SecretKey",
|
||||
"key": "tencent_secret_key",
|
||||
"value": null,
|
||||
"sort": 9,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入SecretKey",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "腾讯云-Region",
|
||||
"key": "tencent_region",
|
||||
"value": null,
|
||||
"sort": 10,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入Region",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "腾讯云-Bucket",
|
||||
"key": "tencent_bucket",
|
||||
"value": null,
|
||||
"sort": 11,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入Bucket",
|
||||
"setting": null,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"title": "腾讯云-上传路径",
|
||||
"key": "tencent_path",
|
||||
"value": "/media/",
|
||||
"sort": 12,
|
||||
"status": false,
|
||||
"data_options": null,
|
||||
"form_item_type": 0,
|
||||
"rule": [
|
||||
{
|
||||
"required": false,
|
||||
"message": "必填项不能为空"
|
||||
}
|
||||
],
|
||||
"placeholder": "请输入上传路径",
|
||||
"setting": null,
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
60
dvadmin/system/fixtures/init_users.json
Normal file
60
dvadmin/system/fixtures/init_users.json
Normal file
@ -0,0 +1,60 @@
|
||||
[
|
||||
{
|
||||
"username": "superadmin",
|
||||
"email": "dvadmin@django-vue-admin.com",
|
||||
"mobile": "13333333333",
|
||||
"avatar": null,
|
||||
"name": "超级管理员",
|
||||
"gender": 1,
|
||||
"user_type": 0,
|
||||
"role": [],
|
||||
"role_key": [
|
||||
"admin"
|
||||
],
|
||||
"dept_key": "dvadmin",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
|
||||
"last_login": null,
|
||||
"is_superuser": true
|
||||
},
|
||||
{
|
||||
"username": "admin",
|
||||
"email": "dvadmin@django-vue-admin.com",
|
||||
"mobile": "18888888888",
|
||||
"avatar": "",
|
||||
"name": "管理员",
|
||||
"gender": 1,
|
||||
"user_type": 0,
|
||||
"role": [],
|
||||
"dept_key": "dvadmin",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
|
||||
"last_login": null,
|
||||
"is_superuser": false
|
||||
},
|
||||
{
|
||||
"username": "test",
|
||||
"email": "dvadmin@django-vue-admin.com",
|
||||
"mobile": "18888888888",
|
||||
"avatar": "",
|
||||
"name": "测试人员",
|
||||
"gender": 1,
|
||||
"user_type": 0,
|
||||
"role": [],
|
||||
"role_key": ["public"],
|
||||
"dept_key": "technology",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"password": "pbkdf2_sha256$260000$g17x5wlSiW1FZAh1Eudchw$ZeSAqj3Xak0io8v/pmPW0BX9EX5R2zFXDwbbD68oBFk=",
|
||||
"last_login": null,
|
||||
"is_superuser": false
|
||||
}
|
||||
]
|
||||
87
dvadmin/system/fixtures/initialize.py
Normal file
87
dvadmin/system/fixtures/initialize.py
Normal file
@ -0,0 +1,87 @@
|
||||
# 初始化
|
||||
import os
|
||||
|
||||
import django
|
||||
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
|
||||
django.setup()
|
||||
|
||||
from dvadmin.utils.core_initialize import CoreInitialize
|
||||
from dvadmin.system.fixtures.initSerializer import (
|
||||
UsersInitSerializer, DeptInitSerializer, RoleInitSerializer,
|
||||
MenuInitSerializer, ApiWhiteListInitSerializer, DictionaryInitSerializer,
|
||||
SystemConfigInitSerializer, RoleMenuInitSerializer, RoleMenuButtonInitSerializer
|
||||
)
|
||||
|
||||
|
||||
class Initialize(CoreInitialize):
|
||||
|
||||
def init_dept(self):
|
||||
"""
|
||||
初始化部门信息
|
||||
"""
|
||||
self.init_base(DeptInitSerializer, unique_fields=['name', 'parent','key'])
|
||||
|
||||
def init_role(self):
|
||||
"""
|
||||
初始化角色信息
|
||||
"""
|
||||
self.init_base(RoleInitSerializer, unique_fields=['key'])
|
||||
|
||||
def init_users(self):
|
||||
"""
|
||||
初始化用户信息
|
||||
"""
|
||||
self.init_base(UsersInitSerializer, unique_fields=['username'])
|
||||
|
||||
def init_menu(self):
|
||||
"""
|
||||
初始化菜单信息
|
||||
"""
|
||||
self.init_base(MenuInitSerializer, unique_fields=['name', 'web_path', 'component', 'component_name'])
|
||||
|
||||
def init_role_menu(self):
|
||||
"""
|
||||
初始化角色菜单信息
|
||||
"""
|
||||
self.init_base(RoleMenuInitSerializer, unique_fields=['role__key', 'menu__web_path', 'menu__component_name'])
|
||||
|
||||
def init_role_menu_button(self):
|
||||
"""
|
||||
初始化角色菜单按钮信息
|
||||
"""
|
||||
self.init_base(RoleMenuButtonInitSerializer, unique_fields=['role__key', 'menu_button__value'])
|
||||
|
||||
def init_api_white_list(self):
|
||||
"""
|
||||
初始API白名单
|
||||
"""
|
||||
self.init_base(ApiWhiteListInitSerializer, unique_fields=['url', 'method', ])
|
||||
|
||||
def init_dictionary(self):
|
||||
"""
|
||||
初始化字典表
|
||||
"""
|
||||
self.init_base(DictionaryInitSerializer, unique_fields=['value', 'parent', ])
|
||||
|
||||
def init_system_config(self):
|
||||
"""
|
||||
初始化系统配置表
|
||||
"""
|
||||
self.init_base(SystemConfigInitSerializer, unique_fields=['key', 'parent', ])
|
||||
|
||||
def run(self):
|
||||
self.init_dept()
|
||||
self.init_role()
|
||||
self.init_users()
|
||||
self.init_menu()
|
||||
self.init_role_menu()
|
||||
self.init_role_menu_button()
|
||||
self.init_api_white_list()
|
||||
self.init_dictionary()
|
||||
self.init_system_config()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Initialize(app='dvadmin.system').run()
|
||||
0
dvadmin/system/management/__init__.py
Normal file
0
dvadmin/system/management/__init__.py
Normal file
BIN
dvadmin/system/management/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/system/management/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
0
dvadmin/system/management/commands/__init__.py
Normal file
0
dvadmin/system/management/commands/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
103
dvadmin/system/management/commands/generate_init_json.py
Normal file
103
dvadmin/system/management/commands/generate_init_json.py
Normal file
@ -0,0 +1,103 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import django
|
||||
from django.db.models import QuerySet
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
django.setup()
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from application.settings import BASE_DIR
|
||||
from dvadmin.system.models import Menu, Users, Dept, Role, ApiWhiteList, Dictionary, SystemConfig, RoleMenuButtonPermission, RoleMenuPermission
|
||||
from dvadmin.system.fixtures.initSerializer import UsersInitSerializer, DeptInitSerializer, RoleInitSerializer, \
|
||||
MenuInitSerializer, ApiWhiteListInitSerializer, DictionaryInitSerializer, SystemConfigInitSerializer, \
|
||||
RoleMenuInitSerializer, RoleMenuButtonInitSerializer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
生产初始化菜单: python3 manage.py generate_init_json 生成初始化的model名
|
||||
例如:
|
||||
全部生成:python3 manage.py generate_init_json
|
||||
只生成某个model的: python3 manage.py generate_init_json users
|
||||
"""
|
||||
|
||||
def serializer_data(self, serializer, query_set: QuerySet):
|
||||
serializer = serializer(query_set, many=True)
|
||||
data = json.loads(json.dumps(serializer.data, ensure_ascii=False))
|
||||
with open(os.path.join(BASE_DIR, f'init_{query_set.model._meta.model_name}.json'), 'w',encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
return
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("generate_name", nargs="*", type=str, help="初始化生成的表名")
|
||||
|
||||
def generate_users(self):
|
||||
self.serializer_data(UsersInitSerializer, Users.objects.all())
|
||||
|
||||
def generate_role(self):
|
||||
self.serializer_data(RoleInitSerializer, Role.objects.all())
|
||||
|
||||
def generate_dept(self):
|
||||
self.serializer_data(DeptInitSerializer, Dept.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_menu(self):
|
||||
self.serializer_data(MenuInitSerializer, Menu.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_api_white_list(self):
|
||||
self.serializer_data(ApiWhiteListInitSerializer, ApiWhiteList.objects.all())
|
||||
|
||||
def generate_dictionary(self):
|
||||
self.serializer_data(DictionaryInitSerializer, Dictionary.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_system_config(self):
|
||||
self.serializer_data(SystemConfigInitSerializer, SystemConfig.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_role_menu(self):
|
||||
self.serializer_data(RoleMenuInitSerializer, RoleMenuPermission.objects.all())
|
||||
|
||||
def generate_role_menu_button(self):
|
||||
self.serializer_data(RoleMenuButtonInitSerializer, RoleMenuButtonPermission.objects.all())
|
||||
|
||||
def handle(self, *args, **options):
|
||||
generate_name = options.get('generate_name')
|
||||
generate_name_dict = {
|
||||
"users": self.generate_users,
|
||||
"role": self.generate_role,
|
||||
"dept": self.generate_dept,
|
||||
"menu": self.generate_menu,
|
||||
"api_white_list": self.generate_api_white_list,
|
||||
"dictionary": self.generate_dictionary,
|
||||
"system_config": self.generate_system_config,
|
||||
"role_menu": self.generate_role_menu,
|
||||
"role_menu_button": self.generate_role_menu_button,
|
||||
}
|
||||
if not generate_name:
|
||||
for ele in generate_name_dict.keys():
|
||||
generate_name_dict[ele]()
|
||||
return
|
||||
|
||||
for generate_name in generate_name:
|
||||
if generate_name not in generate_name_dict:
|
||||
print(f"该初始化方法尚未配置\n{generate_name_dict}")
|
||||
raise Exception(f"该初始化方法尚未配置,已配置项:{list(generate_name_dict.keys())}")
|
||||
generate_name_dict[generate_name]()
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# with open(os.path.join(BASE_DIR, 'temp_init_menu.json')) as f:
|
||||
# for menu_data in json.load(f):
|
||||
# menu_data['creator'] = 1
|
||||
# menu_data['modifier'] = 1
|
||||
# menu_data['dept_belong_id'] = 1
|
||||
# request.user = Users.objects.order_by('create_datetime').first()
|
||||
# serializer = MenuInitSerializer(data=menu_data, request=request)
|
||||
# serializer.is_valid(raise_exception=True)
|
||||
# serializer.save()
|
||||
a = Users.objects.filter()
|
||||
print(type(Users.objects.filter()))
|
||||
56
dvadmin/system/management/commands/init.py
Normal file
56
dvadmin/system/management/commands/init.py
Normal file
@ -0,0 +1,56 @@
|
||||
import logging
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from application import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
项目初始化命令: python manage.py init
|
||||
"""
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"init_name",
|
||||
nargs="*",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument("-y", nargs="*")
|
||||
parser.add_argument("-Y", nargs="*")
|
||||
parser.add_argument("-n", nargs="*")
|
||||
parser.add_argument("-N", nargs="*")
|
||||
parser.add_argument("-app", nargs="*")
|
||||
parser.add_argument("-A", nargs="*")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
reset = False
|
||||
if isinstance(options.get("y"), list) or isinstance(options.get("Y"), list):
|
||||
reset = True
|
||||
if isinstance(options.get("n"), list) or isinstance(options.get("N"), list):
|
||||
reset = False
|
||||
assign_apps = options.get("app") or options.get("A") or []
|
||||
for app in settings.INSTALLED_APPS:
|
||||
if assign_apps and app not in assign_apps:
|
||||
continue
|
||||
try:
|
||||
exec(
|
||||
f"""
|
||||
from {app}.fixtures.initialize import Initialize
|
||||
Initialize(reset={reset},app="{app}").run()
|
||||
"""
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
# 兼容之前版本初始化
|
||||
try:
|
||||
exec(
|
||||
f"""
|
||||
from {app}.initialize import main
|
||||
main(reset={reset})
|
||||
"""
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
print("初始化数据完成!")
|
||||
83
dvadmin/system/management/commands/init_area.py
Normal file
83
dvadmin/system/management/commands/init_area.py
Normal file
@ -0,0 +1,83 @@
|
||||
# 城市联动
|
||||
"""
|
||||
到乡级 使用方法
|
||||
1. https://www.npmjs.com/package/china-division 下载数据,把对应的json放入对应目录
|
||||
2. 修改此文件中对应json名
|
||||
3. 右击执行此py文件进行初始化
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
||||
import django
|
||||
import pypinyin
|
||||
from django.core.management import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
from application import dispatch
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
|
||||
django.setup()
|
||||
from application.settings import BASE_DIR
|
||||
from dvadmin.system.models import Area
|
||||
|
||||
area_code_list = []
|
||||
|
||||
|
||||
def area_list(code_list, pcode=None, depth=1):
|
||||
"""
|
||||
递归获取所有列表
|
||||
"""
|
||||
for code_dict in code_list:
|
||||
code = code_dict.get('code', None)
|
||||
name = code_dict.get('name', None)
|
||||
children = code_dict.get('children', None)
|
||||
pinyin = ''.join([''.join(i) for i in pypinyin.pinyin(name, style=pypinyin.NORMAL)])
|
||||
area_code_list.append(
|
||||
{
|
||||
"name": name,
|
||||
"code": code,
|
||||
"level": depth,
|
||||
"pinyin": pinyin,
|
||||
"initials": pinyin[0].upper() if pinyin else "#",
|
||||
"pcode_id": pcode,
|
||||
}
|
||||
)
|
||||
if children:
|
||||
area_list(code_list=children, pcode=code, depth=depth + 1)
|
||||
|
||||
|
||||
def main():
|
||||
with open(os.path.join(BASE_DIR, 'dvadmin', 'system', 'util', 'pca-code.json'), 'r', encoding="utf-8") as load_f:
|
||||
code_list = json.load(load_f)
|
||||
area_list(code_list)
|
||||
if Area.objects.count() == 0:
|
||||
Area.objects.bulk_create([Area(**ele) for ele in area_code_list])
|
||||
else:
|
||||
for ele in area_code_list:
|
||||
code = ele.pop("code")
|
||||
Area.objects.update_or_create(code=code, defaults=ele)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
"""
|
||||
项目初始化命令: python manage.py init
|
||||
"""
|
||||
|
||||
def add_arguments(self, parser):
|
||||
pass
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
print(f"正在准备初始化省份数据...")
|
||||
|
||||
if dispatch.is_tenants_mode():
|
||||
from django_tenants.utils import get_tenant_model
|
||||
from django_tenants.utils import tenant_context
|
||||
for tenant in get_tenant_model().objects.exclude(schema_name='public'):
|
||||
with tenant_context(tenant):
|
||||
print(f"租户[{connection.tenant.schema_name}]初始化数据开始...")
|
||||
main()
|
||||
print(f"租户[{connection.tenant.schema_name}]初始化数据完成!")
|
||||
else:
|
||||
main()
|
||||
print("省份数据初始化数据完成!")
|
||||
574
dvadmin/system/migrations/0001_initial.py
Normal file
574
dvadmin/system/migrations/0001_initial.py
Normal file
@ -0,0 +1,574 @@
|
||||
# Generated by Django 4.2.14 on 2025-10-16 01:27
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import dvadmin.system.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Users',
|
||||
fields=[
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('username', models.CharField(db_index=True, help_text='用户账号', max_length=150, unique=True, verbose_name='用户账号')),
|
||||
('email', models.EmailField(blank=True, help_text='邮箱', max_length=255, null=True, verbose_name='邮箱')),
|
||||
('mobile', models.CharField(blank=True, help_text='电话', max_length=255, null=True, verbose_name='电话')),
|
||||
('avatar', models.CharField(blank=True, help_text='头像', max_length=255, null=True, verbose_name='头像')),
|
||||
('name', models.CharField(help_text='姓名', max_length=40, verbose_name='姓名')),
|
||||
('gender', models.IntegerField(blank=True, choices=[(0, '未知'), (1, '男'), (2, '女')], default=0, help_text='性别', null=True, verbose_name='性别')),
|
||||
('user_type', models.IntegerField(blank=True, choices=[(0, '后台用户'), (1, '前台用户')], default=0, help_text='用户类型', null=True, verbose_name='用户类型')),
|
||||
('login_error_count', models.IntegerField(default=0, help_text='登录错误次数', verbose_name='登录错误次数')),
|
||||
('pwd_change_count', models.IntegerField(blank=True, default=0, help_text='密码修改次数', verbose_name='密码修改次数')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '用户表',
|
||||
'verbose_name_plural': '用户表',
|
||||
'db_table': 'dvadmin_system_users',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
managers=[
|
||||
('objects', dvadmin.system.models.CustomUserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Dept',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(help_text='部门名称', max_length=64, verbose_name='部门名称')),
|
||||
('key', models.CharField(blank=True, help_text='关联字符', max_length=64, null=True, unique=True, verbose_name='关联字符')),
|
||||
('sort', models.IntegerField(default=1, help_text='显示排序', verbose_name='显示排序')),
|
||||
('owner', models.CharField(blank=True, help_text='负责人', max_length=32, null=True, verbose_name='负责人')),
|
||||
('phone', models.CharField(blank=True, help_text='联系电话', max_length=32, null=True, verbose_name='联系电话')),
|
||||
('email', models.EmailField(blank=True, help_text='邮箱', max_length=32, null=True, verbose_name='邮箱')),
|
||||
('status', models.BooleanField(blank=True, default=True, help_text='部门状态', null=True, verbose_name='部门状态')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('parent', models.ForeignKey(blank=True, db_constraint=False, default=None, help_text='上级部门', null=True, on_delete=django.db.models.deletion.CASCADE, to='system.dept', verbose_name='上级部门')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '部门表',
|
||||
'verbose_name_plural': '部门表',
|
||||
'db_table': 'dvadmin_system_dept',
|
||||
'ordering': ('sort',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Menu',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('icon', models.CharField(blank=True, help_text='菜单图标', max_length=64, null=True, verbose_name='菜单图标')),
|
||||
('name', models.CharField(help_text='菜单名称', max_length=64, verbose_name='菜单名称')),
|
||||
('sort', models.IntegerField(blank=True, default=1, help_text='显示排序', null=True, verbose_name='显示排序')),
|
||||
('is_link', models.BooleanField(default=False, help_text='是否外链', verbose_name='是否外链')),
|
||||
('link_url', models.CharField(blank=True, help_text='链接地址', max_length=255, null=True, verbose_name='链接地址')),
|
||||
('is_catalog', models.BooleanField(default=False, help_text='是否目录', verbose_name='是否目录')),
|
||||
('web_path', models.CharField(blank=True, help_text='路由地址', max_length=128, null=True, verbose_name='路由地址')),
|
||||
('component', models.CharField(blank=True, help_text='组件地址', max_length=128, null=True, verbose_name='组件地址')),
|
||||
('component_name', models.CharField(blank=True, help_text='组件名称', max_length=50, null=True, verbose_name='组件名称')),
|
||||
('status', models.BooleanField(blank=True, default=True, help_text='菜单状态', verbose_name='菜单状态')),
|
||||
('cache', models.BooleanField(blank=True, default=False, help_text='是否页面缓存', verbose_name='是否页面缓存')),
|
||||
('visible', models.BooleanField(blank=True, default=True, help_text='侧边栏中是否显示', verbose_name='侧边栏中是否显示')),
|
||||
('is_iframe', models.BooleanField(blank=True, default=False, help_text='框架外显示', verbose_name='框架外显示')),
|
||||
('is_affix', models.BooleanField(blank=True, default=False, help_text='是否固定', verbose_name='是否固定')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('parent', models.ForeignKey(blank=True, db_constraint=False, help_text='上级菜单', null=True, on_delete=django.db.models.deletion.CASCADE, to='system.menu', verbose_name='上级菜单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '菜单表',
|
||||
'verbose_name_plural': '菜单表',
|
||||
'db_table': 'dvadmin_system_menu',
|
||||
'ordering': ('sort',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MenuButton',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(help_text='名称', max_length=64, verbose_name='名称')),
|
||||
('value', models.CharField(help_text='权限值', max_length=64, unique=True, verbose_name='权限值')),
|
||||
('api', models.CharField(help_text='接口地址', max_length=200, verbose_name='接口地址')),
|
||||
('method', models.IntegerField(blank=True, default=0, help_text='接口请求方法', null=True, verbose_name='接口请求方法')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('menu', models.ForeignKey(db_constraint=False, help_text='关联菜单', on_delete=django.db.models.deletion.CASCADE, related_name='menuPermission', to='system.menu', verbose_name='关联菜单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '菜单权限表',
|
||||
'verbose_name_plural': '菜单权限表',
|
||||
'db_table': 'dvadmin_system_menu_button',
|
||||
'ordering': ('-name',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MessageCenter',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('title', models.CharField(help_text='标题', max_length=100, verbose_name='标题')),
|
||||
('content', models.TextField(help_text='内容', verbose_name='内容')),
|
||||
('target_type', models.IntegerField(default=0, help_text='目标类型', verbose_name='目标类型')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('target_dept', models.ManyToManyField(blank=True, db_constraint=False, help_text='目标部门', to='system.dept', verbose_name='目标部门')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '消息中心',
|
||||
'verbose_name_plural': '消息中心',
|
||||
'db_table': 'dvadmin_message_center',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Role',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(help_text='角色名称', max_length=64, verbose_name='角色名称')),
|
||||
('key', models.CharField(help_text='权限字符', max_length=64, unique=True, verbose_name='权限字符')),
|
||||
('sort', models.IntegerField(default=1, help_text='角色顺序', verbose_name='角色顺序')),
|
||||
('status', models.BooleanField(default=True, help_text='角色状态', verbose_name='角色状态')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '角色表',
|
||||
'verbose_name_plural': '角色表',
|
||||
'db_table': 'dvadmin_system_role',
|
||||
'ordering': ('sort',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RoleMenuPermission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('menu', models.ForeignKey(db_constraint=False, help_text='关联菜单', on_delete=django.db.models.deletion.CASCADE, related_name='role_menu', to='system.menu', verbose_name='关联菜单')),
|
||||
('role', models.ForeignKey(db_constraint=False, help_text='关联角色', on_delete=django.db.models.deletion.CASCADE, related_name='role_menu', to='system.role', verbose_name='关联角色')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '角色菜单权限表',
|
||||
'verbose_name_plural': '角色菜单权限表',
|
||||
'db_table': 'dvadmin_role_menu_permission',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RoleMenuButtonPermission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('data_range', models.IntegerField(choices=[(0, '仅本人数据权限'), (1, '本部门及以下数据权限'), (2, '本部门数据权限'), (3, '全部数据权限'), (4, '自定数据权限')], default=0, help_text='数据权限范围', verbose_name='数据权限范围')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('dept', models.ManyToManyField(blank=True, db_constraint=False, help_text='数据权限-关联部门', to='system.dept', verbose_name='数据权限-关联部门')),
|
||||
('menu_button', models.ForeignKey(blank=True, db_constraint=False, help_text='关联菜单按钮', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='menu_button_permission', to='system.menubutton', verbose_name='关联菜单按钮')),
|
||||
('role', models.ForeignKey(db_constraint=False, help_text='关联角色', on_delete=django.db.models.deletion.CASCADE, related_name='role_menu_button', to='system.role', verbose_name='关联角色')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '角色按钮权限表',
|
||||
'verbose_name_plural': '角色按钮权限表',
|
||||
'db_table': 'dvadmin_role_menu_button_permission',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Post',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(help_text='岗位名称', max_length=64, verbose_name='岗位名称')),
|
||||
('code', models.CharField(help_text='岗位编码', max_length=32, verbose_name='岗位编码')),
|
||||
('sort', models.IntegerField(default=1, help_text='岗位顺序', verbose_name='岗位顺序')),
|
||||
('status', models.IntegerField(choices=[(0, '离职'), (1, '在职')], default=1, help_text='岗位状态', verbose_name='岗位状态')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '岗位表',
|
||||
'verbose_name_plural': '岗位表',
|
||||
'db_table': 'dvadmin_system_post',
|
||||
'ordering': ('sort',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OperationLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('request_modular', models.CharField(blank=True, help_text='请求模块', max_length=64, null=True, verbose_name='请求模块')),
|
||||
('request_path', models.CharField(blank=True, help_text='请求地址', max_length=400, null=True, verbose_name='请求地址')),
|
||||
('request_body', models.TextField(blank=True, help_text='请求参数', null=True, verbose_name='请求参数')),
|
||||
('request_method', models.CharField(blank=True, help_text='请求方式', max_length=8, null=True, verbose_name='请求方式')),
|
||||
('request_msg', models.TextField(blank=True, help_text='操作说明', null=True, verbose_name='操作说明')),
|
||||
('request_ip', models.CharField(blank=True, help_text='请求ip地址', max_length=32, null=True, verbose_name='请求ip地址')),
|
||||
('request_browser', models.CharField(blank=True, help_text='请求浏览器', max_length=64, null=True, verbose_name='请求浏览器')),
|
||||
('response_code', models.CharField(blank=True, help_text='响应状态码', max_length=32, null=True, verbose_name='响应状态码')),
|
||||
('request_os', models.CharField(blank=True, help_text='操作系统', max_length=64, null=True, verbose_name='操作系统')),
|
||||
('json_result', models.TextField(blank=True, help_text='返回信息', null=True, verbose_name='返回信息')),
|
||||
('status', models.BooleanField(default=False, help_text='响应状态', verbose_name='响应状态')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '操作日志',
|
||||
'verbose_name_plural': '操作日志',
|
||||
'db_table': 'dvadmin_system_operation_log',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MessageCenterTargetUser',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('is_read', models.BooleanField(blank=True, default=False, help_text='是否已读', null=True, verbose_name='是否已读')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('messagecenter', models.ForeignKey(db_constraint=False, help_text='关联消息中心表', on_delete=django.db.models.deletion.CASCADE, to='system.messagecenter', verbose_name='关联消息中心表')),
|
||||
('users', models.ForeignKey(db_constraint=False, help_text='关联用户表', on_delete=django.db.models.deletion.CASCADE, related_name='target_user', to=settings.AUTH_USER_MODEL, verbose_name='关联用户表')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '消息中心目标用户表',
|
||||
'verbose_name_plural': '消息中心目标用户表',
|
||||
'db_table': 'dvadmin_message_center_target_user',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='messagecenter',
|
||||
name='target_role',
|
||||
field=models.ManyToManyField(blank=True, db_constraint=False, help_text='目标角色', to='system.role', verbose_name='目标角色'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='messagecenter',
|
||||
name='target_user',
|
||||
field=models.ManyToManyField(blank=True, help_text='目标用户', related_name='user', through='system.MessageCenterTargetUser', to=settings.AUTH_USER_MODEL, verbose_name='目标用户'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MenuField',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('model', models.CharField(max_length=64, verbose_name='表名')),
|
||||
('field_name', models.CharField(max_length=64, verbose_name='模型表字段名')),
|
||||
('title', models.CharField(max_length=64, verbose_name='字段显示名')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('menu', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='system.menu', verbose_name='菜单')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '菜单字段表',
|
||||
'verbose_name_plural': '菜单字段表',
|
||||
'db_table': 'dvadmin_system_menu_field',
|
||||
'ordering': ('id',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LoginLog',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('username', models.CharField(blank=True, help_text='登录用户名', max_length=32, null=True, verbose_name='登录用户名')),
|
||||
('ip', models.CharField(blank=True, help_text='登录ip', max_length=32, null=True, verbose_name='登录ip')),
|
||||
('agent', models.TextField(blank=True, help_text='agent信息', null=True, verbose_name='agent信息')),
|
||||
('browser', models.CharField(blank=True, help_text='浏览器名', max_length=200, null=True, verbose_name='浏览器名')),
|
||||
('os', models.CharField(blank=True, help_text='操作系统', max_length=200, null=True, verbose_name='操作系统')),
|
||||
('continent', models.CharField(blank=True, help_text='州', max_length=50, null=True, verbose_name='州')),
|
||||
('country', models.CharField(blank=True, help_text='国家', max_length=50, null=True, verbose_name='国家')),
|
||||
('province', models.CharField(blank=True, help_text='省份', max_length=50, null=True, verbose_name='省份')),
|
||||
('city', models.CharField(blank=True, help_text='城市', max_length=50, null=True, verbose_name='城市')),
|
||||
('district', models.CharField(blank=True, help_text='县区', max_length=50, null=True, verbose_name='县区')),
|
||||
('isp', models.CharField(blank=True, help_text='运营商', max_length=50, null=True, verbose_name='运营商')),
|
||||
('area_code', models.CharField(blank=True, help_text='区域代码', max_length=50, null=True, verbose_name='区域代码')),
|
||||
('country_english', models.CharField(blank=True, help_text='英文全称', max_length=50, null=True, verbose_name='英文全称')),
|
||||
('country_code', models.CharField(blank=True, help_text='简称', max_length=50, null=True, verbose_name='简称')),
|
||||
('longitude', models.CharField(blank=True, help_text='经度', max_length=50, null=True, verbose_name='经度')),
|
||||
('latitude', models.CharField(blank=True, help_text='纬度', max_length=50, null=True, verbose_name='纬度')),
|
||||
('login_type', models.IntegerField(choices=[(1, '普通登录'), (2, '微信扫码登录')], default=1, help_text='登录类型', verbose_name='登录类型')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '登录日志',
|
||||
'verbose_name_plural': '登录日志',
|
||||
'db_table': 'dvadmin_system_login_log',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FileList',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(blank=True, help_text='名称', max_length=200, null=True, verbose_name='名称')),
|
||||
('url', models.FileField(blank=True, null=True, upload_to=dvadmin.system.models.media_file_name)),
|
||||
('file_url', models.CharField(blank=True, help_text='文件地址', max_length=255, verbose_name='文件地址')),
|
||||
('engine', models.CharField(blank=True, default='local', help_text='引擎', max_length=100, verbose_name='引擎')),
|
||||
('mime_type', models.CharField(blank=True, help_text='Mime类型', max_length=100, verbose_name='Mime类型')),
|
||||
('size', models.CharField(blank=True, help_text='文件大小', max_length=36, verbose_name='文件大小')),
|
||||
('md5sum', models.CharField(blank=True, help_text='文件md5', max_length=36, verbose_name='文件md5')),
|
||||
('upload_method', models.SmallIntegerField(blank=True, choices=[(0, '默认上传'), (1, '文件选择器上传')], default=0, help_text='上传方式', null=True, verbose_name='上传方式')),
|
||||
('file_type', models.SmallIntegerField(blank=True, choices=[(0, '图片'), (1, '视频'), (2, '音频'), (3, '其他')], default=3, help_text='文件类型', null=True, verbose_name='文件类型')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '文件管理',
|
||||
'verbose_name_plural': '文件管理',
|
||||
'db_table': 'dvadmin_system_file_list',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FieldPermission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('is_query', models.BooleanField(default=1, verbose_name='是否可查询')),
|
||||
('is_create', models.BooleanField(default=1, verbose_name='是否可创建')),
|
||||
('is_update', models.BooleanField(default=1, verbose_name='是否可更新')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('field', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, related_name='menu_field', to='system.menufield', verbose_name='字段')),
|
||||
('role', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='system.role', verbose_name='角色')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '字段权限表',
|
||||
'verbose_name_plural': '字段权限表',
|
||||
'db_table': 'dvadmin_system_field_permission',
|
||||
'ordering': ('id',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DownloadCenter',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('task_name', models.CharField(help_text='任务名称', max_length=255, verbose_name='任务名称')),
|
||||
('task_status', models.SmallIntegerField(choices=[(0, '任务已创建'), (1, '任务进行中'), (2, '任务完成'), (3, '任务失败')], default=0, help_text='是否可下载', verbose_name='是否可下载')),
|
||||
('file_name', models.CharField(blank=True, help_text='文件名', max_length=255, null=True, verbose_name='文件名')),
|
||||
('url', models.FileField(blank=True, null=True, upload_to=dvadmin.system.models.media_file_name_downloadcenter)),
|
||||
('size', models.BigIntegerField(default=0, help_text='文件大小', verbose_name='文件大小')),
|
||||
('md5sum', models.CharField(blank=True, help_text='文件md5', max_length=36, null=True, verbose_name='文件md5')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '下载中心',
|
||||
'verbose_name_plural': '下载中心',
|
||||
'db_table': 'dvadmin_download_center',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Dictionary',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('label', models.CharField(blank=True, help_text='字典名称', max_length=100, null=True, verbose_name='字典名称')),
|
||||
('value', models.CharField(blank=True, help_text='字典编号/实际值', max_length=200, null=True, verbose_name='字典编号')),
|
||||
('type', models.IntegerField(choices=[(0, 'text'), (1, 'number'), (2, 'date'), (3, 'datetime'), (4, 'time'), (5, 'files'), (6, 'boolean'), (7, 'images')], default=0, help_text='数据值类型', verbose_name='数据值类型')),
|
||||
('color', models.CharField(blank=True, help_text='颜色', max_length=20, null=True, verbose_name='颜色')),
|
||||
('is_value', models.BooleanField(default=False, help_text='是否为value值,用来做具体值存放', verbose_name='是否为value值')),
|
||||
('status', models.BooleanField(default=True, help_text='状态', verbose_name='状态')),
|
||||
('sort', models.IntegerField(blank=True, default=1, help_text='显示排序', null=True, verbose_name='显示排序')),
|
||||
('remark', models.CharField(blank=True, help_text='备注', max_length=2000, null=True, verbose_name='备注')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('parent', models.ForeignKey(blank=True, db_constraint=False, help_text='父级', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sublist', to='system.dictionary', verbose_name='父级')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '字典表',
|
||||
'verbose_name_plural': '字典表',
|
||||
'db_table': 'dvadmin_system_dictionary',
|
||||
'ordering': ('sort',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Area',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('name', models.CharField(help_text='名称', max_length=100, verbose_name='名称')),
|
||||
('code', models.CharField(db_index=True, help_text='地区编码', max_length=20, unique=True, verbose_name='地区编码')),
|
||||
('level', models.BigIntegerField(help_text='地区层级(1省份 2城市 3区县 4乡级)', verbose_name='地区层级(1省份 2城市 3区县 4乡级)')),
|
||||
('pinyin', models.CharField(help_text='拼音', max_length=255, verbose_name='拼音')),
|
||||
('initials', models.CharField(help_text='首字母', max_length=20, verbose_name='首字母')),
|
||||
('enable', models.BooleanField(default=True, help_text='是否启用', verbose_name='是否启用')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('pcode', models.ForeignKey(blank=True, db_constraint=False, help_text='父地区编码', null=True, on_delete=django.db.models.deletion.CASCADE, to='system.area', to_field='code', verbose_name='父地区编码')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '地区表',
|
||||
'verbose_name_plural': '地区表',
|
||||
'db_table': 'dvadmin_system_area',
|
||||
'ordering': ('code',),
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ApiWhiteList',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('url', models.CharField(help_text='url地址', max_length=200, verbose_name='url')),
|
||||
('method', models.IntegerField(blank=True, default=0, help_text='接口请求方法', null=True, verbose_name='接口请求方法')),
|
||||
('enable_datasource', models.BooleanField(blank=True, default=True, help_text='激活数据权限', verbose_name='激活数据权限')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '接口白名单',
|
||||
'verbose_name_plural': '接口白名单',
|
||||
'db_table': 'dvadmin_api_white_list',
|
||||
'ordering': ('-create_datetime',),
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='current_role',
|
||||
field=models.ForeignKey(blank=True, db_constraint=False, help_text='当前登录角色', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_role_set', to='system.role', verbose_name='当前登录角色'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='dept',
|
||||
field=models.ForeignKey(blank=True, db_constraint=False, help_text='关联部门', null=True, on_delete=django.db.models.deletion.PROTECT, to='system.dept', verbose_name='所属部门'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='manage_dept',
|
||||
field=models.ManyToManyField(blank=True, db_constraint=False, help_text='管理部门', related_name='manage_dept_set', to='system.dept', verbose_name='管理部门'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='post',
|
||||
field=models.ManyToManyField(blank=True, db_constraint=False, help_text='关联岗位', to='system.post', verbose_name='关联岗位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='role',
|
||||
field=models.ManyToManyField(blank=True, db_constraint=False, help_text='关联角色', to='system.role', verbose_name='关联角色'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='users',
|
||||
name='user_permissions',
|
||||
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SystemConfig',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('description', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('modifier', models.CharField(blank=True, help_text='修改人', max_length=255, null=True, verbose_name='修改人')),
|
||||
('dept_belong_id', models.CharField(blank=True, help_text='数据归属部门', max_length=255, null=True, verbose_name='数据归属部门')),
|
||||
('update_datetime', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('title', models.CharField(help_text='标题', max_length=50, verbose_name='标题')),
|
||||
('key', models.CharField(db_index=True, help_text='键', max_length=100, verbose_name='键')),
|
||||
('value', models.JSONField(blank=True, help_text='值', max_length=100, null=True, verbose_name='值')),
|
||||
('sort', models.IntegerField(blank=True, default=0, help_text='排序', verbose_name='排序')),
|
||||
('status', models.BooleanField(default=True, help_text='启用状态', verbose_name='启用状态')),
|
||||
('data_options', models.JSONField(blank=True, help_text='数据options', null=True, verbose_name='数据options')),
|
||||
('form_item_type', models.IntegerField(blank=True, choices=[(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')], default=0, help_text='表单类型', verbose_name='表单类型')),
|
||||
('rule', models.JSONField(blank=True, help_text='校验规则', null=True, verbose_name='校验规则')),
|
||||
('placeholder', models.CharField(blank=True, help_text='提示信息', max_length=50, null=True, verbose_name='提示信息')),
|
||||
('setting', models.JSONField(blank=True, help_text='配置', null=True, verbose_name='配置')),
|
||||
('creator', models.ForeignKey(db_constraint=False, help_text='创建人', null=True, on_delete=django.db.models.deletion.SET_NULL, related_query_name='creator_query', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('parent', models.ForeignKey(blank=True, db_constraint=False, help_text='父级', null=True, on_delete=django.db.models.deletion.CASCADE, to='system.systemconfig', verbose_name='父级')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '系统配置表',
|
||||
'verbose_name_plural': '系统配置表',
|
||||
'db_table': 'dvadmin_system_config',
|
||||
'ordering': ('sort',),
|
||||
'unique_together': {('key', 'parent_id')},
|
||||
},
|
||||
),
|
||||
]
|
||||
0
dvadmin/system/migrations/__init__.py
Normal file
0
dvadmin/system/migrations/__init__.py
Normal file
Binary file not shown.
BIN
dvadmin/system/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/system/migrations/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
687
dvadmin/system/models.py
Normal file
687
dvadmin/system/models.py
Normal file
@ -0,0 +1,687 @@
|
||||
import hashlib
|
||||
import os
|
||||
from time import time
|
||||
from pathlib import PurePosixPath
|
||||
|
||||
from django.contrib.auth.models import AbstractUser, UserManager
|
||||
from django.db import models
|
||||
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||
from application import dispatch
|
||||
from dvadmin.utils.models import CoreModel, table_prefix, get_custom_app_models
|
||||
|
||||
|
||||
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="权限字符")
|
||||
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
|
||||
status = models.BooleanField(default=True, verbose_name="角色状态", help_text="角色状态")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_role"
|
||||
verbose_name = "角色表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class CustomUserManager(UserManager):
|
||||
|
||||
def create_superuser(self, username, email=None, password=None, **extra_fields):
|
||||
user = super(CustomUserManager, self).create_superuser(username, email, password, **extra_fields)
|
||||
user.set_password(password)
|
||||
try:
|
||||
user.role.add(Role.objects.get(name="管理员"))
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
except ObjectDoesNotExist:
|
||||
user.delete()
|
||||
raise ValidationError("角色`管理员`不存在, 创建失败, 请先执行python manage.py init")
|
||||
|
||||
|
||||
class Users(CoreModel, AbstractUser):
|
||||
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="性别"
|
||||
)
|
||||
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", blank=True, verbose_name="关联岗位", db_constraint=False,
|
||||
help_text="关联岗位")
|
||||
role = models.ManyToManyField(to="Role", blank=True, verbose_name="关联角色", db_constraint=False,
|
||||
help_text="关联角色")
|
||||
current_role = models.ForeignKey(to=Role, null=True, blank=True, db_constraint=False, on_delete=models.SET_NULL,
|
||||
verbose_name="当前登录角色", help_text="当前登录角色", related_name='current_role_set')
|
||||
dept = models.ForeignKey(
|
||||
to="Dept",
|
||||
verbose_name="所属部门",
|
||||
on_delete=models.PROTECT,
|
||||
db_constraint=False,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="关联部门",
|
||||
)
|
||||
manage_dept = models.ManyToManyField(
|
||||
to="Dept",
|
||||
verbose_name="管理部门",
|
||||
db_constraint=False,
|
||||
blank=True,
|
||||
help_text="管理部门",
|
||||
related_name='manage_dept_set'
|
||||
)
|
||||
login_error_count = models.IntegerField(default=0, verbose_name="登录错误次数", help_text="登录错误次数")
|
||||
pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数")
|
||||
objects = CustomUserManager()
|
||||
|
||||
def set_password(self, raw_password):
|
||||
if raw_password:
|
||||
super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest())
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.name == "":
|
||||
self.name = self.username
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_users"
|
||||
verbose_name = "用户表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class Post(CoreModel):
|
||||
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="岗位状态")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_post"
|
||||
verbose_name = "岗位表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
class Dept(CoreModel):
|
||||
name = models.CharField(max_length=64, verbose_name="部门名称", help_text="部门名称")
|
||||
key = models.CharField(max_length=64, unique=True, null=True, blank=True, 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="上级部门",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _recursion(cls, instance, parent, result):
|
||||
new_instance = getattr(instance, parent, None)
|
||||
res = []
|
||||
data = getattr(instance, result, None)
|
||||
if data:
|
||||
res.append(data)
|
||||
if new_instance:
|
||||
array = cls._recursion(new_instance, parent, result)
|
||||
res += array
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def get_region_name(cls, obj):
|
||||
"""
|
||||
获取某个用户的递归所有部门名称
|
||||
"""
|
||||
dept_name_all = cls._recursion(obj, "parent", "name")
|
||||
dept_name_all.reverse()
|
||||
return "/".join(dept_name_all)
|
||||
|
||||
@classmethod
|
||||
def recursion_all_dept(cls, dept_id: int, dept_all_list=None, dept_list=None):
|
||||
"""
|
||||
递归获取部门的所有下级部门
|
||||
:param dept_id: 需要获取的id
|
||||
:param dept_all_list: 所有列表
|
||||
:param dept_list: 递归list
|
||||
:return:
|
||||
"""
|
||||
if not dept_all_list:
|
||||
dept_all_list = Dept.objects.values("id", "parent")
|
||||
if dept_list is None:
|
||||
dept_list = [dept_id]
|
||||
for ele in dept_all_list:
|
||||
if ele.get("parent") == dept_id:
|
||||
dept_list.append(ele.get("id"))
|
||||
cls.recursion_all_dept(ele.get("id"), dept_all_list, dept_list)
|
||||
return list(set(dept_list))
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_dept"
|
||||
verbose_name = "部门表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
|
||||
|
||||
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="菜单图标")
|
||||
name = models.CharField(max_length=64, verbose_name="菜单名称", 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="是否外链")
|
||||
link_url = models.CharField(max_length=255, verbose_name="链接地址", null=True, blank=True, 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_iframe = models.BooleanField(default=False, blank=True, verbose_name="框架外显示", help_text="框架外显示")
|
||||
is_affix = models.BooleanField(default=False, blank=True, verbose_name="是否固定", help_text="是否固定")
|
||||
|
||||
@classmethod
|
||||
def get_all_parent(cls, id: int, all_list=None, nodes=None):
|
||||
"""
|
||||
递归获取给定ID的所有层级
|
||||
:param id: 参数ID
|
||||
:param all_list: 所有列表
|
||||
:param nodes: 递归列表
|
||||
:return: nodes
|
||||
"""
|
||||
if not all_list:
|
||||
all_list = Menu.objects.values("id", "name", "parent")
|
||||
if nodes is None:
|
||||
nodes = []
|
||||
for ele in all_list:
|
||||
if ele.get("id") == id:
|
||||
parent_id = ele.get("parent")
|
||||
if parent_id is not None:
|
||||
cls.get_all_parent(parent_id, all_list, nodes)
|
||||
nodes.append(ele)
|
||||
return nodes
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_menu"
|
||||
verbose_name = "菜单表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
|
||||
class MenuField(CoreModel):
|
||||
model = models.CharField(max_length=64, verbose_name='表名')
|
||||
menu = models.ForeignKey(to='Menu', on_delete=models.CASCADE, verbose_name='菜单', db_constraint=False)
|
||||
field_name = models.CharField(max_length=64, verbose_name='模型表字段名')
|
||||
title = models.CharField(max_length=64, verbose_name='字段显示名')
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_menu_field"
|
||||
verbose_name = "菜单字段表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("id",)
|
||||
|
||||
class FieldPermission(CoreModel):
|
||||
role = models.ForeignKey(to='Role', on_delete=models.CASCADE, verbose_name='角色', db_constraint=False)
|
||||
field = models.ForeignKey(to='MenuField', on_delete=models.CASCADE,related_name='menu_field', verbose_name='字段', db_constraint=False)
|
||||
is_query = models.BooleanField(default=1, verbose_name='是否可查询')
|
||||
is_create = models.BooleanField(default=1, verbose_name='是否可创建')
|
||||
is_update = models.BooleanField(default=1, verbose_name='是否可更新')
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_field_permission"
|
||||
verbose_name = "字段权限表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("id",)
|
||||
|
||||
|
||||
class MenuButton(CoreModel):
|
||||
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(unique=True, max_length=64, verbose_name="权限值", help_text="权限值")
|
||||
api = models.CharField(max_length=200, verbose_name="接口地址", help_text="接口地址")
|
||||
METHOD_CHOICES = (
|
||||
(0, "GET"),
|
||||
(1, "POST"),
|
||||
(2, "PUT"),
|
||||
(3, "DELETE"),
|
||||
)
|
||||
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_plural = verbose_name
|
||||
ordering = ("-name",)
|
||||
|
||||
|
||||
class RoleMenuPermission(CoreModel):
|
||||
role = models.ForeignKey(
|
||||
to="Role",
|
||||
db_constraint=False,
|
||||
related_name="role_menu",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="关联角色",
|
||||
help_text="关联角色",
|
||||
)
|
||||
menu = models.ForeignKey(
|
||||
to="Menu",
|
||||
db_constraint=False,
|
||||
related_name="role_menu",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="关联菜单",
|
||||
help_text="关联菜单",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "role_menu_permission"
|
||||
verbose_name = "角色菜单权限表"
|
||||
verbose_name_plural = verbose_name
|
||||
# ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class RoleMenuButtonPermission(CoreModel):
|
||||
role = models.ForeignKey(
|
||||
to="Role",
|
||||
db_constraint=False,
|
||||
related_name="role_menu_button",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="关联角色",
|
||||
help_text="关联角色",
|
||||
)
|
||||
menu_button = models.ForeignKey(
|
||||
to="MenuButton",
|
||||
db_constraint=False,
|
||||
related_name="menu_button_permission",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="关联菜单按钮",
|
||||
help_text="关联菜单按钮",
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
DATASCOPE_CHOICES = (
|
||||
(0, "仅本人数据权限"),
|
||||
(1, "本部门及以下数据权限"),
|
||||
(2, "本部门数据权限"),
|
||||
(3, "全部数据权限"),
|
||||
(4, "自定数据权限"),
|
||||
)
|
||||
data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围",
|
||||
help_text="数据权限范围")
|
||||
dept = models.ManyToManyField(to="Dept", blank=True, verbose_name="数据权限-关联部门", db_constraint=False,
|
||||
help_text="数据权限-关联部门")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "role_menu_button_permission"
|
||||
verbose_name = "角色按钮权限表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class Dictionary(CoreModel):
|
||||
TYPE_LIST = (
|
||||
(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="字典编号/实际值")
|
||||
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="备注")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_dictionary"
|
||||
verbose_name = "字典表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("sort",)
|
||||
|
||||
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() # 有更新则刷新字典配置
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
res = super().delete(using, keep_parents)
|
||||
dispatch.refresh_dictionary()
|
||||
return res
|
||||
|
||||
|
||||
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="返回信息")
|
||||
status = models.BooleanField(default=False, verbose_name="响应状态", help_text="响应状态")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_operation_log"
|
||||
verbose_name = "操作日志"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
def media_file_name(instance, filename):
|
||||
h = instance.md5sum
|
||||
basename, ext = os.path.splitext(filename)
|
||||
return os.path.join("files", h[:1], h[1:2], h + ext.lower())
|
||||
|
||||
|
||||
class FileList(CoreModel):
|
||||
name = models.CharField(max_length=200, null=True, blank=True, verbose_name="名称", help_text="名称")
|
||||
url = models.FileField(upload_to=media_file_name, null=True, blank=True,)
|
||||
file_url = models.CharField(max_length=255, blank=True, verbose_name="文件地址", help_text="文件地址")
|
||||
engine = models.CharField(max_length=100, default='local', blank=True, verbose_name="引擎", help_text="引擎")
|
||||
mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型")
|
||||
size = models.CharField(max_length=36, blank=True, verbose_name="文件大小", help_text="文件大小")
|
||||
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||
UPLOAD_METHOD_CHOIDES = (
|
||||
(0, '默认上传'),
|
||||
(1, '文件选择器上传'),
|
||||
)
|
||||
upload_method = models.SmallIntegerField(default=0, blank=True, null=True, choices=UPLOAD_METHOD_CHOIDES, verbose_name='上传方式', help_text='上传方式')
|
||||
FILE_TYPE_CHOIDES = (
|
||||
(0, '图片'),
|
||||
(1, '视频'),
|
||||
(2, '音频'),
|
||||
(3, '其他'),
|
||||
)
|
||||
file_type = models.SmallIntegerField(default=3, choices=FILE_TYPE_CHOIDES, blank=True, null=True, verbose_name='文件类型', help_text='文件类型')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.md5sum: # file is new
|
||||
md5 = hashlib.md5()
|
||||
for chunk in self.url.chunks():
|
||||
md5.update(chunk)
|
||||
self.md5sum = md5.hexdigest()
|
||||
if not self.size:
|
||||
self.size = self.url.size
|
||||
if not self.file_url:
|
||||
url = media_file_name(self, self.name)
|
||||
self.file_url = f'media/{url}'
|
||||
super(FileList, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_file_list"
|
||||
verbose_name = "文件管理"
|
||||
verbose_name_plural = verbose_name
|
||||
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乡级)")
|
||||
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="父地区编码",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_area"
|
||||
verbose_name = "地区表"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("code",)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
|
||||
class ApiWhiteList(CoreModel):
|
||||
url = models.CharField(max_length=200, help_text="url地址", verbose_name="url")
|
||||
METHOD_CHOICES = (
|
||||
(0, "GET"),
|
||||
(1, "POST"),
|
||||
(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)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "api_white_list"
|
||||
verbose_name = "接口白名单"
|
||||
verbose_name_plural = verbose_name
|
||||
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="父级",
|
||||
)
|
||||
title = models.CharField(max_length=50, verbose_name="标题", help_text="标题")
|
||||
key = models.CharField(max_length=100, 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"),
|
||||
)
|
||||
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="配置")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "system_config"
|
||||
verbose_name = "系统配置表"
|
||||
verbose_name_plural = verbose_name
|
||||
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):
|
||||
super().save(force_insert, force_update, using, update_fields)
|
||||
dispatch.refresh_system_config() # 有更新则刷新系统配置
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
res = super().delete(using, keep_parents)
|
||||
dispatch.refresh_system_config()
|
||||
return res
|
||||
|
||||
|
||||
class LoginLog(CoreModel):
|
||||
LOGIN_TYPE_CHOICES = ((1, "普通登录"), (2, "微信扫码登录"),)
|
||||
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 = "登录日志"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class MessageCenter(CoreModel):
|
||||
title = models.CharField(max_length=100, verbose_name="标题", help_text="标题")
|
||||
content = models.TextField(verbose_name="内容", help_text="内容")
|
||||
target_type = models.IntegerField(default=0, verbose_name="目标类型", help_text="目标类型")
|
||||
target_user = models.ManyToManyField(to=Users, related_name='user', through='MessageCenterTargetUser',
|
||||
through_fields=('messagecenter', 'users'), blank=True, verbose_name="目标用户",
|
||||
help_text="目标用户")
|
||||
target_dept = models.ManyToManyField(to=Dept, blank=True, db_constraint=False,
|
||||
verbose_name="目标部门", help_text="目标部门")
|
||||
target_role = models.ManyToManyField(to=Role, blank=True, db_constraint=False,
|
||||
verbose_name="目标角色", help_text="目标角色")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "message_center"
|
||||
verbose_name = "消息中心"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
|
||||
class MessageCenterTargetUser(CoreModel):
|
||||
users = models.ForeignKey(Users, related_name="target_user", on_delete=models.CASCADE, db_constraint=False,
|
||||
verbose_name="关联用户表", help_text="关联用户表")
|
||||
messagecenter = models.ForeignKey(MessageCenter, on_delete=models.CASCADE, db_constraint=False,
|
||||
verbose_name="关联消息中心表", help_text="关联消息中心表")
|
||||
is_read = models.BooleanField(default=False, blank=True, null=True, verbose_name="是否已读", help_text="是否已读")
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "message_center_target_user"
|
||||
verbose_name = "消息中心目标用户表"
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
def media_file_name_downloadcenter(instance:'DownloadCenter', filename):
|
||||
h = instance.md5sum
|
||||
basename, ext = os.path.splitext(filename)
|
||||
return PurePosixPath("files", "dlct", h[:1], h[1:2], basename + '-' + str(time()).replace('.', '') + ext.lower())
|
||||
|
||||
|
||||
class DownloadCenter(CoreModel):
|
||||
TASK_STATUS_CHOICES = [
|
||||
(0, '任务已创建'),
|
||||
(1, '任务进行中'),
|
||||
(2, '任务完成'),
|
||||
(3, '任务失败'),
|
||||
]
|
||||
task_name = models.CharField(max_length=255, verbose_name="任务名称", help_text="任务名称")
|
||||
task_status = models.SmallIntegerField(default=0, choices=TASK_STATUS_CHOICES, verbose_name='是否可下载', help_text='是否可下载')
|
||||
file_name = models.CharField(max_length=255, null=True, blank=True, verbose_name="文件名", help_text="文件名")
|
||||
url = models.FileField(upload_to=media_file_name_downloadcenter, null=True, blank=True)
|
||||
size = models.BigIntegerField(default=0, verbose_name="文件大小", help_text="文件大小")
|
||||
md5sum = models.CharField(max_length=36, null=True, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.url:
|
||||
if not self.md5sum: # file is new
|
||||
md5 = hashlib.md5()
|
||||
for chunk in self.url.chunks():
|
||||
md5.update(chunk)
|
||||
self.md5sum = md5.hexdigest()
|
||||
if not self.size:
|
||||
self.size = self.url.size
|
||||
super(DownloadCenter, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "download_center"
|
||||
verbose_name = "下载中心"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
27
dvadmin/system/signals.py
Normal file
27
dvadmin/system/signals.py
Normal file
@ -0,0 +1,27 @@
|
||||
import time
|
||||
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import Signal, receiver
|
||||
from django.core.cache import cache
|
||||
from dvadmin.system.models import MessageCenterTargetUser
|
||||
|
||||
# 初始化信号
|
||||
pre_init_complete = Signal()
|
||||
detail_init_complete = Signal()
|
||||
post_init_complete = Signal()
|
||||
# 租户初始化信号
|
||||
pre_tenants_init_complete = Signal()
|
||||
detail_tenants_init_complete = Signal()
|
||||
post_tenants_init_complete = Signal()
|
||||
post_tenants_all_init_complete = Signal()
|
||||
# 租户创建完成信号
|
||||
tenants_create_complete = Signal()
|
||||
|
||||
# 全局变量用于标记最后修改时间
|
||||
last_db_change_time = time.time()
|
||||
|
||||
|
||||
@receiver(post_save, sender=MessageCenterTargetUser)
|
||||
@receiver(post_delete, sender=MessageCenterTargetUser)
|
||||
def update_last_change_time(sender, **kwargs):
|
||||
cache.set('last_db_change_time', time.time(), timeout=None) # 设置永不超时的键值对
|
||||
107
dvadmin/system/tasks.py
Normal file
107
dvadmin/system/tasks.py
Normal file
@ -0,0 +1,107 @@
|
||||
from hashlib import md5
|
||||
from io import BytesIO
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.worksheet.table import Table, TableStyleInfo
|
||||
from openpyxl.utils import get_column_letter
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from application.celery import app
|
||||
from dvadmin.system.models import DownloadCenter
|
||||
|
||||
def is_number(num):
|
||||
try:
|
||||
float(num)
|
||||
return True
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import unicodedata
|
||||
unicodedata.numeric(num)
|
||||
return True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
return False
|
||||
|
||||
def get_string_len(string):
|
||||
"""
|
||||
获取字符串最大长度
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
length = 4
|
||||
if string is None:
|
||||
return length
|
||||
if is_number(string):
|
||||
return length
|
||||
for char in string:
|
||||
length += 2.1 if ord(char) > 256 else 1
|
||||
return round(length, 1) if length <= 50 else 50
|
||||
|
||||
@app.task
|
||||
def async_export_data(data: list, filename: str, dcid: int, export_field_label: dict):
|
||||
instance = DownloadCenter.objects.get(pk=dcid)
|
||||
instance.task_status = 1
|
||||
instance.save()
|
||||
sleep(2)
|
||||
try:
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
header_data = ["序号", *export_field_label.values()]
|
||||
hidden_header = ["#", *export_field_label.keys()]
|
||||
df_len_max = [get_string_len(ele) for ele in header_data]
|
||||
row = get_column_letter(len(export_field_label) + 1)
|
||||
column = 1
|
||||
ws.append(header_data)
|
||||
for index, results in enumerate(data):
|
||||
results_list = []
|
||||
for h_index, h_item in enumerate(hidden_header):
|
||||
for key, val in results.items():
|
||||
if key == h_item:
|
||||
if val is None or val == "":
|
||||
results_list.append("")
|
||||
elif isinstance(val, datetime):
|
||||
val = val.strftime("%Y-%m-%d %H:%M:%S")
|
||||
results_list.append(val)
|
||||
else:
|
||||
results_list.append(val)
|
||||
# 计算最大列宽度
|
||||
result_column_width = get_string_len(val)
|
||||
if h_index != 0 and result_column_width > df_len_max[h_index]:
|
||||
df_len_max[h_index] = result_column_width
|
||||
ws.append([index + 1, *results_list])
|
||||
column += 1
|
||||
# 更新列宽
|
||||
for index, width in enumerate(df_len_max):
|
||||
ws.column_dimensions[get_column_letter(index + 1)].width = width
|
||||
tab = Table(displayName="Table", ref=f"A1:{row}{column}") # 名称管理器
|
||||
style = TableStyleInfo(
|
||||
name="TableStyleLight11",
|
||||
showFirstColumn=True,
|
||||
showLastColumn=True,
|
||||
showRowStripes=True,
|
||||
showColumnStripes=True,
|
||||
)
|
||||
tab.tableStyleInfo = style
|
||||
ws.add_table(tab)
|
||||
stream = BytesIO()
|
||||
wb.save(stream)
|
||||
stream.seek(0)
|
||||
s = md5()
|
||||
while True:
|
||||
chunk = stream.read(1024)
|
||||
if not chunk:
|
||||
break
|
||||
s.update(chunk)
|
||||
stream.seek(0)
|
||||
instance.md5sum = s.hexdigest()
|
||||
instance.file_name = filename
|
||||
instance.url.save(filename, ContentFile(stream.read()))
|
||||
instance.task_status = 2
|
||||
except Exception as e:
|
||||
instance.task_status = 3
|
||||
instance.description = str(e)[:250]
|
||||
instance.save()
|
||||
56
dvadmin/system/tests.py
Normal file
56
dvadmin/system/tests.py
Normal file
@ -0,0 +1,56 @@
|
||||
from functools import wraps
|
||||
|
||||
from django.db.models import Func, F, OuterRef, Exists
|
||||
from django.test import TestCase
|
||||
import django
|
||||
import os
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "application.settings")
|
||||
django.setup()
|
||||
from dvadmin.system.models import Menu, RoleMenuPermission, RoleMenuButtonPermission, MenuButton
|
||||
|
||||
|
||||
import time
|
||||
|
||||
def timing_decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
start_time = time.time()
|
||||
result = func(*args, **kwargs)
|
||||
end_time = time.time()
|
||||
run_time = end_time - start_time
|
||||
print(f"{func.__name__} ran in {run_time:.6f} seconds")
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
@timing_decorator
|
||||
def getMenu():
|
||||
data = []
|
||||
queryset = Menu.objects.filter(status=1, is_catalog=False).values('name', 'id')
|
||||
for item in queryset:
|
||||
parent_list = Menu.get_all_parent(item['id'])
|
||||
names = [d["name"] for d in parent_list]
|
||||
completeName = "/".join(names)
|
||||
isCheck = RoleMenuPermission.objects.filter(
|
||||
menu__id=item['id'],
|
||||
role__id=1,
|
||||
).exists()
|
||||
mbCheck = RoleMenuButtonPermission.objects.filter(
|
||||
menu_button = OuterRef("pk"),
|
||||
role__id=1,
|
||||
)
|
||||
btns = MenuButton.objects.filter(
|
||||
menu__id=item['id'],
|
||||
).annotate(isCheck=Exists(mbCheck)).values('id', 'name', 'value', 'isCheck',data_range=F('menu_button_permission__data_range'))
|
||||
# print(b)
|
||||
dicts = {
|
||||
'name': completeName,
|
||||
'id': item['id'],
|
||||
'isCheck': isCheck,
|
||||
'btns':btns
|
||||
}
|
||||
print(dicts)
|
||||
data.append(dicts)
|
||||
# print(data)
|
||||
|
||||
if __name__ == '__main__':
|
||||
getMenu()
|
||||
56
dvadmin/system/urls.py
Normal file
56
dvadmin/system/urls.py
Normal file
@ -0,0 +1,56 @@
|
||||
from django.urls import path
|
||||
from rest_framework import routers
|
||||
|
||||
from dvadmin.system.views.api_white_list import ApiWhiteListViewSet
|
||||
from dvadmin.system.views.area import AreaViewSet
|
||||
from dvadmin.system.views.clause import PrivacyView, TermsServiceView
|
||||
from dvadmin.system.views.dept import DeptViewSet
|
||||
from dvadmin.system.views.dictionary import DictionaryViewSet
|
||||
from dvadmin.system.views.file_list import FileViewSet
|
||||
from dvadmin.system.views.login_log import LoginLogViewSet
|
||||
from dvadmin.system.views.menu import MenuViewSet
|
||||
from dvadmin.system.views.menu_button import MenuButtonViewSet
|
||||
from dvadmin.system.views.message_center import MessageCenterViewSet
|
||||
from dvadmin.system.views.operation_log import OperationLogViewSet
|
||||
from dvadmin.system.views.role import RoleViewSet
|
||||
from dvadmin.system.views.role_menu import RoleMenuPermissionViewSet
|
||||
from dvadmin.system.views.role_menu_button_permission import RoleMenuButtonPermissionViewSet
|
||||
from dvadmin.system.views.system_config import SystemConfigViewSet
|
||||
from dvadmin.system.views.user import UserViewSet
|
||||
from dvadmin.system.views.menu_field import MenuFieldViewSet
|
||||
from dvadmin.system.views.download_center import DownloadCenterViewSet
|
||||
|
||||
system_url = routers.SimpleRouter()
|
||||
system_url.register(r'menu', MenuViewSet)
|
||||
system_url.register(r'menu_button', MenuButtonViewSet)
|
||||
system_url.register(r'role', RoleViewSet)
|
||||
system_url.register(r'dept', DeptViewSet)
|
||||
system_url.register(r'user', UserViewSet)
|
||||
system_url.register(r'operation_log', OperationLogViewSet)
|
||||
system_url.register(r'dictionary', DictionaryViewSet)
|
||||
system_url.register(r'area', AreaViewSet)
|
||||
system_url.register(r'file', FileViewSet)
|
||||
system_url.register(r'api_white_list', ApiWhiteListViewSet)
|
||||
system_url.register(r'system_config', SystemConfigViewSet)
|
||||
system_url.register(r'message_center', MessageCenterViewSet)
|
||||
system_url.register(r'role_menu_button_permission', RoleMenuButtonPermissionViewSet)
|
||||
system_url.register(r'role_menu_permission', RoleMenuPermissionViewSet)
|
||||
system_url.register(r'column', MenuFieldViewSet)
|
||||
system_url.register(r'login_log', LoginLogViewSet)
|
||||
system_url.register(r'download_center', DownloadCenterViewSet)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('user/export/', UserViewSet.as_view({'post': 'export_data', })),
|
||||
path('user/import/', UserViewSet.as_view({'get': 'import_data', 'post': 'import_data'})),
|
||||
path('system_config/save_content/', SystemConfigViewSet.as_view({'put': 'save_content'})),
|
||||
path('system_config/get_association_table/', SystemConfigViewSet.as_view({'get': 'get_association_table'})),
|
||||
path('system_config/get_table_data/<int:pk>/', SystemConfigViewSet.as_view({'get': 'get_table_data'})),
|
||||
path('system_config/get_relation_info/', SystemConfigViewSet.as_view({'get': 'get_relation_info'})),
|
||||
# path('login_log/', LoginLogViewSet.as_view({'get': 'list'})),
|
||||
# path('login_log/<int:pk>/', LoginLogViewSet.as_view({'get': 'retrieve'})),
|
||||
# path('dept_lazy_tree/', DeptViewSet.as_view({'get': 'dept_lazy_tree'})),
|
||||
path('clause/privacy.html', PrivacyView.as_view()),
|
||||
path('clause/terms_service.html', TermsServiceView.as_view()),
|
||||
]
|
||||
urlpatterns += system_url.urls
|
||||
1
dvadmin/system/util/pca-code.json
Normal file
1
dvadmin/system/util/pca-code.json
Normal file
File diff suppressed because one or more lines are too long
0
dvadmin/system/views/__init__.py
Normal file
0
dvadmin/system/views/__init__.py
Normal file
BIN
dvadmin/system/views/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/api_white_list.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/api_white_list.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/area.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/area.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/clause.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/clause.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/dept.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/dept.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/dictionary.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/dictionary.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/download_center.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/download_center.cpython-311.pyc
Normal file
Binary file not shown.
BIN
dvadmin/system/views/__pycache__/file_list.cpython-311.pyc
Normal file
BIN
dvadmin/system/views/__pycache__/file_list.cpython-311.pyc
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user