优化:字段长度优化
							parent
							
								
									03455ba9d0
								
							
						
					
					
						commit
						d31d9fc3ca
					
				|  | @ -3,6 +3,7 @@ | |||
| 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 | ||||
| 
 | ||||
|  | @ -159,7 +160,7 @@ def get_dictionary_config(schema_name=None): | |||
|         init_dictionary_data = cache.get(f"init_dictionary") | ||||
|         if not init_dictionary_data: | ||||
|             refresh_dictionary() | ||||
|         return cache.get(f"init_dictionary")  or {} | ||||
|         return cache.get(f"init_dictionary") or {} | ||||
|     if not settings.DICTIONARY_CONFIG: | ||||
|         refresh_dictionary() | ||||
|     if is_tenants_mode(): | ||||
|  | @ -243,6 +244,22 @@ def get_system_config_values(key, schema_name=None): | |||
|     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值 | ||||
|  |  | |||
|  | @ -13,8 +13,11 @@ STATUS_CHOICES = ( | |||
| ) | ||||
| 
 | ||||
| 
 | ||||
| class Users(CoreModel,AbstractUser): | ||||
|     username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name="用户账号", help_text="用户账号") | ||||
| class Users(CoreModel, AbstractUser): | ||||
|     username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name="用户账号", | ||||
|                                 help_text="用户账号") | ||||
|     employee_no = models.CharField(max_length=150, unique=True, db_index=True, null=True, blank=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="头像") | ||||
|  | @ -34,8 +37,10 @@ class Users(CoreModel,AbstractUser): | |||
|     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="关联角色") | ||||
|     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="关联角色") | ||||
|     dept = models.ForeignKey( | ||||
|         to="Dept", | ||||
|         verbose_name="所属部门", | ||||
|  | @ -45,7 +50,8 @@ class Users(CoreModel,AbstractUser): | |||
|         blank=True, | ||||
|         help_text="关联部门", | ||||
|     ) | ||||
|     last_token = models.CharField(max_length=255,null=True,blank=True, verbose_name="最后一次登录Token", help_text="最后一次登录Token") | ||||
|     last_token = models.CharField(max_length=255, null=True, blank=True, verbose_name="最后一次登录Token", | ||||
|                                   help_text="最后一次登录Token") | ||||
| 
 | ||||
|     def set_password(self, raw_password): | ||||
|         super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest()) | ||||
|  | @ -87,9 +93,11 @@ class Role(CoreModel): | |||
|         (3, "全部数据权限"), | ||||
|         (4, "自定数据权限"), | ||||
|     ) | ||||
|     data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", help_text="数据权限范围") | ||||
|     data_range = models.IntegerField(default=0, choices=DATASCOPE_CHOICES, verbose_name="数据权限范围", | ||||
|                                      help_text="数据权限范围") | ||||
|     remark = models.TextField(verbose_name="备注", help_text="备注", null=True, blank=True) | ||||
|     dept = models.ManyToManyField(to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, help_text="数据权限-关联部门") | ||||
|     dept = models.ManyToManyField(to="Dept", verbose_name="数据权限-关联部门", db_constraint=False, | ||||
|                                   help_text="数据权限-关联部门") | ||||
|     menu = models.ManyToManyField(to="Menu", verbose_name="关联菜单", db_constraint=False, help_text="关联菜单") | ||||
|     permission = models.ManyToManyField( | ||||
|         to="MenuButton", verbose_name="关联菜单的接口按钮", db_constraint=False, help_text="关联菜单的接口按钮" | ||||
|  | @ -104,7 +112,8 @@ class Role(CoreModel): | |||
| 
 | ||||
| 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="关联字符") | ||||
|     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="联系电话") | ||||
|  | @ -168,10 +177,12 @@ class Menu(CoreModel): | |||
|     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="组件名称") | ||||
|     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="侧边栏中是否显示") | ||||
|     visible = models.BooleanField(default=True, blank=True, verbose_name="侧边栏中是否显示", | ||||
|                                   help_text="侧边栏中是否显示") | ||||
| 
 | ||||
|     class Meta: | ||||
|         db_table = table_prefix + "system_menu" | ||||
|  | @ -198,7 +209,8 @@ class MenuButton(CoreModel): | |||
|         (2, "PUT"), | ||||
|         (3, "DELETE"), | ||||
|     ) | ||||
|     method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法") | ||||
|     method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, | ||||
|                                  help_text="接口请求方法") | ||||
| 
 | ||||
