如何用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM