实现目标及功能,增删改,并且实现搜索,分页,日期插件,删除提示,以及批量导入等功能
软件版本:
python3.5
django1.11
一 用pycharm创建一个项目,名字自定义
二 编辑urls.py
1 from django.conf.urls import url, include
2 from django.contrib import admin
3 from hnf import views
4
5 urlpatterns = [
6 # 无论访问那个页面都会跳转到登陆页面
7 url(r'^$', views.login),
8 # 登陆
9 url(r'^login', views.login),
10 # 注销
11 url(r'^logout', views.logout),
12 # 搜索
13 url(r'^search', views.search, name='search'),
14 # django自带后台
15 url(r'^admin/', admin.site.urls),
16 # 展示页面
17 url(r'^asset/list/$', views.asset_list, name='asset_list'),
18 url(r'^asset/add/$', views.asset_add),
19 url(r'^asset/edit/(?P<cid>\d+)/$', views.asset_edit),
20 url(r'^asset/del/(?P<cid>\d+)/$', views.asset_del),
21 # 导入
22 url(r'^asset/import/$', views.asset_import),
23 # 导入模板
24 url(r'^asset/tpl/$', views.asset_tpl),
三 创建数据库,我这里默认用的sqlite
1 from django.db import models
2
3
4 # Create your models here.
5
6
7 class Asset(models.Model):
8 """
9 资产表
10 """
11 brand = models.CharField(verbose_name='品牌', max_length=32)
12 model = models.CharField(verbose_name='型号', max_length=32)
13 number = models.CharField(verbose_name='编号', max_length=32)
14 leader_time = models.DateTimeField(verbose_name='领用时间', max_length=32)
15 leader = models.CharField(verbose_name='领用人', max_length=32)
16 return_time = models.DateTimeField(verbose_name='归还时间', max_length=32,null=True)
17 other = models.CharField(verbose_name='备注', max_length=128,null=True)
18
19 def __str__(self):
20
21 return self.leader
22
23 class Meta:
24 verbose_name="资产表"
25 verbose_name_plural = verbose_name
然后用下面两条命令去生成数据库
python3 manage.py makemigrations
python3 manage.py migrate
四 更改views.py
1 import os
2 import mimetypes
3 from django.shortcuts import render, redirect
4 from django.http import FileResponse
5 from django.conf import settings
6 import xlrd
7 from asset import mypage
8 from hnf.forms.customer import UserinfoForm
9 from hnf.forms.asset import AssetForm
10 from hnf import models
11
12 from django.contrib import auth
13 from django.contrib.auth.decorators import login_required
14 from hnf.utils.urls import memory_reverse
15
16 # Create your views here.
17 # 登录页面
18 def login(request):
19 if request.method == "GET":
20 return render(request, "login.html")
21 else:
22 next_url = request.GET.get("next")
23
24 username = request.POST.get("username")
25 pwd = request.POST.get("password")
26 user_obj = auth.authenticate(request, username=username, password=pwd)
27 if user_obj:
28 auth.login(request, user_obj) # # 给该次请求设置了session数据,并在响应中回写cookie
29 if next_url:
30 return redirect(next_url)
31 else:
32 return redirect("/asset/list/")
33 else:
34 return render(request, "login.html", {"error_msg": "用户名或密码错误"})
35
36 # 注销页面
37 def logout(request):
38 auth.logout(request)
39 return redirect("/login/")
40
41 def search(request):
42 q = request.GET.get('q')
43 error_msg = ''
44
45 if not q:
46 error_msg = '请输入关键词'
47 return render(request, 'result.html', {'error_msg': error_msg})
48
49 # post_list = models.Asset.objects.filter(leader__icontains=q)
50 # for i in post_list:
51 data_list=models.Asset.objects.filter(leader__contains=q)
52 return render(request, 'result.html', {'error_msg': error_msg, 'post_list': data_list})
53
54
55 @login_required()
56 def asset_list(request):
57 """
58 资产列表
59 :return:
60 """
61 data_list = models.Asset.objects.all()
62 print(data_list)
63 total_count = data_list.count()
64
65 current_page = request.GET.get("page")
66
67 page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
68 data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
69
70 page_html = page_boj.page_html() # 页面
71 page_num = page_boj.num() # 序号
72
73 return render(request, 'asset_list.html', {'data_list': data, 'page_html': page_html, 'num': page_num})
74
75
76 def asset_add(request):
77 """
78 添加资产
79 :param request:
80 :return:
81 """
82 if request.method == 'GET':
83 form = AssetForm()
84 return render(request, 'asset_add.html', {'form': form})
85 form = AssetForm(data=request.POST)
86 if form.is_valid():
87 form.save()
88 return redirect('/asset/list/')
89 return render(request, 'asset_add.html', {'form': form})
90
91
92 def asset_edit(request, cid):
93 """
94 编辑资产
95 :return:
96 """
97 obj = models.Asset.objects.get(id=cid)
98 if request.method == 'GET':
99 form = AssetForm(instance=obj)
100 return render(request, 'asset_edit.html', {'form': form})
101 form = AssetForm(data=request.POST, instance=obj)
102 if form.is_valid():
103 form.save()
104 return redirect('/asset/list/')
105 return render(request, 'asset_edit.html', {'form': form})
106
107
108 def asset_del(request, cid):
109 """
110 删除资产
111 :param request:
112 :param cid:
113 :return:
114 """
115 # models.Asset.objects.filter(id=cid).delete()
116 #
117 # return redirect('/asset/list/')
118
119 origin = memory_reverse(request, 'asset_list')
120 print(origin)
121 if request.method == 'GET':
122 return render(request, 'delete.html', {'cancel': origin})
123 models.Asset.objects.filter(id=cid).delete()
124 return redirect(origin)
125
126
127 def asset_import(request):
128 """
129 批量导入用户
130 :param request:
131 :return:
132 """
133
134 if request.method == 'GET':
135 return render(request, 'asset_import.html')
136
137 context = {'status': True, 'msg': '导入成功'}
138 try:
139 customer_excel = request.FILES.get('customer_excel')
140 """
141 打开上传的Excel文件,并读取内容
142 注:打开本地文件时,可以使用:workbook = xlrd.open_workbook(filename='本地文件路径.xlsx')
143 """
144 workbook = xlrd.open_workbook(file_contents=customer_excel.file.read())
145
146 # sheet = workbook.sheet_by_name('工作表1')
147 sheet = workbook.sheet_by_index(0)
148 row_map = {
149 0: {'text': '品牌', 'name': 'brand'},
150 1: {'text': '型号', 'name': 'model'},
151 2: {'text': '编号', 'name': 'number'},
152 3: {'text': '领用时间', 'name': 'leader_time'},
153 4: {'text': '领用人', 'name': 'leader'},
154 5: {'text': '归还时间', 'name': 'return_time'},
155 6: {'text': '备注', 'name': 'other'},
156
157 }
158 object_list = []
159 for row_num in range(1, sheet.nrows):
160 row = sheet.row(row_num)
161 print(row)
162 row_dict = {}
163 for col_num, name_text in row_map.items():
164 row_dict[name_text['name']] = row[col_num].value
165 object_list.append(models.Asset(**row_dict))
166
167 models.Asset.objects.bulk_create(object_list, batch_size=20)
168 except Exception as e:
169 context['status'] = False
170 context['msg'] = '导入失败'
171
172 return render(request, 'asset_import.html', context)
173
174
175 def asset_tpl(request):
176 """
177 下载批量导入Excel列表
178 :param request:
179 :return:
180 """
181 tpl_path = os.path.join(settings.BASE_DIR, 'hnf', 'files', '批量导入资产模板.xlsx')
182 content_type = mimetypes.guess_type(tpl_path)[0]
183 print(content_type)
184 response = FileResponse(open(tpl_path, mode='rb'), content_type=content_type)
185 response['Content-Disposition'] = "attachment;filename=%s" % 'asset_excel_tpl.xlsx'
186 return response
五 在templates下面添加html页面,我这里举例是asset_list页面
1 {% extends 'layout.html' %}
2
3 {% block content %}
4
5 <div class="luffy-container">
6 <div class="btn-group" style="margin: 5px 0">
7 <a class="btn btn-default" href="/asset/add/">
8 <i class="fa fa-plus-square" aria-hidden="true"></i> 添加资产
9 </a>
10 <a class="btn btn-default" href="/asset/import/">
11 <i class="fa fa-file-excel-o" aria-hidden="true"></i> 批量导入
12 </a>
13 <div class="right" style="margin-left: 911px" >
14 <form method="get" action="{% url 'search' %}">
15 {# {% csrf_token %}#}
16 <input name="q" type="search" placeholder="请输入姓名" required>
17 <button type="submit">搜索</button>
18 </form>
19
20 </div>
21
22 </div>
23
24 <table class="table table-bordered table-hover">
25 <thead>
26 <tr>
27 <th>ID</th>
28 <th>品牌</th>
29 <th>型号</th>
30 <th>编号</th>
31 <th>领用时间</th>
32 <th>领用人</th>
33 <th>归还时间</th>
34 <th>备注</th>
35 <th>编辑</th>
36
37 </tr>
38 </thead>
39 <tbody>
40 {% for row in data_list %}
41 <tr>
42 <td>{{ row.id }}</td>
43 <td>{{ row.brand }}</td>
44 <td>{{ row.model }}</td>
45 <td>{{ row.number }}</td>
46 <td>{{ row.leader_time|date:"Y-m-d" }}</td>
47 <td>{{ row.leader }}</td>
48 <td>{{ row.return_time|date:"Y-m-d" }}</td>
49 <td>{{ row.other }}</td>
50
51 <td>
52 <a style="color: #333333;" href="/asset/edit/{{ row.id }}/">
53 <i class="fa fa-edit" aria-hidden="true"></i></a>
54 |
55 <a style="color: #d9534f;" href="/asset/del/{{ row.id }}/"><i class="fa fa-trash-o"></i></a>
56 </td>
57
58 </tr>
59 {% endfor %}
60 </tbody>
61 </table>
62 {{ page_html|safe }}
63 </div>
64 {% endblock %}
六 最后启动django项目,用浏览器访问即可
七 总结用到的知识点:
1 django自动的auth模块,以及django自带的数据库,自动实现密码加密,用户登录认证等功能,代码如下:
其中 @login_required() 也是auth模块里面的,作用是当访问list页面的时候,必须要先登陆
1 from django.contrib import auth
2 def login(request):
3 if request.method == "GET":
4 return render(request, "login.html")
5 else:
6 next_url = request.GET.get("next")
7
8 username = request.POST.get("username")
9 pwd = request.POST.get("password")
10 user_obj = auth.authenticate(request, username=username, password=pwd)
11 if user_obj:
12 auth.login(request, user_obj) # # 给该次请求设置了session数据,并在响应中回写cookie
13 if next_url:
14 return redirect(next_url)
15 else:
16 return redirect("/asset/list/")
17 else:
18 return render(request, "login.html", {"error_msg": "用户名或密码错误"})
19
20 # 注销页面
21 def logout(request):
22 auth.logout(request)
23 return redirect("/login/")
24
25
26 @login_required()
27 def asset_list(request):
28 """
29 资产列表
30 :return:
31 """
32 data_list = models.Asset.objects.all()
33 print(data_list)
34 total_count = data_list.count()
35
36 current_page = request.GET.get("page")
37
38 page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
39 data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
40
41 page_html = page_boj.page_html() # 页面
42 page_num = page_boj.num() # 序号
43
44 return render(request, 'asset_list.html', {'data_list': data, 'page_html': page_html, 'num': page_num})
2 搜索功能
1 def search(request):
2 q = request.GET.get('q')
3 error_msg = ''
4
5 if not q:
6 error_msg = '请输入关键词'
7 return render(request, 'result.html', {'error_msg': error_msg})
8
9
11 data_list=models.Asset.objects.filter(leader__contains=q) # 利用了orm的语法查询关键字
12 return render(request, 'result.html', {'error_msg': error_msg, 'post_list': data_list})
3 分页功能,需要先自定义一个分页的函数叫MyPage(可自定义),然后导入引用
1 def asset_list(request):
2 """
3 资产列表
4 :return:
5 """
6 data_list = models.Asset.objects.all()
7 ###分页开始 8 total_count = data_list.count()
9
10 current_page = request.GET.get("page")
11
12 page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
13 data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
14
15 page_html = page_boj.page_html() # 页面
16 page_num = page_boj.num() # 序号
###分页结束
17
18 return render(request, 'asset_list.html', {'data_list': data, 'page_html': page_html, 'num': page_num})
4 日期插件功能,效果如图所示,这是导入了第三方的laydate,具体参考 https://www.layui.com/laydate/
实现方法,在html页面里面先导入一个js,#id_return_time'代表的是input框的id值,如何查看这个框的id值,可以f12,选中这个input框去查看
1 {% block js %}
2 <script src="/static/laydate/laydate.js"></script>
3
4 <script>
5 //执行一个laydate实例
6 laydate.render({
7 elem: '#id_leader_time'
8
9 });
10 </script>
11
12 <script>
13 //执行一个laydate实例
14 laydate.render({
15 elem: '#id_return_time'
16
17 });
18 </script>
19 {% endblock %}
5 删除提示实现代码
1 def asset_del(request, cid):
2 """
3 删除资产
4 :param request:
5 :param cid:
6 :return:
7 """
8 # models.Asset.objects.filter(id=cid).delete()
9 #
10 # return redirect('/asset/list/')
11
12 origin = memory_reverse(request, 'asset_list')
13 print(origin)
14 if request.method == 'GET':
15 return render(request, 'delete.html', {'cancel': origin}) # 这里是代表点取消之后返回原来的页面
16 models.Asset.objects.filter(id=cid).delete()
17 return redirect(origin)
然后再增加一个delete.html页面,取消里面的这个href这里一定要和views里面的 return render(request, 'delete.html', {'cancel': origin}),一样。
1 {% extends 'layout.html' %}
2
3 {% block content %}
4 <div class="luffy-container">
5 <div class="alert alert-danger" role="alert">
6 <form method="post">
7 {% csrf_token %}
8 <p style="font-size: 13px;"><i class="fa fa-warning" aria-hidden="true"></i> 删除后将不可恢复,请确定是否删除?</p>
9 <div style="margin-top: 20px;">
10 <a href="{{ cancel }}" class="btn btn-default btn-sm">取消</a>
11 <button type="submit" class="btn btn-danger btn-sm">确 认</button>
12 </div>
13 </form>
14 </div>
15 </div>
16
17 {% endblock %}
6 批量导入功能
import xlrd
def asset_import(request):
"""
批量导入
:param request:
:return:
"""
if request.method == 'GET':
return render(request, 'asset_import.html')
context = {'status': True, 'msg': '导入成功'}
try:
customer_excel = request.FILES.get('customer_excel')
"""
打开上传的Excel文件,并读取内容
注:打开本地文件时,可以使用:workbook = xlrd.open_workbook(filename='本地文件路径.xlsx')
"""
workbook = xlrd.open_workbook(file_contents=customer_excel.file.read())
# sheet = workbook.sheet_by_name('工作表1')
sheet = workbook.sheet_by_index(0)
row_map = {
0: {'text': '品牌', 'name': 'brand'},
1: {'text': '型号', 'name': 'model'},
2: {'text': '编号', 'name': 'number'},
3: {'text': '领用时间', 'name': 'leader_time'},
4: {'text': '领用人', 'name': 'leader'},
5: {'text': '归还时间', 'name': 'return_time'},
6: {'text': '备注', 'name': 'other'},
}
object_list = []
for row_num in range(1, sheet.nrows):
row = sheet.row(row_num)
print(row)
row_dict = {}
for col_num, name_text in row_map.items():
row_dict[name_text['name']] = row[col_num].value
object_list.append(models.Asset(**row_dict))
models.Asset.objects.bulk_create(object_list, batch_size=20)
except Exception as e:
context['status'] = False
context['msg'] = '导入失败'
return render(request, 'asset_import.html', context)
7 form组件
1 from django.forms import ModelForm, Form
2 from django import forms
3 from hnf import models
4
5
6 class AssetForm(ModelForm):
7 class Meta:
8 model = models.Asset
9 fields = "__all__"
10
11 def __init__(self, *args, **kwargs):
12
13 super(AssetForm, self).__init__(*args, **kwargs)
14
15 for name, field in self.fields.items():
16 field.widget.attrs['class'] = 'form-control' # 应用样式
17 # field.widget.attrs['id'] = 'time' # 应用样式
18 field.widget.attrs['placeholder'] = field.label #默认显示的字段
19
20 self.fields['other'].required = False # 是否允许字段为空,false是允许为空,true不允许
21 self.fields['return_time'].required = False
views里面的配置
1 def asset_add(request):
2 """
3 添加资产
4 :param request:
5 :return:
6 """
7 if request.method == 'GET':
8 form = AssetForm()
9 return render(request, 'asset_add.html', {'form': form})
10 form = AssetForm(data=request.POST)
11 if form.is_valid():
12 form.save()
13 return redirect('/asset/list/')
14 return render(request, 'asset_add.html', {'form': form})
html页面配置
1 {% extends 'layout.html' %}
2
3 {% block content %}
4 <div class="luffy-container">
5 <form class="form-horizontal clearfix" method="post" novalidate>
6 {% csrf_token %}
7
8 {% for field in form %}
9 <div class="form-group col-sm-6 clearfix">
10 <label class="col-sm-3 control-label">{{ field.label }}</label>
11 <div class="col-sm-9">
12 {{ field }} <span style="color:firebrick;">{{ field.errors.0 }}</span>
13 </div>
14 </div>
15 {% endfor %}
16 <div class="form-group col-sm-12">
17 <div class="col-sm-6">
18 <div class="col-sm-offset-3">
19 <button type="submit" class="btn btn-primary">提 交</button>
20 </div>
21 </div>
22 </div>
23 </form>
24 </div>
25 {% endblock %}
26
27 {% block js %}
28 <script src="/static/laydate/laydate.js"></script>
29
30 <script>
31 //执行一个laydate实例
32 laydate.render({
33 elem: '#id_leader_time'
34
35 });
36 </script>
37
38 <script>
39 //执行一个laydate实例
40 laydate.render({
41 elem: '#id_return_time'
42
43 });
44 </script>
45 {% endblock %}
完整代码见gitlab https://github.com/huningfei/asset.git 分支名为默认的master