如何用django框架完整的写一个项目
实现目标及功能,增删改,并且实现搜索,分页,日期插件,删除提示,以及批量导入等功能
软件版本:
python3.5
django1.11
一 用pycharm创建一个项目,名字自定义
二 编辑urls.py
- from django.conf.urls import url, include
- from django.contrib import admin
- from hnf import views
- urlpatterns = [
- # 无论访问那个页面都会跳转到登陆页面
- url(r'^$', views.login),
- # 登陆
- url(r'^login', views.login),
- # 注销
- url(r'^logout', views.logout),
- # 搜索
- url(r'^search', views.search, name='search'),
- # django自带后台
- url(r'^admin/', admin.site.urls),
- # 展示页面
- url(r'^asset/list/$', views.asset_list, name='asset_list'),
- url(r'^asset/add/$', views.asset_add),
- url(r'^asset/edit/(?P<cid>\d+)/$', views.asset_edit),
- url(r'^asset/del/(?P<cid>\d+)/$', views.asset_del),
- # 导入
- url(r'^asset/import/$', views.asset_import),
- # 导入模板
- url(r'^asset/tpl/$', views.asset_tpl),
三 创建数据库,我这里默认用的sqlite
- from django.db import models
- # Create your models here.
- class Asset(models.Model):
- """
- 资产表
- """
- brand = models.CharField(verbose_name='品牌', max_length=32)
- model = models.CharField(verbose_name='型号', max_length=32)
- number = models.CharField(verbose_name='编号', max_length=32)
- leader_time = models.DateTimeField(verbose_name='领用时间', max_length=32)
- leader = models.CharField(verbose_name='领用人', max_length=32)
- return_time = models.DateTimeField(verbose_name='归还时间', max_length=32,null=True)
- other = models.CharField(verbose_name='备注', max_length=128,null=True)
- def __str__(self):
- return self.leader
- class Meta:
- verbose_name="资产表"
- verbose_name_plural = verbose_name
然后用下面两条命令去生成数据库
python3 manage.py makemigrations
python3 manage.py migrate
四 更改views.py
- import os
- import mimetypes
- from django.shortcuts import render, redirect
- from django.http import FileResponse
- from django.conf import settings
- import xlrd
- from asset import mypage
- from hnf.forms.customer import UserinfoForm
- from hnf.forms.asset import AssetForm
- from hnf import models
- from django.contrib import auth
- from django.contrib.auth.decorators import login_required
- from hnf.utils.urls import memory_reverse
- # Create your views here.
- # 登录页面
- def login(request):
- if request.method == "GET":
- return render(request, "login.html")
- else:
- next_url = request.GET.get("next")
- username = request.POST.get("username")
- pwd = request.POST.get("password")
- user_obj = auth.authenticate(request, username=username, password=pwd)
- if user_obj:
- auth.login(request, user_obj) # # 给该次请求设置了session数据,并在响应中回写cookie
- if next_url:
- return redirect(next_url)
- else:
- return redirect("/asset/list/")
- else:
- return render(request, "login.html", {"error_msg": "用户名或密码错误"})
- # 注销页面
- def logout(request):
- auth.logout(request)
- return redirect("/login/")
- def search(request):
- q = request.GET.get('q')
- error_msg = ''
- if not q:
- error_msg = '请输入关键词'
- return render(request, 'result.html', {'error_msg': error_msg})
- # post_list = models.Asset.objects.filter(leader__icontains=q)
- # for i in post_list:
- data_list=models.Asset.objects.filter(leader__contains=q)
- return render(request, 'result.html', {'error_msg': error_msg, 'post_list': data_list})
- @login_required()
- def asset_list(request):
- """
- 资产列表
- :return:
- """
- data_list = models.Asset.objects.all()
- print(data_list)
- total_count = data_list.count()
- current_page = request.GET.get("page")
- page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
- data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
- page_html = page_boj.page_html() # 页面
- page_num = page_boj.num() # 序号
- return render(request, 'asset_list.html', {'data_list': data, 'page_html': page_html, 'num': page_num})
- def asset_add(request):
- """
- 添加资产
- :param request:
- :return:
- """
- if request.method == 'GET':
- form = AssetForm()
- return render(request, 'asset_add.html', {'form': form})
- form = AssetForm(data=request.POST)
- if form.is_valid():
- form.save()
- return redirect('/asset/list/')
- return render(request, 'asset_add.html', {'form': form})
- def asset_edit(request, cid):
- """
- 编辑资产
- :return:
- """
- obj = models.Asset.objects.get(id=cid)
- if request.method == 'GET':
- form = AssetForm(instance=obj)
- return render(request, 'asset_edit.html', {'form': form})
- form = AssetForm(data=request.POST, instance=obj)
- if form.is_valid():
- form.save()
- return redirect('/asset/list/')
- return render(request, 'asset_edit.html', {'form': form})
- def asset_del(request, cid):
- """
- 删除资产
- :param request:
- :param cid:
- :return:
- """
- # models.Asset.objects.filter(id=cid).delete()
- #
- # return redirect('/asset/list/')
- origin = memory_reverse(request, 'asset_list')
- print(origin)
- if request.method == 'GET':
- return render(request, 'delete.html', {'cancel': origin})
- models.Asset.objects.filter(id=cid).delete()
- return redirect(origin)
- 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)
- def asset_tpl(request):
- """
- 下载批量导入Excel列表
- :param request:
- :return:
- """
- tpl_path = os.path.join(settings.BASE_DIR, 'hnf', 'files', '批量导入资产模板.xlsx')
- content_type = mimetypes.guess_type(tpl_path)[0]
- print(content_type)
- response = FileResponse(open(tpl_path, mode='rb'), content_type=content_type)
- response['Content-Disposition'] = "attachment;filename=%s" % 'asset_excel_tpl.xlsx'
- return response
五 在templates下面添加html页面,我这里举例是asset_list页面
- {% extends 'layout.html' %}
- {% block content %}
- <div class="luffy-container">
- <div class="btn-group" style="margin: 5px 0">
- <a class="btn btn-default" href="/asset/add/">
- <i class="fa fa-plus-square" aria-hidden="true"></i> 添加资产
- </a>
- <a class="btn btn-default" href="/asset/import/">
- <i class="fa fa-file-excel-o" aria-hidden="true"></i> 批量导入
- </a>
- <div class="right" style="margin-left: 911px" >
- <form method="get" action="{% url 'search' %}">
- {# {% csrf_token %}#}
- <input name="q" type="search" placeholder="请输入姓名" required>
- <button type="submit">搜索</button>
- </form>
- </div>
- </div>
- <table class="table table-bordered table-hover">
- <thead>
- <tr>
- <th>ID</th>
- <th>品牌</th>
- <th>型号</th>
- <th>编号</th>
- <th>领用时间</th>
- <th>领用人</th>
- <th>归还时间</th>
- <th>备注</th>
- <th>编辑</th>
- </tr>
- </thead>
- <tbody>
- {% for row in data_list %}
- <tr>
- <td>{{ row.id }}</td>
- <td>{{ row.brand }}</td>
- <td>{{ row.model }}</td>
- <td>{{ row.number }}</td>
- <td>{{ row.leader_time|date:"Y-m-d" }}</td>
- <td>{{ row.leader }}</td>
- <td>{{ row.return_time|date:"Y-m-d" }}</td>
- <td>{{ row.other }}</td>
- <td>
- <a style="color: #333333;" href="/asset/edit/{{ row.id }}/">
- <i class="fa fa-edit" aria-hidden="true"></i></a>
- |
- <a style="color: #d9534f;" href="/asset/del/{{ row.id }}/"><i class="fa fa-trash-o"></i></a>
- </td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- {{ page_html|safe }}
- </div>
- {% endblock %}
六 最后启动django项目,用浏览器访问即可
七 总结用到的知识点:
1 django自动的auth模块,以及django自带的数据库,自动实现密码加密,用户登录认证等功能,代码如下:
其中 @login_required() 也是auth模块里面的,作用是当访问list页面的时候,必须要先登陆
- from django.contrib import auth
- def login(request):
- if request.method == "GET":
- return render(request, "login.html")
- else:
- next_url = request.GET.get("next")
- username = request.POST.get("username")
- pwd = request.POST.get("password")
- user_obj = auth.authenticate(request, username=username, password=pwd)
- if user_obj:
- auth.login(request, user_obj) # # 给该次请求设置了session数据,并在响应中回写cookie
- if next_url:
- return redirect(next_url)
- else:
- return redirect("/asset/list/")
- else:
- return render(request, "login.html", {"error_msg": "用户名或密码错误"})
- # 注销页面
- def logout(request):
- auth.logout(request)
- return redirect("/login/")
- @login_required()
- def asset_list(request):
- """
- 资产列表
- :return:
- """
- data_list = models.Asset.objects.all()
- print(data_list)
- total_count = data_list.count()
- current_page = request.GET.get("page")
- page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
- data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
- page_html = page_boj.page_html() # 页面
- page_num = page_boj.num() # 序号
- return render(request, 'asset_list.html', {'data_list': data, 'page_html': page_html, 'num': page_num})
2 搜索功能
- def search(request):
- q = request.GET.get('q')
- error_msg = ''
- if not q:
- error_msg = '请输入关键词'
- return render(request, 'result.html', {'error_msg': error_msg})
- data_list=models.Asset.objects.filter(leader__contains=q) # 利用了orm的语法查询关键字
- return render(request, 'result.html', {'error_msg': error_msg, 'post_list': data_list})
3 分页功能,需要先自定义一个分页的函数叫MyPage(可自定义),然后导入引用
- def asset_list(request):
- """
- 资产列表
- :return:
- """
- data_list = models.Asset.objects.all()
- ###分页开始 total_count = data_list.count()
- current_page = request.GET.get("page")
- page_boj = mypage.MyPage(current_page, total_count, url_prefix="asset/list")
- data = data_list[page_boj.start:page_boj.end] # 从第几页显示到第几页
- page_html = page_boj.page_html() # 页面
- page_num = page_boj.num() # 序号
###分页结束- 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框去查看
- {% block js %}
- <script src="/static/laydate/laydate.js"></script>
- <script>
- //执行一个laydate实例
- laydate.render({
- elem: '#id_leader_time'
- });
- </script>
- <script>
- //执行一个laydate实例
- laydate.render({
- elem: '#id_return_time'
- });
- </script>
- {% endblock %}
5 删除提示实现代码
- def asset_del(request, cid):
- """
- 删除资产
- :param request:
- :param cid:
- :return:
- """
- # models.Asset.objects.filter(id=cid).delete()
- #
- # return redirect('/asset/list/')
- origin = memory_reverse(request, 'asset_list')
- print(origin)
- if request.method == 'GET':
- return render(request, 'delete.html', {'cancel': origin}) # 这里是代表点取消之后返回原来的页面
- models.Asset.objects.filter(id=cid).delete()
- return redirect(origin)
然后再增加一个delete.html页面,取消里面的这个href这里一定要和views里面的 return render(request, 'delete.html', {'cancel': origin}),一样。
- {% extends 'layout.html' %}
- {% block content %}
- <div class="luffy-container">
- <div class="alert alert-danger" role="alert">
- <form method="post">
- {% csrf_token %}
- <p style="font-size: 13px;"><i class="fa fa-warning" aria-hidden="true"></i> 删除后将不可恢复,请确定是否删除?</p>
- <div style="margin-top: 20px;">
- <a href="{{ cancel }}" class="btn btn-default btn-sm">取消</a>
- <button type="submit" class="btn btn-danger btn-sm">确 认</button>
- </div>
- </form>
- </div>
- </div>
- {% 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组件
- from django.forms import ModelForm, Form
- from django import forms
- from hnf import models
- class AssetForm(ModelForm):
- class Meta:
- model = models.Asset
- fields = "__all__"
- def __init__(self, *args, **kwargs):
- super(AssetForm, self).__init__(*args, **kwargs)
- for name, field in self.fields.items():
- field.widget.attrs['class'] = 'form-control' # 应用样式
- # field.widget.attrs['id'] = 'time' # 应用样式
- field.widget.attrs['placeholder'] = field.label #默认显示的字段
- self.fields['other'].required = False # 是否允许字段为空,false是允许为空,true不允许
- self.fields['return_time'].required = False
views里面的配置
- def asset_add(request):
- """
- 添加资产
- :param request:
- :return:
- """
- if request.method == 'GET':
- form = AssetForm()
- return render(request, 'asset_add.html', {'form': form})
- form = AssetForm(data=request.POST)
- if form.is_valid():
- form.save()
- return redirect('/asset/list/')
- return render(request, 'asset_add.html', {'form': form})
html页面配置
- {% extends 'layout.html' %}
- {% block content %}
- <div class="luffy-container">
- <form class="form-horizontal clearfix" method="post" novalidate>
- {% csrf_token %}
- {% for field in form %}
- <div class="form-group col-sm-6 clearfix">
- <label class="col-sm-3 control-label">{{ field.label }}</label>
- <div class="col-sm-9">
- {{ field }} <span style="color:firebrick;">{{ field.errors.0 }}</span>
- </div>
- </div>
- {% endfor %}
- <div class="form-group col-sm-12">
- <div class="col-sm-6">
- <div class="col-sm-offset-3">
- <button type="submit" class="btn btn-primary">提 交</button>
- </div>
- </div>
- </div>
- </form>
- </div>
- {% endblock %}
- {% block js %}
- <script src="/static/laydate/laydate.js"></script>
- <script>
- //执行一个laydate实例
- laydate.render({
- elem: '#id_leader_time'
- });
- </script>
- <script>
- //执行一个laydate实例
- laydate.render({
- elem: '#id_return_time'
- });
- </script>
- {% endblock %}
完整代码见gitlab https://github.com/huningfei/asset.git
- 分支名 asset-laydate
如何用django框架完整的写一个项目的更多相关文章
- Django 从0开始创建一个项目
title: Django 从0开始创建一个项目 tags: Django --- Django 从0开始创建一个项目 创建Django工程及配置 创建工程:django-admin starproj ...
- 学习T-io框架,从写一个Redis客户端开始
前言 了解T-io框架有些日子了,并且还将它应用于实战,例如 tio-websocket-server,tio-http-server等.但是由于上述两个server已经封装好,直接应用就可以.所 ...
- python3开发进阶-Django框架学习前的小项目(一个简单的学员管理系统)
''' 自己独立写一个学员管理系统 表结构: 班级表: -id -grade_name 学生表: -id -student_name -grade 关联外键班级表 老师表: -id -teacher_ ...
- django开发项目实例1--建立一个项目并初步运行
1:进入目标目录新建一个项目 D:\>django-admin.py startproject qiweijie 新建完成后,进入项目文件夹查看目录 D:\>cd qiweijie D:\ ...
- redis数据库如何用Django框架缓存数据
---恢复内容开始--- 一.python 使用redis 1.1 安装 pip install redis 测试有一些基本的数据类型 import redis # redis 是一个缓存数据库 # ...
- [ionic3.x开发记录]参考ionic的float-label动效,写一个项目内通用的input组件,易扩展
上图: module: import {NgModule} from "@angular/core"; import {CommonModule} from "@angu ...
- web 框架的本质及自定义web框架 模板渲染jinja2 mvc 和 mtv框架 Django框架的下载安装 基于Django实现的一个简单示例
Django基础一之web框架的本质 本节目录 一 web框架的本质及自定义web框架 二 模板渲染JinJa2 三 MVC和MTV框架 四 Django的下载安装 五 基于Django实现的一个简单 ...
- Django框架01 / http协议、web框架本质
Django框架01 / http协议.web框架本质 目录 Django框架01 / http协议.web框架本质 1.http协议 1.1 http协议简介 1.2 什么是http协议 1.3 H ...
- Django - Django框架 简单介绍
Django框架 简单介绍 本文地址: http://blog.csdn.net/caroline_wendy/article/details/29172271 1. 介绍 Django是一个开放源码 ...
随机推荐
- Stream的去重排序
1.List<Integer>排序 List<Integer> list = new ArrayList<>();list.add(50);list.add(25) ...
- [Array]217.Contains Duplicate
Given an array of integers, find if the array contains any duplicates. Your function should return t ...
- linux基础指令参数
eth0,eth1,eth2--代表网卡一,网卡二,网卡三-- lo代表127.0.0.1,即localhost 参考: Linux命令:ifconfig 功能说明:显示或设置网络设备 语 法:ifc ...
- Neo4j系列-简介及应用场景
1.什么是Neo4j? Neo4j是一个高性能的NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储 ...
- LINNX查看当前登录的用户
W w命令主要是查看当前登录的用户,这个命令相对来说比较简单.我们来看一下截图. 在上面这个截图里面呢,第一列user,代表登录的用户,第二列,tty代表用户登录的终端号,因为在linux中并不是只有 ...
- 计蒜客 Zoning Houses(线段树区间最大次大)
Given a registry of all houses in your state or province, you would like to know the minimum size of ...
- apache添加虚拟主机(windows下)
1.打开Apache的目录下的 D:\Web\Apache\conf\httpd.conf 允许虚拟,启动虚拟配置文件 2.配置虚拟主机 打开 D:\Web\Apache\conf\extra\ht ...
- 【BZOJ2809】【APIO2012】dispatching
左偏树. 每个子节点维护大根堆,遍历一个儿子就往自己合并,合并发现钱不够了就删除队顶. //Achen #include<algorithm> #include<iostream&g ...
- Thinkphp js、css压缩类minify
说明:Minify 是用PHP5开发的应用,通过遵循一些Yahoo的优化规则来提高网站的性能.它会合并多个CSS或者JavaScript文件,移除一些不必要的空格和注释,进行gzip压缩,并且会设置浏 ...
- c中函数指针和回调函数
函数指针: 指向函数的指针.(定义的函数会分配一块内存,同变量一样存在首地址)示例如下: int Func(int x); /*声明一个函数*/ int (*p) (int x); /*定义一个函数指 ...