组合搜索组件文档

科技资讯 投稿 10700 0 评论

组合搜索组件文档

组合搜索组件

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 '<div class="whole">'
        yield self.title
        yield '</div>'
        yield '<div class="others">'
        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 "<a class='active' href='?%s'>全部</a>" % total_query_dict.urlencode(
        else:
            total_query_dict.pop(self.option.field
            yield "<a href='?%s'>全部</a>" % 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 "<a class='active' href='?%s'>%s</a>" % (query_dict.urlencode(, text
                else:
                    yield "<a href='?%s'>%s</a>" % (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 "<a class='active' href='?%s'>%s</a>" % (query_dict.urlencode(, text
                else:
                    multi_value_list.append(value
                    query_dict.setlist(self.option.field, multi_value_list
                    yield "<a href='?%s'>%s</a>" % (query_dict.urlencode(, text

        yield '</div>'


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 '<div class="whole">'
        yield self.title
        yield '</div>'
        yield '<div class="others">'
        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 "<a class='active' href='?%s'>全部</a>" % total_query_dict.urlencode(
        else:
            total_query_dict.pop(self.option.field
            yield "<a href='?%s'>全部</a>" % 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 "<a class='active' href='?%s'>%s</a>" % (query_dict.urlencode(, text
                else:
                    yield "<a href='?%s'>%s</a>" % (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 "<a class='active' href='?%s'>%s</a>" % (query_dict.urlencode(, text
                else:
                    multi_value_list.append(value
                    query_dict.setlist(self.option.field, multi_value_list
                    yield "<a href='?%s'>%s</a>" % (query_dict.urlencode(, text

        yield '</div>'


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. 分享案例

优点:

    可根据传入的字段名读取表中choice并展示和实现对应的筛选功能
  1. 大多数项目可以应用上
  2. 思路(django中admin的源码以及stark组件)

编程笔记 » 组合搜索组件文档

赞同 (60) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