def add_login_user_data(view, data): """ 给数据添加上用户数据 对于字段,这里分:正向的关系字段,反向的关系字段 """ if view.request.method.upper() in ["GET", "OPTIONS", "DELETE"]: return if view.action not in ["create", "update", "partial_update"]: return if not view.request.data: return # 这里兼容签名方式 if view.request.user.is_anonymous: return model_name, model = view.model_slug, view.model # 第一部分,先检测模型中的字段是否有引用用户模型,如果有,则注入用户数据 user = get_user_model().objects.get(id=view.request.user.id) insert_user = partial(insert_user_info, user_id=user.id, action=view.action) auth_fields = insert_user(data, model) relation_fields = meta.get_all_relation_fields(model) if relation_fields: for item in relation_fields: if item.name not in data or item.name in auth_fields: # 如果字段没有在 data 中或者字段名称和 auth_fields 相同,则不做任何处理 continue value = data[item.name] if meta.check_field_is_reverse(item): # FIXME: 当前反向字段使用的是列表数据结构 if not value or not isinstance(value, list): continue for reverse_item in value: insert_user(reverse_item, item.related_model) else: # 这里说明是正向字段 if item.many_to_many: # 说明是多对多字段 if not value or not isinstance(value, list): continue for child_item in value: insert_user(child_item, item.related_model) else: # 使用字典数据结构 if isinstance(value, dict): insert_user(value, item.related_model) return data
def basebone_check_distinct_queryset(self, fields): """检测是否需要 检测是否需要对结果集去重,去重需要单独做好检测 因为去重在统计业务中,如果去重,对于关联的查询,会做子查询,导致 结果不符合预期 这里对于关系字段都需要做去重操作 - 一对多 - 多对一 - 多对多 """ # 如果动作是创建或者跟单条数据相关的,不在进行去重操作 if self.action in [ "create", "retrieve", "destroy", "custom_patch", "update", "partial_update", ]: return if not fields: return # 获取非一对一的关系字段 relation_fields = [ item.name for item in get_all_relation_fields(self.model) if not item.one_to_one ] if not isinstance(fields, list): fields = [fields] separator = "__" for item in fields: if not isinstance(item, str): continue field = item.split(separator)[0] if field in relation_fields: self.basebone_distinct_queryset = True break
def insert_user_to_data(model, user, data): """插入用户到数据中""" # 第一部分,先检测模型中的字段是否有引用用户模型,如果有,则注入用户数据 auth_user_field = None # 检测模型中是否有字段引用了用户模型 has_user_field = meta.get_related_model_field(model, get_user_model()) if has_user_field: field_name = get_gmeta_config_by_key(model, gmeta.GMETA_CLIENT_USER_FIELD) if field_name: auth_user_field = field_name # 如果用户数据中没有传递用户的数据,则进行插入 if field_name not in data: data[field_name] = user.id relation_fields = meta.get_all_relation_fields(model) if relation_fields: for item in relation_fields: if item.name not in data or item.name == auth_user_field: # 如果字段没有在 data 中或者字段名称和 auth_user_field 相同,则不做任何处理 continue value = data[item.name] if meta.check_field_is_reverse(item): # FIXME: 当前反向字段使用的是列表数据结构 if not value or not isinstance(value, list): continue has_user_field = meta.get_related_model_field( item.related_model, get_user_model()) if has_user_field: field_name = get_gmeta_config_by_key( item.related_model, gmeta.GMETA_CLIENT_USER_FIELD) if field_name: for reverse_item in value: if isinstance(reverse_item, dict): # 如果用户数据中没有传递用户的数据,则进行插入 if field_name not in reverse_item: reverse_item[field_name] = user.id else: # 这里说明是正向字段 if item.many_to_many: # 说明是多对多字段 if not value or not isinstance(value, list): continue has_user_field = meta.get_related_model_field( item.related_model, get_user_model()) if has_user_field: field_name = get_gmeta_config_by_key( item.related_model, gmeta.GMETA_CLIENT_USER_FIELD) if field_name: for child_item in value: if isinstance(child_item, dict): # 如果用户数据中没有传递用户的数据,则进行插入 if field_name not in child_item: child_item[field_name] = user.id else: # 使用字典数据结构 if isinstance(value, dict): has_user_field = meta.get_related_model_field( item.related_model, get_user_model()) if has_user_field: field_name = get_gmeta_config_by_key( item.related_model, gmeta.GMETA_CLIENT_USER_FIELD) if field_name: # 如果用户数据中没有传递用户的数据,则进行插入 if field_name not in value: value[field_name] = user
def statistics(self, request, *args, **kwargs): """计算统计数据 请求的数据结构如下: { key: { method: 'count' field: 'xxxx', verbose_name: '可读名称', }, ... } """ log.debug(f"statistics action: {self.action}") configs = request.data.get("fields", None) if not configs: configs = self.basebone_get_statistics_config() if not configs: return success_response({}) queryset = self.get_queryset() method_map = {"sum": Sum, "count": Count} aggregates, relation_aggregates = {}, {} relation_fields = [item.name for item in get_all_relation_fields(self.model)] for key, value in configs.items(): if not isinstance(value, dict): continue method = value.get("method") if method not in method_map: continue field = value.get("field") if value.get("field") else key aggregate_param = method_map[value["method"]](field) if method == "count": aggregate_param = method_map[value["method"]](field, distinct=True) condition = Coalesce(aggregate_param, Value(0)) split_field = field.split("__")[0] if split_field in relation_fields: relation_aggregates[key] = condition else: aggregates[key] = condition if not aggregates and not relation_aggregates: return success_response({}) result = queryset.aggregate(**aggregates) self.basebone_origin_queryset.query.annotations.clear() relation_result = self.basebone_origin_queryset.aggregate(**relation_aggregates) result.update(relation_result) return success_response(result)
def get_no_concrete_or_m2m(model): """获取反向或者对对多字段名称列表""" return [ item.name for item in get_all_relation_fields(model) if not item.concrete or item.many_to_many ]