• 如何用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
  • 相关阅读:
    面试常见题型
    docker的安装及基本使用
    redis缓存的使用
    ab压测工具
    redis分布式锁的使用
    webSocket的基本使用
    递归、os.walk、内置函数、lambda、hashlib模块、md5加密、python安装第三方模块、操作mysql数据库
    【Apache】Apache ab压力测试工具Window下载和用法详解
    函数默认值参数、全局变量、深拷贝、可变参数、关键字参数、json模块使用、time模块操作
    python的文件操作1,监控日志联系、读取大文件、修改文件、集合、元组、random模块以及函数初识
  • 原文地址:https://www.cnblogs.com/huningfei/p/10716916.html
Copyright © 2020-2023  润新知