|     class Meta: | ||||
|         db_table = table_prefix + "system_menu_button" | ||||
|  | @ -219,7 +231,8 @@ class Dictionary(CoreModel): | |||
|         (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="字典编号/实际值") | ||||
|     value = models.CharField(max_length=200, blank=True, null=True, verbose_name="字典编号", | ||||
|                              help_text="字典编号/实际值") | ||||
|     parent = models.ForeignKey( | ||||
|         to="self", | ||||
|         related_name="sublist", | ||||
|  | @ -232,7 +245,8 @@ class Dictionary(CoreModel): | |||
|     ) | ||||
|     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值,用来做具体值存放") | ||||
|     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="备注") | ||||
|  | @ -254,14 +268,20 @@ class Dictionary(CoreModel): | |||
| 
 | ||||
| 
 | ||||
| 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_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_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_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="响应状态") | ||||
|  | @ -302,7 +322,8 @@ class FileList(CoreModel): | |||
| 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乡级)") | ||||
|     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="是否启用") | ||||
|  | @ -335,8 +356,10 @@ class ApiWhiteList(CoreModel): | |||
|         (2, "PUT"), | ||||
|         (3, "DELETE"), | ||||
|     ) | ||||
|     method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, help_text="接口请求方法") | ||||
|     enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限", blank=True) | ||||
|     method = models.IntegerField(default=0, verbose_name="接口请求方法", null=True, blank=True, | ||||
|                                  help_text="接口请求方法") | ||||
|     enable_datasource = models.BooleanField(default=True, verbose_name="激活数据权限", help_text="激活数据权限", | ||||
|                                             blank=True) | ||||
| 
 | ||||
|     class Meta: | ||||
|         db_table = table_prefix + "api_white_list" | ||||
|  | @ -356,8 +379,8 @@ class SystemConfig(CoreModel): | |||
|         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=200, verbose_name="值", help_text="值", null=True, blank=True) | ||||
|     key = models.CharField(max_length=200, verbose_name="键", help_text="键", db_index=True) | ||||
|     value = models.JSONField(max_length=500, 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) | ||||
|  | @ -383,7 +406,7 @@ class SystemConfig(CoreModel): | |||
|         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="提示信息") | ||||
|     placeholder = models.CharField(max_length=100, null=True, blank=True, verbose_name="提示信息", help_text="提示信息") | ||||
|     setting = models.JSONField(null=True, blank=True, verbose_name="配置", help_text="配置") | ||||
| 
 | ||||
|     class Meta: | ||||
|  | @ -415,8 +438,15 @@ class SystemConfig(CoreModel): | |||
| 
 | ||||
| 
 | ||||
| class LoginLog(CoreModel): | ||||
|     LOGIN_TYPE_CHOICES = ((1, "普通登录"), (2, "微信扫码登录"), (3, "飞书扫码登录"), (4, "钉钉扫码登录")) | ||||
|     username = models.CharField(max_length=32, verbose_name="登录用户名", null=True, blank=True, help_text="登录用户名") | ||||
|     LOGIN_TYPE_CHOICES = ( | ||||
|         (1, "普通登录"), | ||||
|         (2, "普通扫码登录"), | ||||
|         (3, "微信扫码登录"), | ||||
|         (4, "飞书扫码登录"), | ||||
|         (5, "钉钉扫码登录"), | ||||
|         (6, "短信登录") | ||||
|     ) | ||||
|     username = models.CharField(max_length=150, 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="浏览器名") | ||||
|  | @ -428,11 +458,13 @@ class LoginLog(CoreModel): | |||
|     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_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="登录类型") | ||||
|     login_type = models.IntegerField(default=1, choices=LOGIN_TYPE_CHOICES, verbose_name="登录类型", | ||||
|                                      help_text="登录类型") | ||||
| 
 | ||||
|     class Meta: | ||||
|         db_table = table_prefix + "system_login_log" | ||||
|  | @ -442,14 +474,16 @@ class LoginLog(CoreModel): | |||
| 
 | ||||
| 
 | ||||
| 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="目标角色") | ||||
|     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" | ||||
|  | @ -457,10 +491,13 @@ class MessageCenter(CoreModel): | |||
|         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="是否已读") | ||||
|     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" | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ class LoginSerializer(TokenObtainPairSerializer): | |||
|     default_error_messages = {"no_active_account": _("账号/密码错误")} | ||||
| 
 | ||||
|     def validate(self, attrs): | ||||
| 
 | ||||
