前面的文章已经把模板、模型、视图、表单等知识点逐一讲解,大家已经熟悉它们具体用法。但如何将其串联起来还一筹莫展。本篇文章分享我之前做过的一个小项目,帮助大家抹开这一层迷雾。

1.想做什么?

我分享的项目是一个社工库查询系统。大家不要一拿到源码,就直接去阅读。建议先思考下,如果让我来设计社工库查询系统,我要如何实现?

我就先阐述我思考的内容。既然项目是一个查询系统,那么重点在于查询。众所周知,查询数据则是执行 SQL 语句来从数据库中获取数据。SQL 查询语句一般使用表中的字段作为查询条件。哪些能作为查询条件呢?先让我们来看看数据库表是怎么定义的?

2.数据库表

数据库中只有一个表,名为 Socialusers。它的创建语句是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Create table if not exists `SocialUsers` (
`id` INTEGER PRIMARY KEY,
`username` varchar(64),
`password` varchar(64),
`chineseName` varchar(64) ,
`email` varchar(64) ,
`QQ` varchar(15) ,
`weibo` varchar(300),
`identity_number` varchar(25),
`cell_phone` varchar(20),
`ip_address` varchar(100),
`college` varchar(60),
`living_place` varchar(200),
`source` varchar(50),
`remarks` varchar(400)
);

表中一共有 13 个字段,其中有 9 个字段的内容属于敏感字段,涉及到个人账号安全问题。因此,我将这 9 个字段,分别是 username、password、chineseName、email、QQ、identity_number、cell_phone、college、source 作为查询条件

那么系统最终的效果是根据查询条件和用户输入的内容来查询数据。如果数据库匹配到数据,就通过表格形式打印数据。反之则提醒用户查询不到数据(查询不到数据应该值得庆幸的,说明你的账号数据没有被泄露)。

我将查询条件以下拉框的形式显示,让用户可以自行选择查询条件。查询内容以文章输入框展示,提供用户输入数据的接口。到这里可以回答之前的想要做什么的问题了。我们最终要实现的页面效果如下:

3.模型建立

数据库已经有了表,我直接使用 Django 自带工具生成 Socialusers 模型。这一步就省略不讲,如果你对这步操作不是很熟悉,可以阅读上篇文章的内容。

最终生成的模型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Socialusers(models.Model):
id = models.IntegerField(blank=True, primary_key=True)
username = models.CharField(max_length=64, blank=True, null=True)
password = models.CharField(max_length=64, blank=True, null=True)
# Field name made lowercase.
chinesename = models.CharField(db_column='chineseName', max_length=64, blank=True, null=True)
email = models.CharField(max_length=64, blank=True, null=True)
# Field name made lowercase.
qq = models.CharField(db_column='QQ', max_length=15, blank=True, null=True)
weibo = models.CharField(max_length=300, blank=True, null=True)
identity_number = models.CharField(max_length=25, blank=True, null=True)
cell_phone = models.CharField(max_length=20, blank=True, null=True)
ip_address = models.CharField(max_length=100, blank=True, null=True)
college = models.CharField(max_length=60, blank=True, null=True)
living_place = models.CharField(max_length=200, blank=True, null=True)
source = models.CharField(max_length=50, blank=True, null=True)
remarks = models.CharField(max_length=400, blank=True, null=True)

class Meta:
managed = True
db_table = 'SocialUsers'

注意下 chinesename 和 qq 这两个属性。我们在数据库中的定义是 chineseName 和 QQ。而 Django 在生成的模型时,自动将大写转为化小写。因此,当我们在使用 Socialusers 这两个属性时,要注意它们的定义已经改变,属性的定义全是小写的。

4.表单实现

表单的实现由两种方式:一种是根据 model 生成 Form,另一种是自定义 Form。我分别把这两种方式实现。你可以对比下这两种写法的差异,以及如何给表单指定 bootstrap CSS 样式的。

4-1.根据 model 生成 Form

在 app 目录下新建文件夹 forms 以及文件 forms.py 。forms.py 主要存放表单的定义,实现代码如下:

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
# forms.py 
CONDITION_CHOICES = (
('username', '用户名'),
('password', '密码'),
('chineseName', '姓名'),
('email', '邮箱'),
('QQ', 'QQ'),
('identity_number', '身份证'),
('cell_phone', '电话'),
('college', '大学'),
('source', '来源'),
)

class QueryUserForm(forms.Form):
condition = forms.CharField( # 也可以定义为 ChoiceField
max_length=20,
widget=forms.Select(choices=CONDITION_CHOICES,
attrs={'class':"form-control",
'title':"query condition",
'name':'condition',
}),
localize=('username', '用户名')
)

