效果 主要分三个部分进行介绍 界面设计;动态渲染;数据获取
界面设计
(1)将这个界面分为上部导航栏、左侧导航栏和表格显示区域三部分; 我们期望的结果是通过点击左侧导航栏的选项,在右侧动态展示不同信息, 这里我们使用iframe来实现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Manage</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<iframe height="50px" width="100%" id="top" src="{% url 'top' %}"></iframe>
<iframe height="600px" width="15%" id="left" src="{% url 'left' %}"></iframe>
<iframe height="600px" width="83%" id="right" name="show"></iframe>
</body>
</html>
定义三个iframe:left、top和right,设置每个frame的高和宽,达到上面的布局,这里不再详细阐述,可以看上方代码。 (2)编写相应三个iframe对应网页 top和left主要是编写导航栏,可以直接搜索bootstrap的导航栏,选择自己喜欢的样式复制过来即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Manage</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<iframe height="50px" width="100%" id="top" src="{% url 'top' %}"></iframe>
<iframe height="600px" width="15%" id="left" src="{% url 'left' %}"></iframe>
<iframe height="600px" width="83%" id="right" name="show"></iframe>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Top</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#demo-navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">管理系统</a>
</div>
</body>
</html>
本文选用a标签设计导航栏,通过href实现点击跳转动作,{% url ‘student_manage’ %}表示跳转的路由,在urls中定义了和该路由绑定的视图函数,当然也可以写成静态HTML。target表示点击该标签后,请求路由,并将请求到的信息在target上显示,这里target=‘show’,在manage中定义了right iframe的名字是show。也就是说当点击标签后,进行跳转,将请求到的信息在right的iframe中显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Left</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="list-group">
<a href="{% url 'student_manage' %}" class="list-group-item" target="show">学生管理</a>
<a href="{% url 'book_manage' %}" class="list-group-item" target="show">图书管理</a>
<a href="{% url 'comment_manage' %}" class="list-group-item" target="show">评论管理</a>
<a href="{% url 'record_manage' %}" class="list-group-item" target="show">记录管理</a>
<a href="{% url 'advise_manage' %}" class="list-group-item" target="show">建议栏</a>
</div>
</body>
</html>
接下来需要编写我们需要管理的各种信息界面,对应左侧导航栏中的每个选择,这里以图书管理为例,编写book_manage.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"5></script>
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">
<script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>
<script src="https://unpkg.com/bootstrap-table@1.15.3/dist/locale/bootstrap-table-zh-CN.min.js"></script>
</head>
<body>
<div id="panel-group" >
<div class="panel-body">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">图书信息管理</h3>
</div>
<div class="panel-body">
<div style="display:inline-block;">
<div style="float:left;padding:6px;">
<span>查询内容:</span>
</div>
<div style="float:left;">
<input id="input" class="form-control" style="width:200px;" placeholder="请输入" />
</div>
<div style="float:left;padding:6px;">
<span>查询条件:</span>
</div>
<div style="float:left;">
<select id="select" class="form-control" style="width:200px;">
<option value="">请选择</option>
<option value="b_id">书号</option>
<option value="b_isbn">ISBN</option>
<option value="b_pub">出版社</option>
<option value="a_id">作者</option>
<option value="b_category">类别</option>
<option value="b_score">评分</option>
</select>
</div>
<div style="float:left;margin-left:20px;">
<button id="query" class="btn btn-primary" onclick="search()">查询</button>
</div>
<div style="float:left;margin-left:20px;">
<button id="reset" class="btn btn-primary" onclick="reset()">重置</button>
</div>
</div>
</div>
</div>
<div style="width: 95%;margin-bottom: 10%;margin-right: 20px;margin-left: 20px;">
<table id="table" ></table>
</div>
</div>
</body>
</html>
使用boostrap-table显示各种信息,在使用时,引入bootstrap和bootstrap-table相关的js和css文件,只需要定义一个table,即<table id="table" ></table> 。表信息的初始化在JS代码中实现。
bootstrap-table显示信息
在JS中定义表头,请求路由,后端返回数据,在前端表中显示出来; 1、queryParams之前定义一些参数信息,重要的参数有 (1)请求路由url (2)请求参数method,一般是get和post,默认为get (3)pageNumber: 1 从第几页开始显示 (4)pageSize: 8 每页显示多少行 (5)sidePagination: “server”, //分页方式:client客户端分页,server服务端分页(*) (6)queryParamsType : “limit”,设置为 ‘limit’ 则会发送符合 RESTFul 格式的参数。 2、queryParams: function (params) 在这个函数里,可以自定义参数传递到后端,比如我们设计的查询内容和查询条件,以字典的形式传递到后端进行处理 3、columns定义表头,里面主要包含三个元素 (1)field: 相当于这个字段的ID,这个要和后端传递过来的键值匹配,才能正确显示内容 (2)title: 表头显示的内容 (3)align: ‘center’, 表格对齐方式
<script type="text/javascript">
$(function () {
load('/info/')
});
function load(url){
$('#table').bootstrapTable({
url: url,
dataType: "json",
method: 'post',
pagination: true,
singleSelect: false,
search: false,
toolbar: '#toolbar',
striped: true,
cache: false,
pageNumber: 1,
pageSize: 8,
pageList: [8, 20, 50, 100],
strictSearch: true,
showColumns: false,
showRefresh: false,
minimumCountColumns: 2,
clickToSelect: true,
uniqueId: "id",
showToggle: false,
cardView: false,
sidePagination: "server",
queryParamsType : "limit",
queryParams: function (params) {
var data = {
size: params.limit,
current: (params.offset / params.limit) + 1,
content:$('#input').val(),
condition:$('#select').val(),
table_name:'Book',
};
return data;
},
responseHandler: function (res) {
return res;
},
columns: [{
checkbox: true,
visible: true
}, {
field: 'b_id',
title: '书号',
align: 'center',
}, {
field: 'b_isbn',
title: 'ISBN',
align: 'center'
}, {
field: 'b_pub',
title: '出版社',
align: 'center'
}, {
field: 'b_date',
title: '出版日期',
align: 'center',
}, {
field: 'a_id',
title: '作者',
align: 'center',
}, {
field: 'b_intro',
title: '书籍简介',
align: 'center',
}, {
field: 'b_img',
title: '封面',
align: 'center',
}, {
field: 'b_score',
title: '评分',
align: 'center',
}, {
field: 'b_category',
title: '分类',
align: 'center',
}, {
field: 'b_title',
title: '标题',
align: 'center',
}, {
field: 'op',
title: '操作',
align: 'center',
formatter: function (value, row, index) {
var result = "";
result += '<a href="javascript:;" class="btn btn-xs btn-success" style="margin:5px" οnclick="EditViewById(\'undefined\', view=\'view\')" title="查看">';
result += '<span class="glyphicon glyphicon-search"></span></a>';
result += '<a href="javascript:;" class="btn btn-xs btn-info" style="margin:5px" οnclick="EditViewById(\'undefined\')" title="编辑">';
result += '<span class="glyphicon glyphicon-pencil"></span></a>';
result += '<a href="javascript:;" class="btn btn-xs btn-danger" style="margin:5px" οnclick="DeleteByIds(\'undefined\')" title="删除">';
result += '<span class="glyphicon glyphicon-remove"></span></a>';
return result;
}
}
],
});
}
function search(){
$('#table').bootstrapTable('destroy');
load('/query/');
}
function reset(){
$('#table').bootstrapTable('destroy');
$("#select").val("");
$("#input").val("");
load('/info/');
}
</script>
初始化时请求路由‘/info/’会查询整张表,当点击查询按钮查询数据时,需要先将表中内容清空$('#table').bootstrapTable('destroy'); ,然后请求查询数据路由,根据返回的数据重新渲染表格;
ORM数据库配置
首先在settings中配置数据库,本文采用的是MySQL数据库,默认使用的是sqlite3 NAME为数据库名称、USER用户名、PASSWORD密码、HOST数据库服务器地址、PORT端口号
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'XXX',
'USER':'XXX',
'PASSWORD':'XXX',
'HOST':'XX.XX.XX.XX',
'PORT':'3306',
}
}
ORM表格创建
此处等待更新
ORM查询操作
(1)使用filter过滤器 ob = models.Book.object.filter() 返回的是Query set,可以返回多条结果;验证某个数据是否存在时,可以用ob.count()方法计算结果的数量 (2)get方法 ob = models.Book.object.get() 返回的是Model,可以使用model_to_dict转化为字典进行访问,但是只能返回一个数据,如果有多条数据会报错;判断数据是否存在时,则是判断ob是否为空.
filter适合批量查询,比如查询某个作者写的所有的书籍,适合用filter。
python反射机制根据传递的表名灵活查询
反射机制:通过字符串的形式导入模块;通过字符串的形式,在模块寻找指定函数;通过字符串的形式查找某个函数中的成员
在后端管理系统中,往往有很多信息需要管理,如作者信息和书籍信息,都需要进行全表查询,将查询结果显示在前端界面。所以可以写一个视图函数,来处理全表查询操作,增强代码的复用性,减少冗余性,这就需要指定表名。 在bootstrap-table里queryParams: function (params)函数中,添加参数table_name指定表名。
queryParams: function (params) {//自定义参数,这里的参数是传给后台的
var data = {
size: params.limit, //页面大小
current: (params.offset / params.limit) + 1, //页码
content:$('#input').val(),
condition:$('#select').val(),
table_name:'Book',
};
return data;
},
responseHandler: function (res) {
return res;
},
第一种反射机制:获取模块中的方法 请求方法是POST方法,参数存储在body中,先取出参数,通过getattr()获取models中的方法,第一个反射机制体现在table = getattr(models, body[‘table_name’])中。
最常用方法是models.Book.objects.all(),Book为表名,因此我们通过getattr函数,就可以获取一个table对象,直接使用table.objects.all()即可获取表的全部信息。
if request.method == 'POST':
body = json.loads(request.body)
table = getattr(models, body['table_name'])
size, current = body['size'], body['current']
total = table.objects.count()
infos = table.objects.all().order_by()
paginator = Paginator(infos, per_page=size)
page_object = paginator.page(current)
total = infos.count()
rows = []
for item in page_object:
d = model_to_dict(item)
for k, v in d.items():
if 'date' in k:
d[k] = str(v)
elif k == "a_id":
d[k] = item.a_id.a_name
rows.append(d)
data = {'total': total, 'rows': rows}
return HttpResponse(json.dumps(data), content_type='application/json')
注意:bootstrap-table接收的数据类型必须为{'total':total.'rows':rows} ,因此需要先将数据转换成该形式,再返回给前端。此外,返回的数据必须是字符串类型,才可以显示在表格中,如果含有date类型数据,需要现将其转换为字符串。
第二种反射机制:获取某个成员中的元素 主要是先获取表格中的所有字段,再根据字段信息获取该字段对应的value值,其实本质想将model或者queryset数据转换为bootstrap可以接受的形式。但是后面发现可以直接使用model_to_dict实现,所以就舍弃了下面的方法;这种思路可以借鉴。
body = json.loads(request.body)
table = getattr(models, body['table_name'])
fields = table._meta.fields
infos = table.objects.all()
d = {}
rows = []
for info in infos:
for f in fields:
d[f] = getattr(info,f)
rows.append(d)
|