|         captcha = self.initial_data.get("captcha", None) | ||||
|         if dispatch.get_system_config_values("base.captcha_state"): | ||||
|             if captcha is None: | ||||
|  |  | |||
|  | @ -7,12 +7,15 @@ | |||
| @Remark: 公共基础model类 | ||||
| """ | ||||
| import uuid | ||||
| from datetime import date, timedelta | ||||
| 
 | ||||
| from django.apps import apps | ||||
| from django.db import models | ||||
| from django.db import models, connection, ProgrammingError | ||||
| from django.db.models import QuerySet | ||||
| 
 | ||||
| from application import settings | ||||
| from application.dispatch import is_tenants_mode | ||||
| 
 | ||||
| table_prefix = settings.TABLE_PREFIX  # 数据库表名前缀 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -40,10 +43,17 @@ class SoftDeleteManager(models.Manager): | |||
|             return SoftDeleteQuerySet(self.model, using=self._db).exclude(is_deleted=False) | ||||
|         return SoftDeleteQuerySet(self.model).exclude(is_deleted=True) | ||||
| 
 | ||||
|     def get_by_natural_key(self,name): | ||||
|     def get_by_natural_key(self, name): | ||||
|         return SoftDeleteQuerySet(self.model).get(username=name) | ||||
| 
 | ||||
| 
 | ||||
| def get_month_range(start_day, end_day): | ||||
|     months = (end_day.year - start_day.year) * 12 + end_day.month - start_day.month | ||||
|     month_range = ['%s-%s-01' % (start_day.year + mon // 12, str(mon % 12 + 1).zfill(2)) | ||||
|                    for mon in range(start_day.month - 1, start_day.month + months)] | ||||
|     return month_range | ||||
| 
 | ||||
| 
 | ||||
| class SoftDeleteModel(models.Model): | ||||
|     """ | ||||
|     软删除模型 | ||||
|  | @ -73,10 +83,13 @@ class CoreModel(models.Model): | |||
|     id = models.BigAutoField(primary_key=True, help_text="Id", verbose_name="Id") | ||||
|     description = models.CharField(max_length=255, verbose_name="描述", null=True, blank=True, help_text="描述") | ||||
|     creator = models.ForeignKey(to=settings.AUTH_USER_MODEL, related_query_name='creator_query', null=True, | ||||
|                                 verbose_name='创建人', help_text="创建人", on_delete=models.SET_NULL, db_constraint=False) | ||||
|                                 verbose_name='创建人', help_text="创建人", on_delete=models.SET_NULL, | ||||
|                                 db_constraint=False) | ||||
|     modifier = models.CharField(max_length=255, null=True, blank=True, help_text="修改人", verbose_name="修改人") | ||||
|     dept_belong_id = models.CharField(max_length=255, help_text="数据归属部门", null=True, blank=True, verbose_name="数据归属部门") | ||||
|     update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", verbose_name="修改时间") | ||||
|     dept_belong_id = models.CharField(max_length=255, help_text="数据归属部门", null=True, blank=True, | ||||
|                                       verbose_name="数据归属部门") | ||||
|     update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", | ||||
|                                            verbose_name="修改时间") | ||||
|     create_datetime = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间", | ||||
|                                            verbose_name="创建时间") | ||||
| 
 | ||||
|  | @ -86,6 +99,113 @@ class CoreModel(models.Model): | |||
|         verbose_name_plural = verbose_name | ||||
| 
 | ||||
| 
 | ||||
| class AddPostgresPartitionedBase: | ||||
|     """ | ||||
|     pgsql表分表基类 | ||||
|     """ | ||||
| 
 | ||||
|     @classmethod | ||||
|     def add_hash_partition(cls, number=36): | ||||
|         """ | ||||
|         创建分区表 | ||||
|         :return: | ||||
|         """ | ||||
|         if cls.PartitioningMeta.method != 'hash': | ||||
|             raise ProgrammingError("表分区错误,无法进行分区") | ||||
|         schema_editor = connection.schema_editor() | ||||
|         if is_tenants_mode(): | ||||
|             schema_editor.sql_add_hash_partition = f'CREATE TABLE "{connection.tenant.schema_name}".%s PARTITION OF "{connection.tenant.schema_name}".%s FOR VALUES WITH (MODULUS %s, REMAINDER %s)' | ||||
|         for item in range(number): | ||||
|             try: | ||||
|                 schema_editor.add_hash_partition( | ||||
|                     model=cls, | ||||
|                     name="_" + str(item), | ||||
|                     modulus=number, | ||||
|                     remainder=item, | ||||
|                 ) | ||||
|             except ProgrammingError as e: | ||||
|                 print(f"{cls.__name__}分表失败:" + str(e).rstrip('\n')) | ||||
|         return | ||||
| 
 | ||||
|     @classmethod | ||||
|     def add_range_day_partition(cls, day=7): | ||||
|         """ | ||||
|         按照创建时间"天"分表 | ||||
|         :return: | ||||
|         """ | ||||
|         if cls.PartitioningMeta.method != 'range': | ||||
|             raise ProgrammingError("表分区错误,无法进行分区") | ||||
|         day_before = date.today().strftime("%Y-%m-%d") | ||||
|         schema_editor = connection.schema_editor() | ||||
|         if is_tenants_mode(): | ||||
|             schema_editor.sql_add_range_partition = ( | ||||
|                 f'CREATE TABLE "{connection.tenant.schema_name}".%s PARTITION OF "{connection.tenant.schema_name}".%s FOR VALUES FROM (%s) TO (%s)' | ||||
|             ) | ||||
|         for index in range(day): | ||||
|             try: | ||||
|                 day_following = (date.today() + timedelta(days=index + 1)).strftime("%Y-%m-%d") | ||||
|                 schema_editor.add_range_partition( | ||||
|                     model=cls, | ||||
|                     name=f"{day_before}_{day_following}", | ||||
|                     from_values=day_before, | ||||
|                     to_values=day_following, | ||||
|                 ) | ||||
|                 day_before = day_following | ||||
|             except ProgrammingError as e: | ||||
|                 print(f"{cls.__name__}分表失败:" + str(e).rstrip('\n')) | ||||
|         return | ||||
| 
 | ||||
