Django中Q搜索的简单应用

本节涉及:

1.Q搜索在前后端的设计

2.Django中Queryset对象的序列化(由后端扔给前端的数据必然会经过序列化)

3.前端动态地构造表格以便显示(动态创建DOM对象)

思路:

用户通过前端查询数据库内容时,可添加多个搜索框,一个搜索框内可以输入多个条件。同一搜索框内的条件是或OR关系,不同搜索框间是与AND关系。如搜索图书,每条图书信息包括名称、页数、印刷日期、类型,在一个搜索框内可选择搜索书名,以中文逗号分隔即可以书名同时搜索多本图书,同一搜索框内就是OR关系。又可以再添加输入框,这时就可以再添加类型、价格等信息,缩小搜索范围,这些搜索框之间就是AND关系。条件传递给后端后,后端拿到结果,处理后再抛给前端,由前端在页面展示。

代码

数据库信息

class BookType(models.Model):
    caption = models.CharField(max_length=32)

class Book(models.Model):
    name = models.CharField(max_length=32)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    pubdate = models.DateField()
    # 外键
    book_type = models.ForeignKey(BookType, on_delete=models.CASCADE)

    def __str__(self):
        return "Book Object: %s %sp %s元" % (self.name, self.pages, self.price)

数据库信息

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="/static/js/jquery-2.1.4.min.js"></script>
    <title>Index页面</title>
</head>
<body>
    // 搜索框
    <div class="condition">
        <div class="item ">
            // 点击后会添加一个搜索框
            <div class=‘icon‘ onclick="AddCondition(this);">+</div>
            <div>
                // 选择不同的搜索条件时,会触发方法
                <select onchange="ChangeName(this);">
                    <option value="name">书名</option>
                    <option value="book_type__caption">类型</option>
                    <option value="price">价格</option>
                </select>
            </div>
            <div class="left"><input type="text" name="name"/></div>
        </div>
    </div>
    <div>
        // 点击触发搜索,向后端传递
        <input type="button" onclick="Search();" value="搜索">
    </div>
    // 展示区
    <div class="container">

    </div>
</body>

HTML代码

JS代码

<script>
    function AddCondition(ths){
        // dom对象转换为jquery对象
        var new_tag = $(ths).parent().clone();
        // 新添加的搜索框的按钮改为减号,定义删除方法
        new_tag.find(‘.icon‘).text(‘-‘);
        new_tag.find(‘.icon‘).attr(‘onclick‘,‘RemoveCondition(this);‘);
        $(ths).parent().append(new_tag);
    }

    // 新添加的搜索框还可删除
    function RemoveCondition(ths){
        $(ths).parent().remove();
    }

    //
    function ChangeName(tag){
        // 获取搜索条件value属性的值
        var v = $(tag).val();
        // 定义input的name属性
        // 这里主要是为了随着用户选择不同的搜索条件
        // 也向后端传递不同的搜索条件,Q搜索中会用到
        $(tag).parent().next().find(‘input‘).attr(‘name‘, v);
    }

    function Search(){
        // 获取所有用户输入的内容并提交
        // 将要给后端传递的字典
        var post_data_dict = {};
        // 循环所有的input
        $(‘.condition input‘).each(
            function(){
               // 操作jquery对象
               // 获得搜索条件
               var attr_name = $(this).attr(‘name‘);
               // 获取用户输入
               var value_list = $(this).val().split(‘,‘);
               post_data_dict[attr_name] = value_list;
            }
        );
        // 将要传递的字典序列化
        var post_data_str = JSON.stringify(post_data_dict);
        $.ajax({
            url: ‘/index/‘,
            type: ‘POST‘,
            data: {‘post_data‘: post_data_str},
            // 此参数使得后端传来的json会被解析为js对象
            dataType: "json",
            success: function(ret){
                if(ret.status){
                    // 清空展示柜,避免重复显示
                    $(‘.container‘).empty();
                    // {‘status‘:true, ‘content‘: [{},{}]}
                    $.each(ret.content, function(useless_key, value_dict){
                        // 有多少条数据就有多少个表
                        // 形式为一表一行n列
                        var table = document.createElement(‘table‘);
                        // 每个表有一行数据
                        var tr = document.createElement(‘tr‘);
                        // {‘name‘:‘xx‘, ‘pages‘:540}
                        $.each(value_dict, function(key, val){
                            // 书籍信息的每一项内容对应一列 td
                            var td = document.createElement(‘td‘);
                            // 为td标签加上class属性,值为其键
                            td.setAttribute(‘class‘, key);
                            // 为td标签加上文本, 即其值
                            td.innerText = val;
                            td.setAttribute(‘width‘, 100);
                            // 每次创建一个td标签都添加到tr上
                            tr.appendChild(td);
                        });
                        // 将tr标签加入table中
                        table.appendChild(tr);
                        table.setAttribute(‘border‘, 1);
                        // 将table加入展示柜中
                        $(‘.container‘).append(table);
                    });
                }else{
                    alert(ret.message);
                }
            }
        })
    }
