# -*- coding: utf-8 -*- """ @author: 猿小天 @contact: QQ:1638245306 @Created on: 2021/5/31 031 22:08 @Remark: 公共基础model类 """ from datetime import datetime from importlib import import_module from application import settings from django.apps import apps from django.conf import settings from django.db import models from rest_framework.request import Request table_prefix = settings.TABLE_PREFIX # 数据库表名前缀 class SoftDeleteQuerySet(models.QuerySet): pass class SoftDeleteManager(models.Manager): """支持软删除""" def __init__(self, *args, **kwargs): self.__add_is_del_filter = False super(SoftDeleteManager, self).__init__(*args, **kwargs) def filter(self, *args, **kwargs): # 考虑是否主动传入is_deleted if not kwargs.get('is_deleted') is None: self.__add_is_del_filter = True return super(SoftDeleteManager, self).filter(*args, **kwargs) def get_queryset(self): if self.__add_is_del_filter: 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): return SoftDeleteQuerySet(self.model).get(username=name) class SoftDeleteModel(models.Model): """ 软删除模型 一旦继承,就将开启软删除 """ is_deleted = models.BooleanField(verbose_name="是否软删除", help_text='是否软删除', default=False, db_index=True) objects = SoftDeleteManager() class Meta: abstract = True verbose_name = '软删除模型' verbose_name_plural = verbose_name def delete(self, using=None, soft_delete=True, *args, **kwargs): """ 重写删除方法,直接开启软删除 """ if soft_delete: self.is_deleted = True self.save(using=using) # 级联软删除关联对象 for related_object in self._meta.related_objects: related_model = getattr(self, related_object.get_accessor_name()) # 处理一对多和多对多的关联对象 if related_object.one_to_many or related_object.many_to_many: related_objects = related_model.all() elif related_object.one_to_one: related_objects = [related_model] else: continue for obj in related_objects: obj.delete(soft_delete=True) else: super().delete(using=using, *args, **kwargs) class CoreModelManager(models.Manager): def get_queryset(self): is_deleted = getattr(self.model, 'is_soft_delete', False) flow_work_status = getattr(self.model, 'flow_work_status', False) queryset = super().get_queryset() if flow_work_status: queryset = queryset.filter(flow_work_status=1) if is_deleted: queryset = queryset.filter(is_deleted=False) return queryset def create(self,request: Request=None, **kwargs): data = {**kwargs} if request: request_user = request.user data["creator"] = request_user data["modifier"] = request_user.id data["dept_belong_id"] = request_user.dept_id # 调用父类的create方法执行实际的创建操作 return super().create(**data) 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) 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="修改时间") create_datetime = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间", verbose_name="创建时间") objects = CoreModelManager() all_objects = models.Manager() class Meta: abstract = True verbose_name = '核心模型' verbose_name_plural = verbose_name def get_request_user(self, request: Request): if getattr(request, "user", None): return request.user return None def get_request_user_id(self, request: Request): if getattr(request, "user", None): return getattr(request.user, "id", None) return None def get_request_user_name(self, request: Request): if getattr(request, "user", None): return getattr(request.user, "name", None) return None def get_request_user_username(self, request: Request): if getattr(request, "user", None): return getattr(request.user, "username", None) return None def common_insert_data(self, request: Request): data = { 'create_datetime': datetime.now(), 'creator': self.get_request_user(request) } return {**data, **self.common_update_data(request)} def common_update_data(self, request: Request): return { 'update_datetime': datetime.now(), 'modifier': self.get_request_user_username(request) } exclude_fields = [ '_state', 'pk', 'id', 'create_datetime', 'update_datetime', 'creator', 'creator_id', 'creator_pk', 'creator_name', 'modifier', 'modifier_id', 'modifier_pk', 'modifier_name', 'dept_belong_id', ] def get_exclude_fields(self): return self.exclude_fields def get_all_fields(self): return self._meta.fields def get_all_fields_names(self): return [field.name for field in self.get_all_fields()] def get_need_fields_names(self): return [field.name for field in self.get_all_fields() if field.name not in self.exclude_fields] def to_data(self): """将模型转化为字典(去除不包含字段)(注意与to_dict_data区分)。 """ res = {} for field in self.get_need_fields_names(): field_value = getattr(self, field) res[field] = field_value.id if (issubclass(field_value.__class__, CoreModel)) else field_value return res @property def DATA(self): return self.to_data() def to_dict_data(self): """需要导出的字段(去除不包含字段)(注意与to_data区分) """ return {field: getattr(self, field) for field in self.get_need_fields_names()} @property def DICT_DATA(self): return self.to_dict_data() def insert(self, request): """插入模型 """ assert self.pk is None, f'模型{self.__class__.__name__}还没有保存到数据中,不能手动指定ID' validated_data = {**self.common_insert_data(request), **self.DICT_DATA} return self.__class__._default_manager.create(**validated_data) def update(self, request, update_data: dict[str, any] = None): """更新模型 """ assert isinstance(update_data, dict), 'update_data必须为字典' validated_data = {**self.common_insert_data(request), **update_data} for key, value in validated_data.items(): # 不允许修改id,pk,uuid字段 if key in ['id', 'pk', 'uuid']: continue if hasattr(self, key): setattr(self, key, value) self.save() return self def get_all_models_objects(model_name=None): """ 获取所有 models 对象 :return: {} """ settings.ALL_MODELS_OBJECTS = {} if not settings.ALL_MODELS_OBJECTS: all_models = apps.get_models() for item in list(all_models): table = {"tableName": item._meta.verbose_name, "table": item.__name__, "tableFields": []} for field in item._meta.fields: fields = {"title": field.verbose_name, "field": field.name} table['tableFields'].append(fields) 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 {} def get_model_from_app(app_name): """获取模型里的字段""" model_module = import_module(app_name + '.models') exclude_models = getattr(model_module, 'exclude_models', []) filter_model = [ value for key, value in model_module.__dict__.items() if key != 'CoreModel' and isinstance(value, type) and issubclass(value, models.Model) and key not in exclude_models ] model_list = [] for model in filter_model: if model.__name__ == 'AbstractUser': continue fields = [{'title': field.verbose_name, 'name': field.name, 'object': field} for field in model._meta.fields] model_list.append({'app': app_name, 'verbose': model._meta.verbose_name, 'model': model.__name__, 'object': model, 'fields': fields}) return model_list def get_custom_app_models(app_name=None): """ 获取所有项目下的app里的models """ if app_name: return get_model_from_app(app_name) all_apps = apps.get_app_configs() res = [] for app in all_apps: if app.name.startswith('django'): continue if app.name in settings.COLUMN_EXCLUDE_APPS: continue try: all_models = get_model_from_app(app.name) if all_models: for model in all_models: res.append(model) except Exception as e: pass return res