|     @classmethod | ||||
|     def add_range_month_partition(cls, start_date, end_date): | ||||
|         """ | ||||
|         按照创建时间"月"分表 | ||||
|         :return: | ||||
|         """ | ||||
|         if cls.PartitioningMeta.method != 'range': | ||||
|             raise ProgrammingError("表分区错误,无法进行分区") | ||||
|         range_month_partition_list = get_month_range(start_date, end_date) | ||||
|         schema_editor = connection.schema_editor() | ||||
|         if is_tenants_mode(): | ||||
|             schema_editor.sql_add_range_partition = ( | ||||
|                 f'CREATE TABLE "{connection.tenant.schema_name}".%s PARTITION OF "{connection.tenant.schema_name}".%s FOR VALUES FROM (%s) TO (%s)' | ||||
|             ) | ||||
|         for index, ele in enumerate(range_month_partition_list): | ||||
|             if index == 0: | ||||
|                 continue | ||||
|             try: | ||||
|                 schema_editor.add_range_partition( | ||||
|                     model=cls, | ||||
|                     name=f"{range_month_partition_list[index - 1][:-3]}_{ele[:-3]}", | ||||
|                     from_values=range_month_partition_list[index - 1], | ||||
|                     to_values=ele, | ||||
|                 ) | ||||
|             except ProgrammingError as e: | ||||
|                 print(f"{cls.__name__}分表失败:" + str(e).rstrip('\n')) | ||||
|         return | ||||
| 
 | ||||
|     @classmethod | ||||
|     def add_list_partition(cls, unique_value): | ||||
|         """ | ||||
|         按照某个值进行分区 | ||||
|         :param unique_value: | ||||
|         :return: | ||||
|         """ | ||||
|         if cls.PartitioningMeta.method != 'list': | ||||
|             raise ProgrammingError("表分区错误,无法进行分区") | ||||
|         schema_editor = connection.schema_editor() | ||||
|         if is_tenants_mode(): | ||||
|             schema_editor.sql_add_list_partition = ( | ||||
|                 f'CREATE TABLE "{connection.tenant.schema_name}".%s PARTITION OF "{connection.tenant.schema_name}".%s FOR VALUES IN (%s)' | ||||
|             ) | ||||
|         try: | ||||
|             schema_editor.add_list_partition( | ||||
|                 model=cls, | ||||
|                 name=f"_{unique_value}", | ||||
|                 values=[unique_value], | ||||
|             ) | ||||
|         except ProgrammingError as e: | ||||
|             print(f"{cls.__name__}分表失败:" + str(e).rstrip('\n')) | ||||
|         return | ||||
| 
 | ||||
| 
 | ||||
| def get_all_models_objects(model_name=None): | ||||
|  | @ -111,4 +231,4 @@ def get_all_models_objects(model_name=None): | |||
|             settings.ALL_MODELS_OBJECTS.setdefault(item.__name__, {"table": table, "object": item}) | ||||
|     if model_name: | ||||
|         return settings.ALL_MODELS_OBJECTS[model_name] or {} | ||||
|     return settings.ALL_MODELS_OBJECTS or {} | ||||
|     return settings.ALL_MODELS_OBJECTS or {} | ||||
|  |  | |||
|  | @ -202,7 +202,7 @@ def get_ip_analysis(ip): | |||
|     return data | ||||
| 
 | ||||
| 
 | ||||
| def save_login_log(request): | ||||
| def save_login_log(request, login_type=1): | ||||
|     """ | ||||
|     保存登录日志 | ||||
|     :return: | ||||
|  | @ -214,6 +214,7 @@ def save_login_log(request): | |||
|     analysis_data['agent'] = str(parse(request.META['HTTP_USER_AGENT'])) | ||||
|     analysis_data['browser'] = get_browser(request) | ||||
|     analysis_data['os'] = get_os(request) | ||||
|     analysis_data['login_type'] = login_type | ||||
|     analysis_data['creator_id'] = request.user.id | ||||
|     analysis_data['dept_belong_id'] = getattr(request.user, 'dept_id', '') | ||||
|     LoginLog.objects.create(**analysis_data) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 李强
						李强