上篇文章已经完成框架搭建,本文接着上篇的内容继续讲解。本片主要的说三点内容,分别是:根据条件查询数据、根据查询结果显示不同内容、将查询数据填充到页面上。

1.逻辑优化

在上篇文章,我在原来的 url 地址中处理用户提交的表单数据。Url 值改变了,但是页面没有刷新。同时,表单数据没有进行分类。这会导致用户不管提交什么数据,页面就呈现什么数据。

而正常的逻辑应该是这样。如果用户访问的是首页,那么不需要填充任何数据以及展示提示框。

如果用户提交了表单数据,但是数据库中没有查询到数据,则提醒下用户没有查询到相关数据。

如果用户提交了表单数据,数据库也能查询到数据。页面需要提醒用户查询到数据,并将查询结果展示出来。

为了解决这个问题,我通过定义一个变量 countNum 来区分。

2.根据查询结果显示不同内容

2-1.视图改造

按照解决方案,我们需要对 V 层进行改造。定义全局变量 countNum,初始化为 -1。如果用户访问的是首页,就直接返回。如果用户提交表单数据,数据库查询不到数据。则将 countNum 赋值为 0 ,然后返回。如果用户提交表单数据,数据库查询不到数据,就返回数据总条。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# views.py
def index(request):
templateView = 'index.html'
countNum = -1
keywords = ''

if request.method == 'GET':

form = QueryUserForm(request.GET)
# 验证表单
if form.is_valid():
# 过滤需要的数据
condition = form.cleaned_data['condition']
keywords = form.cleaned_data['queryContent']

print('condition == ' + condition)
print('keywords == ' + keywords)

countNum = 0
# 查询结果
# 假设经过查询, 一共获取到 3 条数据
countNum = 3
if countNum != 0:
return render(request, templateView, {
'countNum': countNum,
'keywords': keywords,
'form': form,
})
# 查询不到数据, 显示没有数据的浮窗
if countNum == 0:
return render(request, templateView, {
'countNum': countNum,
'keywords': keywords,
'form': form,
})
# 直接访问主页, 显示的内容
else:
return render(request, templateView, {'countNum': countNum, 'form': form})

2-2.模板改造

T 层(模板)需要根据 V 层(视图)透传过来的 countNum 的值进行判断,然后渲染相应的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# index.html
<!DOCTYPE html>
<html>
<body>
<div class="container" id="container">
<!-- 前面代码不变 -->
{% if countNum == -1 %}
<!-- 显示首页内容, 不需要做处理 -->
{% else %}
<!-- 查询不到数据, 提醒用户更换 关键词或者类型 -->
{% if countNum == 0 %}
<div class="alert alert-warning alert-dismissible col-md-10 col-md-offset-1" role="alert">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span></button>
找不到与<b>&nbsp{{ keywords }}&nbsp</b>相关的结果。请更换其他<b>&nbsp关键词或类型&nbsp</b>试试。</div></div>
{% else %}
<!-- 显示总数以及查询耗时
打印表格、说明头部行、查询到的数据-->
<div class="row">
<div class="alert alert-success alert-dismissible col-md-10 col-md-offset-1" role="alert">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span></button>
找到与<b>&nbsp {{ keywords }} &nbsp</b>相关的结果 {{ countNum }} 个。用时 {{ time }} 秒。</div>
<div class="table-responsive col-md-12">
<table class="table table-striped table-hover">
<tr>
<th class="text-center">用户名</th>
<th class="text-center">密码</th>
<th class="text-center">姓名</th>
<th class="text-center">邮箱</th>
<th class="text-center">QQ 号码</th>
<th class="text-center">数据来源</th>
</tr>
<!-- 填充查询到的数据 -->
</table></div></div>
{% endif %}
{% endif %}
</div>
</body>
</html>

3.根据条件查询数据

模型层主要跟数据库打交道, 数据库存储数据的地方。所以查询数据内容其实是模型知识地运用。

考虑到数据库中可能存在多条关键字(queryContent)相关的数据,所以需要使用 filter() 来匹配。我使用的匹配模式是精确匹配,所以无须使用正则表达式来匹配。直接把关键字作为模型过滤条件就可以了,实现代码如下:

1
2
3
4
5
# 把 Socialusers 的 username 属性作为 condition 来查询数据。
# 查询内容是用户输入的内容 queryContent
user_list = Socialusers.objects.filter(username=keywords)
# 获取总条数
countNum = user_list.count()

condition 记录用户选择下拉框的条目值。该变量的值决定模型 Socialusers 要使用哪个属性来查询。由于 python 没有 switch 语句,只能写多个 elif 来处理多个条件。那么代码可以这么实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# views.py
def index(request):
templateView = 'index.html'
countNum = -1
keywords = ''
time = 0

if request.method == 'GET':
form = QueryUserForm(request.GET)
# 验证表单
if form.is_valid():
# 过滤需要的数据
condition = form.cleaned_data['condition']
keywords = form.cleaned_data['queryContent']

print('condition == ' + condition)
print('keywords == ' + keywords)

countNum = 0
# 查询结果
if condition == 'username':
user_list = Socialusers.objects.filter(username=keywords)
countNum = user_list.count()
# 获取查询耗时
time = (connection.queries)[0].get('time')
print('user_list size=== ', user_list.count())
print('time === ', time)

# 显示分页操作, 每页显示 20 条
paginator = Paginator(user_list, 20)
page = request.GET.get('page')
try:
users = paginator.page(page)
except PageNotAnInteger:
# 如果请求的页数不是整数,返回第一页。
users = paginator.page(1)
except EmptyPage:
# 如果请求的页数不在合法的页数范围内,返回结果的最后一页。
users = paginator.page(paginator.num_pages)

return render(request, templateView, {
'countNum': countNum,
'condition': condition,
'keywords': keywords,
'form': form,
'users': users,
'time': time,
})
elif condition == 'password':
# 后面的代码逻辑跟前面类似, 只不过 filer() 的内容改变了。

# 查询不到数据, 显示没有数据的浮窗
if countNum == 0:
return render(request, templateView, {
'countNum': countNum,
'keywords': keywords,
'form': form,
})
# 直接访问主页, 显示的内容
else:
return render(request, templateView, {'countNum': countNum, 'form': form})

代码中使用到了分页 Paginator,这部分后面会继续讲解。

4.填充数据

最后一步工作就是在模板中填充查询到的数据。因为我们在视图中将查询到 user_list 集合传递给模板。这里要注意的是,user_list 其实是一个查询集 QuerySet,不是真正意义上的列表,只不过命名为列表而已。在模板中,使用一个 for 循环逐一解析每个模型的值,就能完成数据填充工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
# index.html
<!-- 填充查询到的数据 -->
# 在下面的注释下面,打印查询到的数据
{% for user in users %}
<tr>
<td class="text-center">{{ user.username }}</td>
<td class="text-center">{{ user.password }}</td>
<td class="text-center">{{ user.chinesename }}</td>
<td class="text-center">{{ user.email }}</td>
<td class="text-center">{{ user.qq }}</td>
<td class="text-center">{{ user.source }}</td>
</tr>
{% endfor %}

第一个实战项目到这里就结束了。主要目的是让大家明白如何将模型、表单、模板、视图串联起来。后面的文章会讲解高级用法以及前面遗漏的细节内容。

5.源码

如果你想获取项目的源码, 点击按钮进行下载。

评论