本节涉及:

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>

index.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

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

  1. Django中Q查询及Q()对象

    问题 一般我们在Django程序中查询数据库操作都是在QuerySet里进行进行,例如下面代码: >>> q1 = Entry.objects.filter(headline__st ...

  2. Django中组合搜索功能

    需求分析 很多电商网站中有组合搜索的功能,所谓组合搜索就是网页中组合多个条件,对数据库中进行查询,并且将结果显示在页面中,看个例子吧: 注意红框中的标识,我们可以根据URL来做组合搜索. video- ...

  3. Asp.net 中高亮显示搜索关键字简单方法

    今天用到搜索时的高亮显示,百度了一下,如下面: 1.替换关键字,对字体变色.         public static string ReplaceRed(string strtitle, stri ...

  4. Django 中的缓存问题

    Django 中的缓存问题 简单介绍 ​ 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. ​ 当一个网站的用户访问量很大的 ...

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

    Django中的模糊查询: 需要做一个查找的功能,所以需要使用到模糊查询. 使用方法是:字段名加上双下划线跟上contains或者icontains,icontains和contains表示是否区分大 ...

  6. Django中的F和Q函数

    内容简介: 介绍Django中的F和Q作用以及使用方法 一.F介绍 作用:操作数据表中的某列值,F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用,不用获取对象放在内存中再对字段 ...

  7. Django中的ORM相关操作:F查询,Q查询,事物,ORM执行原生SQL

    一    F查询与Q查询: 1 . F查询: 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢? Django 提供 F() 来做这样的 ...

  8. Django中简单添加HTML、css、js等文件(非正规添加,适合小白)

    Django中简单添加HTML.css.js等文件 首先申明下自己的环境, python版本3.65(亲测3.7版本有毒,没解决掉!) Django版本1.11.15(版本比较成熟,也可以用最新的版本 ...

  9. django 中的聚合和分组 F查询 Q查询 事务cookies和sessions 066

    1 聚合和分组 聚合:对一些数据进行整理分析 进而得到结果(mysql中的聚合函数) 1aggregate(*args,**kwargs) : 通过对QuerySet进行计算 ,返回一个聚合值的字典. ...

随机推荐

  1. Dynamics CRM 日常使用JS整理(一)

    整理下平时CRM开发中用到的一些基本的js操作 取值: var oResult = Xrm.Page.getAttribute(sFieldName).getValue(); var oResult ...

  2. jvisualvm安装visualgc插件

    jdk1.7自带jvisualvm可以对java应用进行监控.其中有个插件visualgc可以查看jvm垃圾回收的具体信息.安装插件的步骤是打开jvisualvm,点击工具->插件,在可用插件列 ...

  3. python GUI 之 tkinter

    写一个 登陆窗口来学习 tkinter ,还剩下一些问题 代码暂时如下 import tkinter as tk import webbrowser import pickle from tkinte ...

  4. 如何清理Docker占用的磁盘空间?(转载)

    本文转载自https://blog.fundebug.com/2018/01/10/how-to-clean-docker-disk/ , 感谢原作者. 摘要:用了Docker,好处挺多的,但是有一个 ...

  5. [译]Ocelot - Delegating Handlers

    原文 可以为HttpClient添加delegating handlers. Usage 为了添加delegating handler需要做两件事. 首先如下一样创建一个类. public class ...

  6. 【ARTS】01_21_左耳听风-201900401~201900407

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  7. Javascript模块化简史

    Script标签和闭包 RequireJS, AngularJS以及依赖注入 Node.js以及CommonJS的出现 ES6, import, Babel和Webpack https://ponyf ...

  8. django日志,django-crontab,django邮件模块

    django 日志 四大块,格式器,过滤器,处理器,日志管理器 LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'formatt ...

  9. python数据分析实例(1)

    1.获取数据: 想要获得道指30只成分股的最新股价 import requests import re import pandas as pd def retrieve_dji_list(): try ...

  10. redis-hash操作

    hset(name, key, value) # name对应的hash中设置一个键值对(不存在,则创建:否则,修改) # 参数: # name,redis的name # key,name对应的has ...