queryContent = forms.CharField(
max_length=100,
widget=forms.TextInput(attrs={'class': 'form-control is-invalid',
'name': 'queryContent',
'placeholder': '请输入需要要查询的内容...'
}),
error_messages={'required': '查询内容不能为空 !'}
)

其中, widget 是指定字段呈现样式,如 condition 被指定呈现下拉框 Select;localize 是设置初始化值;error_messages 是错误提示形式。attrs 是为呈现的组件指定一些属性,如 CSS 样式、name 等。这部分内容,后面的文章会做详细讲解。

4-2.自定义 Form

为了更好区分模型,我在 models.py 中新建一个模型来代替之前的 Socialusers 模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# models.py 
# 用于表单查询的 model
CONDITION_CHOICES = (
('username', '用户名'),
('password', '密码'),
('chineseName', '姓名'),
('email', '邮箱'),
('QQ', 'QQ'),
('identity_number', '身份证'),
('cell_phone', '电话'),
('college', '大学'),
('source', '来源'),
)

class QueryUser(models.Model):
condition = models.CharField(max_length=20, choices=CONDITION_CHOICES)
queryContent = models.CharField(max_length=100)

def __str__(self): # __unicode__ on Python 2
return self.condition

Form 的实现代码如下:

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
# forms.py 
class QueryUserForm(ModelForm):
class Meta:
model = QueryUser
fields = ['condition', 'queryContent', ]
# 指定呈现样式字段、指定 CSS 样式
widgets = {
'condition': Select(attrs={'class':"form-control",
'title':"query condition",
'name':'condition',
}),
'queryContent':TextInput(attrs={'class': 'form-control is-invalid',
'name': 'queryContent',
'placeholder': '请输入需要要查询的内容...'
})
}

localized = {
'condition':('username', '用户名'),
'queryContent':123
}

# 自定义错误信息
error_messages = {
'queryContent':{
'required': '查询内容不能为空 !',
}
}

各个字段的含义跟第一种实现方式类似,我就不重复说明。

5.模板创建

我创建名为 templates 文件夹来存放 HTML 文件。其中 index.html 是主页面,也是我们查询数据的页面。因为我前端框架使用的是 bootstrap,所以需要加载一些库。我为了满足在电脑无网络的状态也能使用的需求。我将其 bootstrap 所用到的库到打包到 static 目录下。

代码比较多,我只把重点内容贴出来。详细代码可以通过点击【阅读原文】查看完整代码。

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
{% load staticfiles %}
<!DOCTYPE html>
<html>
<body>
<div class="container" id="container">
<div id="page-header">
<h1 class="text-center"> 社工库查询系统 </h1>
</div>

<div class="row">
<form action="" method="GET" class="form-horizontal" role="form">
<div id="checkbox" class="text-center">
<label class="checkbox-inline text-success">默认采用完整匹配</label>
</div>

<div class="col-md-10 col-md-offset-1">
<div class="col-md-2 col-md-offset-0">
{{ form.condition }}
{% comment %}
{{ form.condition }} 在 html 中将被渲染成以下代码
<select name='condition' title="query condition" class="form-control">
<option >用户名</option>
<option>密码</option>
<option>姓名</option>
<option>邮箱</option>
<option>QQ</option>
<option>身份证</option>
<option>电话</option>
<option>大学</option>
<option>来源</option>
</select>
{% endcomment %}
</div>

<div class="input-group col-md-10 col-md-offset-1">
{{ form.queryContent.field.errors }}
{{ form.queryContent }}

{% comment %}
{{ form.queryContent }} 在 html 中将被渲染成以下代码
<input type="text" class="form-control is-invalid" name="q" placeholder="请输入内容..." value="">
{% endcomment %}

<div class="input-group-btn">
<button type="submit" class="btn btn-primary" required >Search</button>
<div class="invalid-feedback">
Please provide a valid value.
</div>
</div>
</div>
</div>
</form>
</div>
<br>
</div>
</body>
</html>

在 html 代码中,我直接将 form 标签直接写出来,里面的 Select 和 Input 标签通过 Django Form 来填充。下拉框使用表单的 condition 属性,即 来填充 ,输入框也是使用 来填充。当它们渲染的时候,会自动被解析为 Select 和 input 控件。

6.视图

我设定是用户提交表单地址不改变。所以表单数据会被提交到原来的页面。因此,在视图的工作是拦截表单,并截取里面的内容。最后将查询结果返回给 HTML 页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# views.py
def index(request):
templateView = 'index.html'

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)

# 查询数据...

return render(request, templateView, {'form': form})
# 直接访问主页, 显示的内容
else:
return render(request, templateView, {'form': form})

系统的基本框架已经搭建差不多。因为文章篇幅关系,一部分内容下篇文章讲解。下篇文章主要是如何查询数据、如何根据查询结果显示不同内容、如何将数据呈现出来。

7.源码

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

评论