</script>
</html>

JS代码

后端代码(views.py)

from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
# Create your views here.
# 业务处理逻辑
import json
from decimal import Decimal
from datetime import date

class DecimalDatetimeEncoder(json.JSONEncoder):

    def default(self, o):
        if isinstance(o, Decimal):
            return str(o)
        elif isinstance(o, date):
            return o.strftime(‘%Y-%m-%d‘)
        return json.JSONEncoder.default(self, o)

def index(request):
    # 定义要给前端传递的字典
    post_ret_dict = {‘status‘: True, ‘content‘: None}
    if request.method == ‘POST‘:
        try:
            # 获取前端抛来的字符串
            post_data_str = request.POST.get(‘post_data‘, None)
            # 反序列化
            post_data_dict = json.loads(post_data_str)
            # post_data_dict: {‘name‘: [‘nameA‘, ‘nameB‘],‘price‘:[20,30,40] }
            from django.db.models import Q
            # 构造Q搜索
            condition = Q()
            for k, v in post_data_dict.items():
                # 同一搜索框内(同一条件)的输入是OR关系(主关系)
                q = Q()
                q.connector = ‘OR‘
                for item in v:
                    # 这里的k就是前端传来的name属性的值,也就是搜索条件(子关系)
                    q.children.append((k, item))
                condition.add(q, ‘AND‘)
            # 将Q搜索直接作为filter的条件传入,并再用values方法取到想要的值
            # 这里用book_type__caption双下划线的形式找到外键表的caption域的值
            # 返回值仍是Queryset对象,可通过list转换为列表
            list_ret = list(models.Book.objects.filter(condition).values(‘name‘, ‘pages‘, ‘price‘, ‘pubdate‘, ‘book_type__caption‘))  # QuerySet
            post_ret_dict[‘content‘] = list_ret
        except Exception as e:
            post_ret_dict[‘status‘] = False
        # 最后再序列化要给前端的内容
        # 注意价格是Decimal类型,印刷日期是Datetime类型,这两类都不是python内置类型,无法直接用json.dumps方法序列化
        # 这里可以借助第二个参数,构造一个自定义的解析类,自行处理
        post_ret_str = json.dumps(post_ret_dict, cls=DecimalDatetimeEncoder)
        return HttpResponse(post_ret_str)

        # django提供的序列化方法,但是无法获得外键表的对应值,不能在使用values方法后序列化
        # from django.core.serializers import serialize
        # ret = models.Book.objects.filter(condition)  # QuerySet
        # str_ret = serialize(‘json‘, ret)
        # print(str_ret)
        # return HttpResponse(str_ret)
    return render(request, "index.html")

views.py

原文地址:https://www.cnblogs.com/yifeixu/p/8877734.html

时间: 2024-10-29 19:51:41

Django中Q搜索的简单应用的相关文章

【Django】Django中的模糊查询以及Q对象的简单使用

