首页 > 其他分享 >django常用的组合搜索组件

django常用的组合搜索组件

时间:2024-08-14 12:23:41浏览次数:15  
标签:self value django field 搜索 func 组件 dict condition

文章目录

django常用的组合搜索组件

在项目开发中,如果有大量数据就要用到组合搜索,通过组合搜索对大块内容进行分类筛选。

在这里插入图片描述

快速使用

三步走:(其实主要就是传入配置信息)

  1. 创建组合搜索类的实例对象,传入参数进行配置(三个参数: request, model_class, *options
  2. 在数据库查询时传入search_group.get_condition方法生成的查询条件(该方法会根据传入的配置生成查询条件)
  3. 在前端使用search_group.get_row_list(search_group.get_row_list生成一个列表,包含所有传入的Option字段的信息)

配置信息

这是Option类的init函数:

class Option(object):
    def __init__(self, field, is_condition=True, is_multi=False, db_condition=None, text_func=None, value_func=None):
        """
        :param field: 组合搜索关联的字段(支持choice/Foreignkey类型)
        :param is_multi: 是否支持多选
        :param db_condition: 数据库关联查询时的条件(字典)
        :param text_func: 此函数用于显示组合搜索按钮页面文本(页面展示的值)
        :param value_func: 此函数用于显示组合搜索按钮值(url中的参数值)
        """
        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

示例:

search_group = NbSearchGroup(
        request,
        models.TransactionRecord,
        Option('charge_type', 
               is_multi=True, 
               text_func=lambda x: x[1],
               value_func=lambda x:x[0]
              ),  # choice
        Option('customer', 
               db_condition={"id__lte": 10, 'active': 1}, 
               text_func=lambda x: x.username,value_func=lambda x:x.id
              ),  # fk
    )

在这里插入图片描述

1. 视图函数

from django.shortcuts import render
from web import models
from utils.pager import Pagination
from django.db.models import Q
from utils.group import Option, NbSearchGroup

def my_transaction_list(request):
    # 第一步:配置和传参
    search_group = NbSearchGroup(
        request,
        models.TransactionRecord,
        Option('charge_type'),  # choice
    )
    
    # ...其他的查询条件

    # 第二步:获取条件 .filter(**search_group.get_condition)
    queryset = models.TransactionRecord.objects.filter(**search_group.get_condition).filter(其他查询条件)
    pager = Pagination(request, queryset) # 分页组件

    context = {
        "pager": pager,
        "keyword": keyword,
        "search_group": search_group  # 第三步:将对象传入前端页面
    }
    return render(request, 'my_transaction_list.html', context)

2. 前端模板

{% 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 %}

3. 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;
}

代码实现

#!/usr/bin/env python
# -*- coding:utf-8 -*-
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):
        """
        :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

若有错误与不足请指出,关注DPT一起进步吧!!!

标签:self,value,django,field,搜索,func,组件,dict,condition
From: https://blog.csdn.net/m0_66925868/article/details/141187852

相关文章

  • 8.14信息学集训_树、搜索与剪枝
    目录P1305新二叉树B3642二叉树的遍历P4913【深基16.例3】二叉树深度P3884[JLOI2009]二叉树问题P8681[蓝桥杯2019省AB]完全二叉树的权值P1434[SHOI2002]滑雪P1040[NOIP2003提高组]加分二叉树P1074[NOIP2009提高组]靶形数独P2827[NOIP2016提高组]蚯蚓T266208......
  • (算法)猜数字⼤⼩II————<暴搜->记忆化搜索->动态规划>
    1.题⽬链接:375.猜数字⼤⼩II2.题⽬描述:3.解法(暴搜->记忆化搜索):算法思路:暴搜:a.递归含义:给dfs⼀个使命,给他⼀个区间[left,right],返回在这个区间上能完胜的最⼩费⽤;b.函数体:选择[left,right]区间上的任意⼀个数作为头结点,然后递归分析左右⼦树。求出所有情况......
  • (算法)最⻓递增⼦序列————<暴搜->记忆化搜索->动态规划>
    1.题⽬链接:300.最⻓递增⼦序列2.题⽬描述:3.解法(暴搜->记忆化搜索->动态规划):算法思路:暴搜:a.递归含义:给dfs⼀个使命,给他⼀个数i,返回以i位置为起点的最⻓递增⼦序列的⻓度;b.函数体:遍历i后⾯的所有位置,看看谁能加到i这个元素的后⾯。统计所有情况下的最⼤值。......
  • 【Django开发】django美多商城项目完整开发4.0第2篇:项目准备【附代码文档】
    本教程的知识点为:美多商城项目准备项目准备配置1.修改settings/dev.py文件中的路径信息2.INSTALLED_APPS3.数据库用户部分图片验证码1.后端接口设计:视图原型2.具体视图实现用户部分使用Celery完成发送短信判断帐号是否存在1.判断用户名是否存在后端接口设......
  • Vue3如何使用v-model写一个多条件联合搜索
    在Vue3中,使用v-model进行多条件联合搜索通常涉及到绑定多个输入字段到组件的数据属性上,并在搜索逻辑中根据这些属性的值来过滤数据。虽然v-model本身是针对单个表单元素进行双向数据绑定的,但你可以通过结合使用多个v-model和计算属性或方法来处理多条件搜索。以下是一个简单......
  • 动态组件,插槽,vue项目创建,vue项目目录结构,vue开发规范,es6语法
    Ⅰ动态组件【一】基本使用【1】不使用动态组件<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>动态组件</title><scriptsrc="./js2/vue.js"></script></head><......
  • Django-rest-framework(DRF)怎么使用celery
    目录一、什么是celery1、celery简介2、celery的使用场景3、celery的架构二、Django使用celery1、安装celery2、Django配置三、定时任务和异步任务一、什么是celery1、celery简介Celery是一个基于Python开发的分布式异步消息任务队列,它专注于实时处理的异步任务队......
  • LayUI Upload组件连续上传同一文件无反应
    可能原因:组件会缓存上次的上传历史,若是同一文件就不处理具体原因:待查解决方法:在choose里面增加如下语句“uploadListIns.config.elem.next()[0].value='' ”varuploadListIns=upload.render({elem:'#FileUpload',elemList:$('#FileList'),//列表元素对......
  • vue父子组件传值有几种方式?
    在Vue.js中,组件间通信是构建复杂应用的关键。子组件与父组件之间的通信以及父组件向子组件传递数据都有多种方式。下面是常见的几种方法:父组件向子组件传递数据Props描述:这是最常见的方法,通过定义props,父组件可以将数据直接传递给子组件。推荐度:强烈推荐,这是最符合Vue单......
  • 基于django+vue基于单片机及spring框架的高血压患者居家监测系统【开题报告+程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着人口老龄化的加剧和生活方式的改变,高血压已成为全球范围内最常见的慢性疾病之一,其高发病率和并发症的严重性对公共健康构成了严重威胁......