Example #1
0
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
Example #2
0
    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
Example #3
0
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
Example #4
0
    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)
Example #5
0
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
    ]