Django中的模糊查询: 需要做一个查找的功能,所以需要使用到模糊查询. 使用方法是:字段名加上双下划线跟上contains或者icontains,icontains和contains表示是否区分大小写. 实测icontains为不区分大小写,contains为区分大小写. from djangp.db.models import Q def select_seller(request,keyword): seller_info= Seller.objects.filter(Q(usernam

memcached简单介绍及在django中的使用

什么是memcached? Memcached是一个高性能的分布式的内存对象缓存系统,全世界有不少公司采用这个缓存项目来构建大负载的网站,来分担数据库的压力.Memcached是通过在内存里维护一个统一的巨大的hash表,memcached能存储各种各样的数据,包括图像.视频.文件.以及数据库检索的结果等,当然因为memcached中的数据是保存在内存中的,应该没有人会把视频.图片等数据保存在memcached中.其实,memcached的原理简单的说就是将数据调用到内存中,然后从内存中读取,从

Django中如何使用django-celery完成异步任务

本篇博文主要介绍在开发环境中的celery使用,请勿用于部署服务器. 许多Django应用需要执行异步任务, 以便不耽误http request的执行. 我们也可以选择许多方法来完成异步任务, 使用Celery是一个比较好的选择, 因为Celery有着大量的社区支持, 能够完美的扩展, 和Django结合的也很好. Celery不仅能在Django中使用, 还能在其他地方被大量的使用. 因此一旦学会使用Celery, 我们可以很方便的在其他项目中使用它. 1. Celery版本 本篇博文主要针对

Django中的app及mysql数据库篇(ORM操作)

Django常见命令 在Django的使用过程中需要使用命令让Django进行一些操作,例如创建Django项目.启动Django程序.创建新的APP.数据库迁移等. 创建Django项目 一把我们都新建一个文件夹来存放项目文件,切换到这个目录下,启动命令行工具.创建一个名为mysite的Django项目: django-admin startproject mysite 创建好项目之后,可以查看当前目录下多出一个名为mysite的文件夹,mysite的文件夹目录结构如下: mysite/ ma

Django中使用表单

使用表单 表单用 user 提交数据,是网站中比较重要的一个内容 GET 和 POST 方法 GET 和 POST 的区别 URL,全称是"统一资源定位符".用于对应互联网上的每一个文件.而 GET.POST 等方法,本质上就是对这个 URL 进行一系列的操作.GET.POST.PUT.DELETE 分别对应对资源进行查.改.增.删.因此,任何对系统状态有改变的请求(例如,对数据库的数据进行修改)都应该使用 POST .GET 方法用于不影响系统状态的请求,如搜索或者是请求发送一些数据

[转载]SharePoint 2013搜索学习笔记之搜索构架简单概述

Sharepoint搜索引擎主要由6种组件构成,他们分别是爬网组件,内容处理组件,分析处理组件,索引组件,查询处理组件,搜索管理组件.可以将这6种组件分别部署到Sharepoint场内的多个服务器上,组成适合需求的Sharepoint搜索场,搜索场的体系结构设计主要参考量是爬网内容量,微软根据爬网内容量不同将搜索场分为大型场,中型场和小型场,更多详细信息可参考: SharePoint Server 2013 中的搜索概述和在SharePoint Server 2013 中规划企业搜索体系结构.

Django中如何使用django-celery完成异步任务1(转)

原文链接: http://www.weiguda.com/blog/73/ 本篇博文主要介绍在开发环境中的celery使用,请勿用于部署服务器. 许多Django应用需要执行异步任务, 以便不耽误http request的执行. 我们也可以选择许多方法来完成异步任务, 使用Celery是一个比较好的选择, 因为Celery 有着大量的社区支持, 能够完美的扩展, 和Django结合的也很好. Celery不仅能在Django中使用, 还能在其他地方被大量的使用. 因此一旦学会使用Celery,

在Django中使用markdown

markdown比wiki语法要简单,github上的代码几乎都是readme.md,这种易读易写的脚本语言已经变得非常流行. 关于语法,可参考markdown语法 本片博文简单介绍一下如何在Django中集成markdown的功能 下载python下的markdown解析器. $sudo pip install markdown 或者是 $sudo easy install markdown 其他安装方式可参考markdown的python解析器 在app的models.py中创建一个博文的类

Django 中的用户认证

Django 自带一个用户认证系统,这个系统处理用户帐户.组.权限和基于 cookie 的 会话.本文说明这个系统是如何工作的. 概览 认证系统由以下部分组成: 用户 权限:控制用户进否可以执行某项任务的二进制(是/否)标志. 组:一种为多个用户加上标签和权限的常用方式. 消息:一种为指定用户生成简单消息队列的方式. Deprecated in Django 1.2: 认证系统的消息部分将会在 Django 1.4 版中去除. 安装 认证系统打包在 Django 的 django.contrib