• 组合搜索组件文档


    组合搜索组件

    1. 先展示一下使用效果:

    2. 使用方法

    • 第一步: 在views.py中配置和传参
    search_group = NbSearchGroup(
        request,
        models.TransactionRecord,  # 传入表
        Option('charge_type'),  # 传入choice字段名
    )
    

    • 第二步: 添加查询条件
    # 查询条件 .filter(**search_group.get_condition)
    queryset = models.TransactionRecord.objects.filter(q).filter(**search_group.get_condition).filter(
        customer_id=request.user_obj.id, active=1).order_by(
        '-id')
    
    • 第三步: 向html中传递参数
    context = {
        'show_data': pager.show_data,
        'pager_string': pager.html(),
        'keyword': keyword,
        "search_group": search_group  # 这是需要添加的
    }
    return render(request, 'transaction_list.html', context)
    

    • 第四步: 导入html search_group.html
    {% if search_group.get_row_list %}
        <div class="panel panel-default">
            <div class="panel-heading">
                <i class="fa fa-filter" aria-hidden="true">i> 快速筛选
            div>
            <div class="panel-body">
                <div class="search-group">
                    {% for row in search_group.get_row_list %}
                        <div class="row">
                            {% for obj in row %}
                                {{ obj|safe }}
                            {% endfor %}
                        div>
                    {% endfor %}
                div>
            div>
        div>
    {% endif %}
    
    • 第五步: 导入css(最好放到static静态文件中) search_group.css
    .search-group {
        padding: 5px 10px;
    }
    
    .search-group .row .whole {
        width: 60px;
        float: left;
        display: inline-block;
        padding: 5px 0 5px 8px;
        margin: 3px;
        font-weight: bold;
        text-align: right;
    
    }
    
    .search-group .row .others {
        padding-left: 80px;
    }
    
    .search-group .row a {
        display: inline-block;
        padding: 5px 8px;
        margin: 3px;
        border: 1px solid #d4d4d4;
    
    }
    
    .search-group .row a {
        display: inline-block;
        padding: 5px 8px;
        margin: 3px;
        border: 1px solid #d4d4d4;
    }
    
    .search-group a.active {
        color: #fff;
        background-color: #337ab7;
        border-color: #2e6da4;
    }
    
    • 第六步: 导入核心代码(源码)group.py
    # -*- encoding:utf-8 -*-
    # @time: 2023/4/14 21:03
    # @author: Maxs_hu
    from django.db.models import ForeignKey, ManyToManyField
    
    
    class SearchGroupRow(object):
        def __init__(self, title, queryset_or_tuple, option, query_dict):
            """
            :param title: 组合搜索的列名称
            :param queryset_or_tuple: 组合搜索关联获取到的数据
            :param option: 配置
            :param query_dict: request.GET
            """
            self.title = title
            self.queryset_or_tuple = queryset_or_tuple
            self.option = option
            self.query_dict = query_dict
    
        def __iter__(self):
            yield '
    ' yield self.title yield '
    '
    yield '
    ' total_query_dict = self.query_dict.copy() total_query_dict._mutable = True origin_value_list = self.query_dict.getlist(self.option.field) if not origin_value_list: yield "全部" % total_query_dict.urlencode() else: total_query_dict.pop(self.option.field) yield "全部" % total_query_dict.urlencode() for item in self.queryset_or_tuple: text = self.option.get_text(item) value = str(self.option.get_value(item)) query_dict = self.query_dict.copy() query_dict._mutable = True if not self.option.is_multi: query_dict[self.option.field] = value if value in origin_value_list: query_dict.pop(self.option.field) yield "%s" % (query_dict.urlencode(), text) else: yield "%s" % (query_dict.urlencode(), text) else: # {'gender':['1','2']} multi_value_list = query_dict.getlist(self.option.field) if value in multi_value_list: multi_value_list.remove(value) query_dict.setlist(self.option.field, multi_value_list) yield "%s" % (query_dict.urlencode(), text) else: multi_value_list.append(value) query_dict.setlist(self.option.field, multi_value_list) yield "%s" % (query_dict.urlencode(), text) yield '
    '
    class Option(object): def __init__(self, field, is_condition=True, is_multi=False, db_condition=None, text_func=None, value_func=None): """ :param field: 组合搜索关联的字段 :param is_multi: 是否支持多选 :param db_condition: 数据库关联查询时的条件 :param text_func: 此函数用于显示组合搜索按钮页面文本 :param value_func: 此函数用于显示组合搜索按钮值 """ self.field = field self.is_condition = is_condition self.is_multi = is_multi if not db_condition: db_condition = {} self.db_condition = db_condition self.text_func = text_func self.value_func = value_func self.is_choice = False def get_db_condition(self, request, *args, **kwargs): return self.db_condition def get_queryset_or_tuple(self, model_class, request, *args, **kwargs): """ 根据字段去获取数据库关联的数据 :return: """ # 根据gender或depart字符串,去自己对应的Model类中找到 字段对象 field_object = model_class._meta.get_field(self.field) title = field_object.verbose_name # 获取关联数据 if isinstance(field_object, ForeignKey) or isinstance(field_object, ManyToManyField): # FK和M2M,应该去获取其关联表中的数据: QuerySet db_condition = self.get_db_condition(request, *args, **kwargs) return SearchGroupRow(title, field_object.remote_field.model.objects.filter(**db_condition), self, request.GET) else: # 获取choice中的数据:元组 self.is_choice = True return SearchGroupRow(title, field_object.choices, self, request.GET) def get_text(self, field_object): """ 获取文本函数 :param field_object: :return: """ if self.text_func: return self.text_func(field_object) if self.is_choice: return field_object[1] return str(field_object) def get_value(self, field_object): if self.value_func: return self.value_func(field_object) if self.is_choice: return field_object[0] return field_object.pk def get_search_condition(self, request): if not self.is_condition: return None if self.is_multi: values_list = request.GET.getlist(self.field) # tags=[1,2] if not values_list: return None return '%s__in' % self.field, values_list else: value = request.GET.get(self.field) # tags=[1,2] if not value: return None return self.field, value class NbSearchGroup(object): def __init__(self, request, model_class, *options): self.request = request self.model_class = model_class self.options = options def get_row_list(self): row_list = [] for option_object in self.options: row = option_object.get_queryset_or_tuple(self.model_class, self.request) row_list.append(row) return row_list @property def get_condition(self): """ 获取组合搜索的条件 :param request: :return: """ condition = {} # ?depart=1&gender=2&page=123&q=999 for option in self.options: key_and_value = option.get_search_condition(self.request) if not key_and_value: continue key, value = key_and_value condition[key] = value return condition

    3. 分享源码实现和封装

    from django.db.models import ForeignKey, ManyToManyField
    
    
    class SearchGroupRow(object):
        def __init__(self, title, queryset_or_tuple, option, query_dict):
            """
            :param title: 组合搜索的列名称
            :param queryset_or_tuple: 组合搜索关联获取到的数据
            :param option: 配置
            :param query_dict: request.GET
            """
            self.title = title
            self.queryset_or_tuple = queryset_or_tuple
            self.option = option
            self.query_dict = query_dict
    
        def __iter__(self):
            yield '
    ' yield self.title yield '
    '
    yield '
    ' total_query_dict = self.query_dict.copy() total_query_dict._mutable = True origin_value_list = self.query_dict.getlist(self.option.field) if not origin_value_list: yield "全部" % total_query_dict.urlencode() else: total_query_dict.pop(self.option.field) yield "全部" % total_query_dict.urlencode() for item in self.queryset_or_tuple: text = self.option.get_text(item) value = str(self.option.get_value(item)) query_dict = self.query_dict.copy() query_dict._mutable = True if not self.option.is_multi: query_dict[self.option.field] = value if value in origin_value_list: query_dict.pop(self.option.field) yield "%s" % (query_dict.urlencode(), text) else: yield "%s" % (query_dict.urlencode(), text) else: # {'gender':['1','2']} multi_value_list = query_dict.getlist(self.option.field) if value in multi_value_list: multi_value_list.remove(value) query_dict.setlist(self.option.field, multi_value_list) yield "%s" % (query_dict.urlencode(), text) else: multi_value_list.append(value) query_dict.setlist(self.option.field, multi_value_list) yield "%s" % (query_dict.urlencode(), text) yield '
    '
    class Option(object): def __init__(self, field, is_condition=True, is_multi=False, db_condition=None, text_func=None, value_func=None): """ :param field: 组合搜索关联的字段 :param is_multi: 是否支持多选 :param db_condition: 数据库关联查询时的条件 :param text_func: 此函数用于显示组合搜索按钮页面文本 :param value_func: 此函数用于显示组合搜索按钮值 """ self.field = field self.is_condition = is_condition self.is_multi = is_multi if not db_condition: db_condition = {} self.db_condition = db_condition self.text_func = text_func self.value_func = value_func self.is_choice = False def get_db_condition(self, request, *args, **kwargs): return self.db_condition def get_queryset_or_tuple(self, model_class, request, *args, **kwargs): """ 根据字段去获取数据库关联的数据 :return: """ # 根据gender或depart字符串,去自己对应的Model类中找到 字段对象 field_object = model_class._meta.get_field(self.field) title = field_object.verbose_name # 获取关联数据 if isinstance(field_object, ForeignKey) or isinstance(field_object, ManyToManyField): # FK和M2M,应该去获取其关联表中的数据: QuerySet db_condition = self.get_db_condition(request, *args, **kwargs) return SearchGroupRow(title, field_object.remote_field.model.objects.filter(**db_condition), self, request.GET) else: # 获取choice中的数据:元组 self.is_choice = True return SearchGroupRow(title, field_object.choices, self, request.GET) def get_text(self, field_object): """ 获取文本函数 :param field_object: :return: """ if self.text_func: return self.text_func(field_object) if self.is_choice: return field_object[1] return str(field_object) def get_value(self, field_object): if self.value_func: return self.value_func(field_object) if self.is_choice: return field_object[0] return field_object.pk def get_search_condition(self, request): if not self.is_condition: return None if self.is_multi: values_list = request.GET.getlist(self.field) # tags=[1,2] if not values_list: return None return '%s__in' % self.field, values_list else: value = request.GET.get(self.field) # tags=[1,2] if not value: return None return self.field, value

    4. 分享案例

    优点:

    1. 可根据传入的字段名读取表中choice并展示和实现对应的筛选功能
    2. 大多数项目可以应用上
    3. 思路(django中admin的源码以及stark组件)
  • 相关阅读:
    intellij 使用
    【数据结构与算法】详解单向无头非循环链表的基本操作
    MP逻辑删除
    Sora:AI视频模型的无限可能与挑战
    2022 这份刚出炉的 Java 八股文太全了,3 大主题,5 个主要模块,35 个小板块
    基于C#实现的小型动物识别推理系统
    彻底解决全局安装权限问题
    BGP学习笔记
    Java 后端实现鼠标滚动,点击事件
    C语言双向链表
  • 原文地址:https://www.cnblogs.com/huxiaofeng1029/p/17320336.html