如何用django框架完整的写一个项目

实现目标及功能,增删改,并且实现搜索,分页,日期插件,删除提示,以及批量导入等功能

软件版本:

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
View Code

五 在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 %}
View Code

六  最后启动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 

分支名  asset-laydate
原文地址:https://www.cnblogs.com/huningfei/p/10716916.html