三、Python复习教程(重点)- 前端框架实战
目录导航:
文章目录
- 目录导航:
- 五、Django商城项目开发(上)
- 1. 项目需求分析
- ①. 项目开发流程
- (1). 软件开发过程的划分
- (2). 软件开发流程
- (3). 软件开发过程域遵循的标准文档
- (4). 项目需求分析
- (5). 项目系统设计
- (6). 编码测试
- (7). 试运行、实施和验收
- (8). 服务与维护
- ②. 商城项目需求分析
- (1). 确立项目:商城项目(B2C)单商家模式
- (2). 项目功能介绍
- ① 网站前台
- ② 网站后台管理
- (3). 绘制项目的功能模块 和操作流程图
- ① 商城项目功能模块图(如下图)
- ② 商城前台用户操作流程图(如下图)
- ③ 商城后台管理员操作流程图(如下图)
- (4). 具体功能描述
- (5). 项目运行环境要求
- (6). 项目具体完成时间和报价
- (7). 验收标准
- 2. 项目的数据库设计
- (1). 结构设计:
- * 找实体:
- * 找属性:
- * 找关系:
- * 绘制E-R图:
- (2). 逻辑结构设计
- * 确定关系模式:
- * 消除冗余:
- (3). 物理结果设计
- * 设计数据表结构:
- * 通过数据表结构来创建数据表:
- (4). 安全保密设计
- 3. 项目架构的程序设计
- (1). 项目使用技术
- (2). 项目的目录结构
- (3). 项目模块结构
- * 网站后台应用的模块操作说明
- * 网站前台应用的模块操作说明
- (4). 程序结构
- (5). 项目中的编码规范
- 4. 基于Django框架的项目搭建
- (1). 创建数据库 `shopdb`
- (2). 创建项目 `myobject` 框架和应用 `myamdin`、`web`和`common`。
- (3). 项目框架配置
- (4). 项目urls路由信息配置
- (5). 编写后台视图测试
- (6). 摆放后台首页面:
- 5. 项目实战后台之会员管理
- (1). 用户信息数据表:users
- (2). 定义模型Model类
- (3). 项目urls路由信息配置
- (4). 编辑视图文件
- (5). 编写模板文件
- (6). 运行测试
- 6. 项目实战后台之管理员登陆与退出
- ①. 添加中间件
- (1). 在common公共应用中创建中间件
- (2). 将自定义的中间件注册到项目中
- (3). 配置路由、模板并测试中间件
- (4). 启动服务测试,网站后台就进不去了,统一调跳转登录页面中
- ②. 登录与退出
- (1). 配置路由(已配置过可省略)
- (2). 编写视图文件
- (3). 创建模板
- (4). 启动服务测试,即可测试网站后台是否可以使用。注意只有管理员才开登录。
- ③. 添加验证码
- (1). 配置路由
- (2). 编写视图文件
- (3). 在中间件设置放行
- (4). 在登录模板中使用验证码
- (5). 验证码校验
- (6). 启动服务测试,即可测试网站后台是否可以使用。注意只有管理员才开登录。
- 7. 项目实战后台之商品类别信息管理
- 后台商品类别信息管理
- (1). 商品类别信息数据表:`type`
- (2). 定义模型Model类
- (3). 项目urls路由信息配置
- (4). 编辑视图文件
- (5). 编写模板文件
- (6). 运行测试
- 8. 项目实战后台之商品信息管理
- (1). 商品信息数据表:goods
- (2). 定义模型Model类
- (3). 项目urls路由信息配置
- (4). 编辑视图文件
- (5). 编写模板文件
- (6). 运行测试
- ①. 搜索分页浏览商品信息(附加)
- 8.1 搜索&分页浏览商品信息(附加)
- (1). 编辑项目urls路由信息配置
- (2). 编辑视图文件
- (3). 编写模板文件
- (4). 运行测试
- 六、Django商城项目开发(下)
- 商城项目前台结构:
- 项目前台的URL路由配置:
- 9. 项目实战前台搭建
- (1). 开发前的准备工作:
- (2). 目urls路由信息配置:
- (3). 编辑视图文件
- (4). 编写模板文件
- 10. 项目实战前台之会员注册与登陆
- (1). 项目urls路由信息配置
- (2). 编辑视图文件
- (3). 编写模板文件
- 11. 项目实战前台之商品展示
- (1). 项目urls路由信息配置
- (2). 编辑视图文件
- (3). 编写模板文件
- 12. 项目实战前台之购物车实战
- (1). 开发前的准备工作:
- (2). 项目urls路由信息配置
- (3). 编辑视图文件
- (4). 编写模板文件
- 13. 项目实战前台之下单操作
- (1). 开发前的准备工作:
- (2). 项目urls路由信息配置
- (3). 编辑视图文件
- (4). 编写模板文件
- 14. 项目实战前台之个人中心
- (1). 个人中心简介:
- (2). 项目urls路由信息配置
- (3). 编辑视图文件
- (4). 编写模板文件
- 15. 项目实战后台之订单处理
- (1). 后台订单处理说明:
- (2). 项目urls路由信息配置
- (3). 编辑视图文件
- (4). 编写模板文件
- 16. 项目实战总结
- (1). 项目中还有那些需要开发
- (2). 项目中的优化:
- [Published with GitBook](https://www.gitbook.com/)
五、Django商城项目开发(上)
1. 项目需求分析
①. 项目开发流程
(1). 软件开发过程的划分
本规定对一个完整的开发过程按“软件过程改进方法和规范”把
产品生命周期
划分为 6 个阶段:
- 产品概念阶段(记为 PH0)
- 产品定义阶段(记为 PH1)
- 产品开发阶段(记为 PH2)
- 产品测试阶段(记为 PH3)
- 用户验收阶段(记为 PH4)
- 产品维护阶段(记为 PH5)
软件项目的过程有三大类:
项目管理过程
、项目研发过程
和机构支持过程
。而这三类过程可以细分为
19
个主要过程域,分布在PH0
到PH5
的各个阶段。项目管理过程包
6
个过程域,分为:立项管理
、结项管理
、项目规划
、项目监控
、风险管理
、需求管理
。项目研发过程包
8
个过程域,分为:需求开发
、技术预研
、系统设计
、实现与测试
、系统测试
、Beta测试
、客户验收
、技术评审
。机构支撑过程包
5
个过程域,分为:配置管理
、质量保证
、培训管理
、外包与采购管理
、服务与维护
。建议用户(企业)根据自身情况(如发 展战略、研发实力等)适当地修改使用
(2). 软件开发流程
(3). 软件开发过程域遵循的标准文档
(4). 项目需求分析
- 需求调研的主要收集方式有 以下方面:
- 与用户交谈,向用户提问题。
- 参观用户的工作流程,观察用户的操作。
- 向用户群体发调查问卷。
- 与同行、专家交谈,听取他们的意见。
- 分析已经存在的同类产品,提取需求。
- 从行业标准、规则中提取需求。
- 从 Internet 上搜查相关资料。
- 输出:新产品概念书、调研报告、《需求说明书》、《项目建议书》、计划书和计划表:
(5). 项目系统设计
- 输入部分包括:《项目建议书》、《需求说明书》、软件设计过程中的标准与规范、软、硬件开发环境。
- 输出:《系统设计说明》、用户界面原型、《数据库设计说明》、《功能模块设计说明》、《使用说明书初稿》。
(6). 编码测试
- 软件实现是指通过编程、调试、优化、内部测试和代码审查等活动,开发出符合用户需求、质量合格的产品。
- 软件的优化指的是提高软件的运行速度、提高对内存资源的利用率、加强用户界面的 友好化等方面。
(7). 试运行、实施和验收
(8). 服务与维护
②. 商城项目需求分析
(1). 确立项目:商城项目(B2C)单商家模式
(2). 项目功能介绍
本商城项目分为网站前台和网站后台管理两部分:
① 网站前台
- 网站首页商品展示:推荐商品,分类展示部分商品,热卖商品,新商品等展示
- 商品列表页:分页展示某类别或指定条件(搜索)的部分商品列表信息。
- 商品详情页:通过商品ID号来展示指定商品详情信息。
- 购物车管理:添加、查看、删除、清空等自己的购物信息。
- 会员模块:注册,登录、退出以及进入会员中心
- 会员中心:个人信息管理、我的订单信息
- 订单处理
- 其他扩展:商品评论、商品多图;会员收货地址管理,商品收藏;首页轮播图;站内公告、新闻;友情链接;
② 网站后台管理
- 后台操作:登录、退出
- 会员信息管理:查看、修改会员状态、重置密码
- 商品类别信息管理:添加、删除、修改、查看商品类别信息
- 商品信息管理:添加、删除、修改、查看
- 订单信息管理:查看订单、订单详情、处理订单
- 其他扩展:商品评论管理、商品多图管理;会员收货地址管理,商品收藏;首页轮播图管理;站内公告、新闻管理;友情链接管理
(3). 绘制项目的功能模块 和操作流程图
① 商城项目功能模块图(如下图)
② 商城前台用户操作流程图(如下图)
③ 商城后台管理员操作流程图(如下图)
(4). 具体功能描述
- 针对与商场网站的每个功能块进行详细描述,主要包含以下几个方面:
- 功能名称、编号、设计者、时间
- 功能框图及说明
- 操作权限
- 需要哪些输入
- 具体执行过程内容
- 输出结果
- 业务数据流:DFD图
- 功能效果预览
(5). 项目运行环境要求
- 服务器环境要求:服务器数量,类型和用途;以及每台服务器的配置要求
- 软件环境:Python、MySQL、框架Django的版本要求
- 各种接口标准要求(支付、微信、短信等接口)
(6). 项目具体完成时间和报价
- 项目开发进度计划表,时间周期的安排
- 项目总体报价,以及每个模块的报价、付款方式
- 项目违约处理,后期功能附加条款处理等事项说明
(7). 验收标准
- 项目模块功能的完成情况
- 项目的执行性能(如:网站的响应时间值:正常<=3秒)
2. 项目的数据库设计
- 参考《项目建议书》、《需求说明书》、用户界面原型、以及各种标准和规范对数据库设计如下:
(1). 结构设计:
* 找实体:
- 实体是实体-关系模型的基本对象,是现实世界中各种事物的抽象。
- 凡是可以相互区 开并可以被识 的事、物、概念等对象均可认为是实体。
- 基本的实体列表如下:
- 会员
- 类别
- 商品
- 订单
- 订单详情
- 收货地址
- 商品评论
- 商品图片
- 友情链接
- 站内公告
- …
* 找属性:
- 每个实体都有一组特征或性质,称为实体的属性。
- 实体的属性值是数据库中存储的主要 数据,一个属性实际上相当于表中的一个列。
- 如会员实体:账号、密码、真实姓名、性别、地址、邮编、电话、邮箱、状态、注册时间
- 商品实体:商品名称、厂家、简介、单价、图片、状态、库存量、购买量、点击次数、添加时间
- … …
* 找关系:
- 每个商品属于一个类别,每个类别下可以有多个商品,那么类别与商品的关系为:1:n(1对多关系)
- 每个订单属于一个会员,每个会员下可以有多个订单,那么会员与订单的关系为:1:n(1对多关系)
- 每个订单详情属于一个订单,每个订单下可以有多条购买商品,那么关系为:1:n(1对多关系)
* 绘制E-R图:
(2). 逻辑结构设计
- 在上面实体之间的关系基础上,将实体、属性和实体之间的联系转换为关系模式。
* 确定关系模式:
根据转换算法,E-R 图中有 5 个实体类型,可以转换成 4 个关系模式:
1).
会员
(id号、账号、密码、真实姓名、性别、收货地址、邮政编码、电话、Email、状态、注册时间)2).
商品类别
(类别id号,类别名称,父类别id,类别路径)3).
商品
(商品id、类别id
、商品名称、生产厂家、详情描述、单价、图片名称、库存量、购买数量、点击次数、状态、添加时间)4).
订单
(订单id号、会员id号
、联系人、收货地址、邮政编码、联系电话、购买时间、总金额、状态)5).
订单详情
(id号、订单id号
、商品id号
,商品名称、单价、购买量)
* 消除冗余:
- 冗余数据和冗余联系容易破坏数据库的完整性,给数据库的维护增加困难,应当予以消除。
- 本系统的冗余数据和冗余关系已经在概念结构设计中处理过了,这里不再进行过多的叙述。
(3). 物理结果设计
- 数据库设计的最后阶段是确定数据库在物理设备上的存储结构和存取方法,即物理数据模型。
- 物理数据模型的设计其实也是在设计表结构。
- 一般地,实体对应于表,实体的属性对应于表的列(字段),实体之间的关系成为表的约束。
* 设计数据表结构:
* 通过数据表结构来创建数据表:
-- 会员信息表(后台管理员信息也在此标准,通过状态区分)
CREATE TABLE `users`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`username` varchar(32) NOT NULL,`name` varchar(16) DEFAULT NULL,`password` char(32) NOT NULL,`sex` tinyint(1) unsigned NOT NULL DEFAULT '1',`address` varchar(255) DEFAULT NULL,`code` char(6) DEFAULT NULL,`phone` varchar(16) DEFAULT NULL,`email` varchar(50) DEFAULT NULL,`state` tinyint(1) unsigned NOT NULL DEFAULT '1',`addtime` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`)
)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 商品类别表
CREATE TABLE `type`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,`pid` int(11) unsigned DEFAULT '0',`path` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 商品信息表
CREATE TABLE `goods`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`typeid` int(11) unsigned NOT NULL,`goods` varchar(32) NOT NULL,`company` varchar(50) DEFAULT NULL,`content` text,`price` double(6,2) unsigned NOT NULL,`picname` varchar(255) DEFAULT NULL,`store` int(11) unsigned NOT NULL DEFAULT '0', `num` int(11) unsigned NOT NULL DEFAULT '0',`clicknum` int(11) unsigned NOT NULL DEFAULT '0',`state` tinyint(1) unsigned NOT NULL DEFAULT '1',`addtime` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `typeid` (`typeid`)
)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 订单信息表
CREATE TABLE `orders`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`uid` int(11) unsigned DEFAULT NULL,`linkman` varchar(32) DEFAULT NULL,`address` varchar(255) DEFAULT NULL,`code` char(6) DEFAULT NULL,`phone` varchar(16) DEFAULT NULL,`addtime` datetime DEFAULT NULL,`total` double(8,2) unsigned DEFAULT NULL,`state` tinyint(1) unsigned DEFAULT NULL,PRIMARY KEY (`id`)
)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 订单信息详情表
CREATE TABLE `detail`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`orderid` int(11) unsigned DEFAULT NULL,`goodsid` int(11) unsigned DEFAULT NULL,`name` varchar(32) DEFAULT NULL,`price` double(6,2) DEFAULT NULL,`num` int(11) unsigned DEFAULT NULL,PRIMARY KEY (`id`)
)ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;-- 在user上表中添加一条后台管理员账户数据
insert into users values(null,'admin','管理员',md5('admin'),1,'北京市朝阳区大山子007号','100086','13566686868','122794105@qq.com',0,now())
(4). 安全保密设计
- 本数据库系统采用安全的用户名加口令方式登录。用户名的权限限制为只能进行基本的 增删改查数据功能。
- 数据库应用对数据一般都具有一定的限制,这种限制称为完整性。
- 关系数据库系统应该保证输入的值符合其规定的数据类型,并保证值在系统支持的范围内。
- 关系数据库系统都支持 3 种完整性:
域约束
、实体完整性约束
和关联完整性约束
。
3. 项目架构的程序设计
(1). 项目使用技术
- 基于Python语言,版本:>=3.5及以上。
- 使用Django框架,版本:1.11.11的LTS版本。
- MySQL数据库
- 连接数据库:pymysql=0.8.0
- 图像处理: Pillow=5.0.0
- Web前端技术:HTML、CSS、JavaScript和Jquery等
(2). 项目的目录结构
本次项目共计四个应用:
myadmin
、
web
、
common
和
ueditor
/myobject/├── manage.py├── myobject│ ├── __init__.py│ ├── settings.py│ ├── urls.py│ └── wsgi.py├── common 公共应用│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── shopmiddleware.py 自定义的中间件│ ├── migrations│ ├── models.py 网站前后台的共用Model类│ ├── tests.py│ └── views.py├── myadmin 网站后台应用│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ ├── views│ │ ├── index.py 后台主视图│ │ ├── users.py 会员管理视图│ │ ├── type.py 商品类别管理视图│ │ ├── goods.py 商品管理视图│ │ └── orders.py 订单管理视图│ ├── models.py│ ├── tests.py│ └── urls.py│├── web 网站前台应用│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ ├── views│ │ ├── index.py web前台主视图│ │ ├── users.py 会员操作视图│ │ ├── cart.py 购物车管理视图│ │ └── orders.py 订单处理视图│ ├── models.py│ ├── tests.py│ └── urls.py│├── ueditor 百度编辑器(富文本编辑器)│ ├── __init__.py│ ├── UE│ ├── controller.py│ ├── msyhdb.ttf│ ├── ueconfig.json│ └── urls.py│├── templates 模板目录│ ├── myadmin 后台模板总目录│ │ ├── users/ 后台会员管理│ │ │ ├── index.html │ │ │ ├── add.html │ │ │ ├── edit.html │ │ │ ├── repass.html │ │ ├── type/ 后台类别管理模板│ │ │ ├── index.html │ │ │ ├── add.html │ │ │ ├── edit.html │ │ ├── goods/ 商品信息管理模板│ │ │ ├── index.html │ │ │ ├── add.html │ │ │ ├── edit.html │ │ ├── orders/ 订单信息管理模板│ │ │ ├── index.html │ │ │ ├── edit.html │ │ ├── index.html│ │ ├── login.html│ │ ├── base.html│ │ ├── info.html│ ││ ├── web 前台模板目录│ │ ├── base.html│ │ ├── index.html│ │ ├── list.html│ │ ├── detail.html│ │ ├── login.html│ │ ├── signup.html│ │ └── ......│├── static 静态资源目录│ ├── myadmin 后台静态资源 │ │ ├──....│ │ ├──....│ ││ ││ ├── web 网站前台静态资源│ │ ├──....│ │ ├──....
(3). 项目模块结构
* 网站后台应用的模块操作说明
- 网站后台模板采用github上提供的一个简洁界面,网址:https://github.com/alecfan/mstp_17_akira
模块 | 操作 | 权限 |
---|---|---|
登录&退出管理 | 获取登录界面、处理登录、退出、验证码 | 无 |
后台首页页 | 后台首页 | 网站编辑权限 |
后台会员信息管理 | 浏览(搜索&分页)、详情、更改状态、重置密码 | 网站编辑权限 |
商品类别管理 | 浏览、获取添加界面、执行添加、获取编辑界面、执行修改、删除 | 网站编辑权限 |
商品信息管理 | 浏览(搜索&分页)、获取添加界面、执行添加、获取编辑界面、执行修改、删除 | 网站编辑权限 |
订单信息管理 | 浏览(搜索&分页)、查看订单详情、处理订单、删除 | 网站编辑权限 |
* 网站前台应用的模块操作说明
模块 | 操作 | 权限 |
---|---|---|
商品展示 | 商品首页展示、列表页(搜索分页)、商品详情页 | 无 |
购物车管理 | 添加商品、查看购物车,修改、删除、清空 | 无 |
前台会员管理 | 注册界面、执行注册,登录界面,执行登录,验证码、退出 | 无 |
订单处理 | 订单处理界面,确认订单界面、执行订单处理 | 会员权限 |
会员中心管理 | 个人信息界面、执行个人信息修改,查看订单,订单详情、处理订单 | 会员权限 |
(4). 程序结构
建议统一URL访问格式:
http://主机名:端口/应用名/视图名/函数名其中:index省略不写,web前台应用名省略不写。
视图中的函数命名格式:
- index() ---- 浏览信息
- add() ---- 加载添加界面
- insert() ---- 执行添加
- delete() ---- 执行删除(路由中使用del)
- edit() ---- 加载编辑界面
- update() ---- 执行信息编辑
(5). 项目中的编码规范
遵循良好的编码风格,可以有效的提高代码的可读性,降低出错几率和维护难度。
在团队开发中,使用(尽量)统一的编码风格,还可以降低沟通成本。
网上有很多版本的编码规范介绍,基本上都是遵循 PEP8 的规范:
具体详见:https://www.python.org/dev/peps/pep-0008/
如下参考格式:
缩进
* 不要使用 tab 缩进
* 使用任何编辑器写 Python,请把一个 tab 展开为 4 个空格
* 绝对不要混用 tab 和空格,否则容易出现 IndentationError空格
* 在 list, dict, tuple, set, 参数列表的 , 后面加一个空格
* 在 dict 的 : 后面加一个空格
* 在注释符号 # 后面加一个空格,但是 #!/usr/bin/python 的 # 后不能有空格
* 操作符两端加一个空格,如 +, -, *, /, |, &, =
* 接上一条,在参数列表里的 = 两端不需要空格
* 括号((), {}, [])内的两端不需要空格空行
* function 和 class 顶上两个空行
* class 的 method 之间一个空行
* 函数内逻辑无关的段落之间空一行,不要过度使用空行
* 不要把多个语句写在一行,然后用 ; 隔开
* if/for/while 语句中,即使执行语句只有一句,也要另起一行换行
* 每一行代码控制在 80 字符以内
* 使用 \ 或 () 控制换行.命名
* 使用有意义的,英文单词或词组,绝对不要使用汉语拼音
* package/module 名中不要出现 -import
* 所有 import 尽量放在文件开头,在 docstring 下面,其他变量定义的上面
* 不要使用 from foo imort *
* import 需要分组,每组之间一个空行,每个分组内的顺序尽量采用字典序,分组顺序是:* 标准库* 第三方库* 本项目的 package 和 module注释
* 文档字符串 docstring, 是 package, module, class, method, function 级别的注释,可以通过 * __doc__ 成员访问到,注释内容在一对 """ 符号之间
* function, method 的文档字符串应当描述其功能、输入参数、返回值,如果有复杂的算法和实现,也需要写清楚
不要写错误的注释,不要无谓的注释异常
* 不要轻易使用 try/except
* except 后面需要指定捕捉的异常,裸露的 except 会捕捉所有异常,意味着会隐藏潜在的问题
* 可以有多个 except 语句,捕捉多种异常,分别做异常处理
* 使用 finally 子句来处理一些收尾操作
* try/except 里的内容不要太多,只在可能抛出异常的地方使用,
4. 基于Django框架的项目搭建
(1). 创建数据库 shopdb
- 进入MySQL数据库中,创建一个数据库名为:shopdb
- 将上节《项目的数据库设计》中准备好的shopdb.sql脚本导入到
shopdb
数据库中
(2). 创建项目 myobject
框架和应用 myamdin
、web
和common
。
# 创建项目框架 `myobject`$ django-admin startproject myobject$ cd myobject# 在项目中创建一个myadmin应用(项目的后台管理)$ python manage.py startapp myadmin# 在项目中再创建一个web应用(项目前台)$ python manage.py startapp web# 在项目中再创建一个common应用(项目的前台和后台的公告应用)$ python manage.py startapp common# 创建模板目录$ mkdir templates$ mkdir templates/myadmin$ mkdir templates/web# 创建静态资源目录$ mkdir static$ mkdir static/myadmin$ mkdir static/web# 创建前后台应用模板目录,并在里面各创建一个`__init__.py`和`index.py`的空文件$ mkdir myadmin/views$ touch myadmin/views/__init__.py$ touch myadmin/views/index.py$ mkdir web/views$ touch web/views/__init__.py$ touch web/views/index.py# 删除前后台应用的默认模板文件# rm -rf myadmin/views.py# rm -rf web/views.py# 拷贝路由文件到应用目录中$ cp myobject/urls.py myadmin/urls.py$ cp myobject/urls.py web/urls.py# 退出项目目录$ cd ..#查看项目目录结构$ tree myobjectmyobject/├── manage.py├── myobject│ ├── __init__.py│ ├── settings.py│ ├── urls.py│ └── wsgi.py├── myadmin│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ │ └── __init__.py│ ├── views│ │ ├── __init__.py│ │ └── index.py│ ├── models.py│ ├── tests.py│ └── urls.py├── web│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ │ ├── __init__.py│ ├── views│ │ ├── __init__.py│ │ └── index.py│ ├── models.py│ ├── tests.py│ └── urls.py├── common│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ │ ├── __init__.py│ ├── models.py│ ├── tests.py│ └── views.py├── static│ ├── myadmin/│ └── web/└── templates├── myadmin/└── web/
(3). 项目框架配置
- 3.1 编辑
myobject/myobject/__init__.py
文件,添加Pymysql的数据库操作支持
import pymysql
pymysql.install_as_MySQLdb()
注意:此配置需要安装pymysql软件包, 如:$ pip install pymysql
- 3.2 编辑myobject/myobject/settings.py文件:
# myobject/myobject/settings.py 项目配置文件# 1. 配置允许访问的主机名信息
ALLOWED_HOSTS = ['*']
或
ALLOWED_HOSTS = ['localhost','127.0.0.1','192.168.2.240']...# 2. 将myadmin和web的应用添加到项目框架结构中
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','myadmin','web','common',
]...# 3. 配置模板目录 os.path.join(BASE_DIR,'templates')
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [os.path.join(BASE_DIR,'templates')],'APP_DIRS': True,'OPTIONS': {'context_processors': ['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},
]...# 4. 配置项目的数据库连接信息:
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'shopdb','USER': 'root','PASSWORD': '','HOST': 'localhost','PORT': '3306',}
}...# 5. 设置时区和语言
LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'...# 6. 配置网站的静态资源目录
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
]
(4). 项目urls路由信息配置
- 4.1 打开根路由文件:myobject/myobject/urls.py路由文件,编写路由配置信息
# myobject/myobject/urls.pyfrom django.conf.urls import url,include
#from django.contrib import adminurlpatterns = [
# url(r'^admin/', admin.site.urls),url(r'^myadmin/', include('myadmin.urls')), #网站后台路由url(r'^', include('web.urls')), #网站前台路由
]
- 4.2 打开项目后台管理路由文件:myobject/myadmin/urls.py路由文件,编写路由配置信息
# myobject/myadmin/urls.pyfrom django.conf.urls import urlfrom myadmin.views import indexurlpatterns = [# 后台首页url(r'^$', index.index, name="myadmin_index"),]
- 4.3 打开项目前台路由文件:myobject/web/urls.py路由文件,编写路由配置信息
# myobject/web/urls.pyfrom django.conf.urls import urlfrom web.views import indexurlpatterns = [# url(r'^$', index.index, name="index"),
]
(5). 编写后台视图测试
- 5.1 编辑后台视图文件
# myobject/myadmin/views/index.py
from django.shortcuts import render
from django.http import HttpResponse#后台首页
def index(request):return HttpResponse('欢迎进入商城网站后台!')
# myobject/web/views/index.py
from django.shortcuts import render
from django.http import HttpResponse#前台首页
def index(request):return HttpResponse('欢迎进入商城网站前台首页!')
- 5.2 运行测试
- 在项目根目录下启动服务,并使用浏览器访问测试:http://localhost:8000/myadmin
[root@localhost myobject]# pwd
/python/myobject
[root@localhost myobject]# ls
manage.py myadmin myobject web static templates
[root@localhost myobject]# python3 manage.py runserver 0:8000
Performing system checks...System check identified no issues (0 silenced).April 06, 2018 - 14:29:36
Django version 1.11, using settings 'myobject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
^C[root@localhost myobject]#
(6). 摆放后台首页面:
6.1. 使用事先准备好的后台模板:
从github上下载一个后台简洁模板:https://github.com/alecfan/mstp_17_akira
将后台模板目录中的资源目录:
css
、js
、img
复制到项目的后台静态资源目录static/myadmin/
中在
templates/myadmin/
目录中创建一个基类父模板文件base.html
在
templates/myadmin/
目录中创建一个首页模板文件index.html
在
templates/myadmin/
目录中创建一个信息提示模板文件info.html
修改
myobject/myadmin/views/index.py
视图文件中index函数中代码:
def index(request):'''管理后台首页'''return render(request,"myadmin/index.html")
6.2. 编辑父类模板:/templates/myadmin/base.html
{% load static from staticfiles %}
<!DOCTYPE html>
<html lang="cn"><head><meta charset="utf-8"><title>网站后台管理</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><link href="{% static 'myadmin/css/bootstrap.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/bootstrap-responsive.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/site.css' %}" rel="stylesheet"><!--[if lt IE 9]><script src="{% static 'myadmin/js/html5.js' %}"></script><![endif]--></head><body><div class="container"><!-- 页头开始 --><div class="navbar"><div class="navbar-inner"><div class="container"><a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> <a class="brand" href="#">网站后台管理</a><div class="nav-collapse"><ul class="nav"><li class="active"><a href="index.html">首页</a></li><li><a href="settings.htm">在线设置</a></li><li><a href="help.htm">帮助</a></li><li class="dropdown"><a href="help.htm" class="dropdown-toggle" data-toggle="dropdown">更多 <b class="caret"></b></a><ul class="dropdown-menu"><li><a href="help.htm">Introduction Tour</a></li><li><a href="help.htm">Project Organisation</a></li><li><a href="help.htm">Task Assignment</a></li><li><a href="help.htm">Access Permissions</a></li><li class="divider"></li><li class="nav-header">Files</li><li><a href="help.htm">How to upload multiple files</a></li><li><a href="help.htm">Using file version</a></li></ul></li></ul><form class="navbar-search pull-left" action=""><input type="text" class="search-query span2" placeholder="Search" /></form><ul class="nav pull-right"><li><a href="profile.htm">@管理员</a></li><li><a href="login.htm">退出</a></li></ul></div></div></div></div><!-- 页头结束--><div class="row"><div class="span3"><!-- 侧边导航开始 --><div class="well" style="padding: 8px 0;"><ul class="nav nav-list"><li class="nav-header">导航栏</li><li class="active"><a href="index.htm"><i class="icon-white icon-home"></i> 首页</a></li><li class="nav-header">会员管理</li><li><a href="#"><i class="icon-folder-open"></i> 浏览会员</a></li><li><a href="#"><i class="icon-check"></i> 添加会员</a></li><li class="nav-header">商品类别管理</li><li><a href="messages.htm"><i class="icon-envelope"></i> 浏览商品类别</a></li><li><a href="files.htm"><i class="icon-file"></i> 添加商品类别</a></li><li class="nav-header">商品信息管理</li><li><a href="activity.htm"><i class="icon-list-alt"></i> 浏览商品信息</a></li><li><a href="activity.htm"><i class="icon-list-alt"></i> 添加商品信息</a></li><li class="divider"></li><li><a href="help.htm"><i class="icon-info-sign"></i> Help</a></li><li class="nav-header">Bonus Templates</li><li><a href="gallery.htm"><i class="icon-picture"></i> Gallery</a></li><li><a href="blank.htm"><i class="icon-stop"></i> Blank Slate</a></li></ul></div><!-- 侧边导航结束 --></div><div class="span9"><!-- 主体开始 -->{% block mainbody %}{% endblock %}<!-- 主体结束 --></div></div></div><script src="{% static 'myadmin/js/jquery.min.js' %}"></script><script src="{% static 'myadmin/js/bootstrap.min.js' %}"></script><script src="{% static 'myadmin/js/site.js' %}"></script></body>
</html>
- 6.3. 编辑后台首页模板:/templates/myadmin/index.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h2>商城网站后台管理首页</h2><div class="hero-unit"><h3>Welcome!</h3><p>To get the most out of Akira start with our 3 minute tour.</p><p><a href="help.htm" class="btn btn-primary btn-large">Start Tour</a> <a class="btn btn-large">No Thanks</a></p></div><div class="well summary"><ul><li><a href="#"><span class="count">3</span> Projects</a></li><li><a href="#"><span class="count">27</span> Tasks</a></li><li><a href="#"><span class="count">7</span> Messages</a></li><li class="last"><a href="#"><span class="count">5</span> Files</a></li></ul></div>
{% endblock %}
- 6.4. 后台公共提示信息模板:/templates/myadmin/info.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h2>操作信息提示</h2><h4>{{ info }}</h4>
{% endblock %}
5. 项目实战后台之会员管理
- 本页面完成项目后台管理的用户模块操作
(1). 用户信息数据表:users
- 在数据库
shopdb
中创建users表,若此表已存在请跳过
CREATE TABLE `users`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`username` varchar(32) NOT NULL,`name` varchar(16) DEFAULT NULL,`password` char(32) NOT NULL,`sex` tinyint(1) unsigned NOT NULL DEFAULT '1',`address` varchar(255) DEFAULT NULL,`code` char(6) DEFAULT NULL,`phone` varchar(16) DEFAULT NULL,`email` varchar(50) DEFAULT NULL,`state` tinyint(1) unsigned NOT NULL DEFAULT '1',`addtime` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`)
)ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
(2). 定义模型Model类
- 进入
common
应用目录中编辑:myobject/common/models.py
模型文件
from django.db import models
from datetime import datetime#用户信息模型
class Users(models.Model):username = models.CharField(max_length=32)name = models.CharField(max_length=16)password = models.CharField(max_length=32)sex = models.IntegerField(default=1)address = models.CharField(max_length=255)code = models.CharField(max_length=6)phone = models.CharField(max_length=16)email = models.CharField(max_length=50)state = models.IntegerField(default=1)addtime = models.DateTimeField(default=datetime.now)def toDict(self):return {'id':self.id,'username':self.username,'name':self.name,'password':self.password,'address':self.address,'phone':self.phone,'email':self.email,'state':self.state,'addtime':self.addtime}class Meta:db_table = "users" # 更改表名
(3). 项目urls路由信息配置
- 打开根路由文件:myobject/myadmin/urls.py路由文件,编辑路由配置信息
from django.conf.urls import urlfrom myadmin.views import index,usersurlpatterns = [# 后台首页url(r'^$', index.index, name="myadmin_index"),# 后台用户管理url(r'^users$', users.index, name="myadmin_users_index"),url(r'^users/add$', users.add, name="myadmin_users_add"),url(r'^users/insert$', users.insert, name="myadmin_users_insert"),url(r'^users/del/(?P<uid>[0-9]+)$', users.delete, name="myadmin_users_del"),url(r'^users/edit/(?P<uid>[0-9]+)$', users.edit, name="myadmin_users_edit"),url(r'^users/update/(?P<uid>[0-9]+)$', users.update, name="myadmin_users_update"),
]
(4). 编辑视图文件
- 创建:myobject/myadmin/views/users.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponsefrom common.models import Users
from datetime import datetime# 浏览会员
def index(request):# 执行数据查询,并放置到模板中list = Users.objects.all()context = {"userslist":list}#return HttpResponse(list)return render(request,'myadmin/users/index.html',context)# 会员信息添加表单
def add(request):return render(request,'myadmin/users/add.html')#执行会员信息添加
def insert(request):try:ob = Users()ob.username = request.POST['username']ob.name = request.POST['name']#获取密码并md5import hashlibm = hashlib.md5() m.update(bytes(request.POST['password'],encoding="utf8"))ob.password = m.hexdigest()ob.sex = request.POST['sex']ob.address = request.POST['address']ob.code = request.POST['code']ob.phone = request.POST['phone']ob.email = request.POST['email']ob.state = 1ob.addtime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")ob.save()context = {'info':'添加成功!'}except Exception as err:print(err)context = {'info':'添加失败!'}return render(request,"myadmin/info.html",context)# 执行会员信息删除
def delete(request,uid):try:ob = Users.objects.get(id=uid)ob.delete()context = {'info':'删除成功!'}except:context = {'info':'删除失败!'}return render(request,"myadmin/info.html",context)# 打开会员信息编辑表单
def edit(request,uid):try:ob = Users.objects.get(id=uid)context = {'user':ob}return render(request,"myadmin/users/edit.html",context)except Exception as err:print(err)context = {'info':'没有找到要修改的信息!'}return render(request,"myadmin/info.html",context)# 执行会员信息编辑
def update(request,uid):try:ob = Users.objects.get(id=uid)ob.name = request.POST['name']ob.sex = request.POST['sex']ob.address = request.POST['address']ob.code = request.POST['code']ob.phone = request.POST['phone']ob.email = request.POST['email']ob.state = request.POST['state']ob.save()context = {'info':'修改成功!'}except Exception as err:print(err)context = {'info':'修改失败!'}return render(request,"myadmin/info.html",context)
(5). 编写模板文件
- 5.1. 后台用户信息浏览模板:/templates/myadmin/users/index.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h4>会员信息管理</h4><table class="table table-bordered table-striped"><thead><tr><th>账号</th><th>真实姓名</th><th>性别</th><th>邮箱</th><th>注册时间</th><th>状态</th><th>操作</th></tr></thead><tbody>{% for vo in userslist %}<tr><td>{{ vo.username }}</td><td>{{ vo.name }}</td><td>{% if vo.sex == 1 %}男{% else %}女{% endif %}</td><td>{{ vo.email }}</td><td>{{ vo.addtime|date:'Y-m-d H:i:s' }}</td><td>{{ vo.state }}</td><td><a href="{% url 'myadmin_users_del' vo.id %}" class="view-link">删除</a><a href="{% url 'myadmin_users_edit' vo.id %}" class="view-link">编辑</a></td></tr>{% endfor %}</tbody></table> <div class="pagination"><ul><li class="disabled"><a href="#">«</a></li><li class="active"><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">»</a></li></ul></div>
{% endblock %}
- 5.3. 后台用户信息添加模板:/templates/myadmin/users/add.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>会员信息管理</h3><form id="edit-profile" action="{% url 'myadmin_users_insert' %}" class="form-horizontal" method="post">{% csrf_token %}<fieldset><legend>添加会员信息</legend><div class="control-group"><label class="control-label" for="input01">账号:</label><div class="controls"><input type="text" name="username" class="input-xlarge" id="input01" value="" /></div></div><div class="control-group"><label class="control-label" for="input01">密码:</label><div class="controls"><input type="password" name="password" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">重复密码:</label><div class="controls"><input type="password" name="repassword" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">真实姓名:</label><div class="controls"><input type="text" name="name" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">性别:</label><div class="controls"><input type="radio" name="sex" class="input-xlarge" id="input01" value="1" /> 男<input type="radio" name="sex" class="input-xlarge" id="input01" value="0" /> 女</div></div><div class="control-group"><label class="control-label" for="input01">地址:</label><div class="controls"><input type="text" name="address" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">邮编:</label><div class="controls"><input type="text" name="code" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">电话:</label><div class="controls"><input type="text" name="phone" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">email邮箱:</label><div class="controls"><input type="text" name="email" class="input-xlarge" id="input01"/></div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">添加</button> <button type="reset" class="btn">重置</button></div></fieldset></form>
{% endblock %}
- 5.4. 后台用户信息编辑模板:/templates/myadmin/users/edit.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>会员信息管理</h3><form id="edit-profile" action="{% url 'myadmin_users_update' user.id %}" class="form-horizontal" method="post">{% csrf_token %}<fieldset><legend>编辑会员信息</legend><div class="control-group"><label class="control-label" for="input01">账号:</label><div class="controls">{{ user.username }}</div></div><div class="control-group"><label class="control-label" for="input01">真实姓名:</label><div class="controls"><input type="text" name="name" class="input-xlarge" id="input01" value="{{ user.name }}" /></div></div><div class="control-group"><label class="control-label" for="input01">性别:</label><div class="controls"><input type="radio" name="sex" class="input-xlarge" id="input01" value="1" {% if user.sex == 1 %}checked{% endif %} /> 男<input type="radio" name="sex" class="input-xlarge" id="input01" value="0"{% if user.sex == 0 %}checked{% endif %} /> 女</div></div><div class="control-group"><label class="control-label" for="input01">地址:</label><div class="controls"><input type="text" name="address" class="input-xlarge" id="input01" value="{{ user.address }}" /></div></div><div class="control-group"><label class="control-label" for="input01">邮编:</label><div class="controls"><input type="text" name="code" class="input-xlarge" id="input01" value="{{ user.code }}" /></div></div><div class="control-group"><label class="control-label" for="input01">电话:</label><div class="controls"><input type="text" name="phone" class="input-xlarge" id="input01" value="{{ user.phone }}" /></div></div><div class="control-group"><label class="control-label" for="input01">email邮箱:</label><div class="controls"><input type="text" name="email" class="input-xlarge" id="input01" value="{{ user.email }}" /></div></div><div class="control-group"><label class="control-label" for="input01">状态:</label><div class="controls"><input type="radio" name="state" class="input-xlarge" id="input01" value="0" {% if user.state == 0 %}checked{% endif %} /> 管理员 <input type="radio" name="state" class="input-xlarge" id="input01" value="1" {% if user.state == 1 %}checked{% endif %} /> 启用会员<input type="radio" name="state" class="input-xlarge" id="input01" value="2" {% if user.state == 2 %}checked{% endif %} /> 禁用用户</div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">保存</button> <button type="reset" class="btn">重置</button></div></fieldset></form>
{% endblock %}
(6). 运行测试
- 在项目根目录下启动服务,并使用浏览器访问测试:http://localhost:8000/myadmin
[root@localhost myobject]# pwd
/python/myobject
[root@localhost myobject]# ls
manage.py myadmin myobject myweb static templates
[root@localhost myobject]# python3 manage.py runserver
Performing system checks...System check identified no issues (0 silenced).April 06, 2018 - 14:29:36
Django version 1.11, using settings 'myobject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
^C[root@localhost myobject]#
6. 项目实战后台之管理员登陆与退出
①. 添加中间件
②. 登录与退出
③. 添加验证码
注意:本节实战会使用到Django框架中的session,而session信息又存放的数据库中,所以要先使用数据迁移命令在MySQL数据库中先生成一些Django默认自带表。
python manage.py migrate
①. 添加中间件
- 此中间件对后台网址访问做了是否登录的判断
- 关于网站后台要求:只要访问的URL地址是以 “/admin” 开头的都会执行是否登录判断验证。
(1). 在common公共应用中创建中间件
- 创建文件:
myobject/common/shopmiddleware.py
, 代码如下:
# 自定义中间件类
from django.shortcuts import redirect
from django.core.urlresolvers import reverseimport reclass ShopMiddleware(object):def __init__(self, get_response):self.get_response = get_response# One-time configuration and initialization(一次性配置和初始化).#print("ShopMiddleware")def __call__(self, request):# 定义网站后台不用登录也可访问的路由urlurllist = ['/myadmin/login','/myadmin/dologin','/myadmin/logout']# 获取当前请求路径path = request.path#print("Hello World!"+path)# 判断当前请求是否是访问网站后台,并且path不在urllist中if re.match("/myadmin",path) and (path not in urllist):# 判断当前用户是否没有登录if "adminuser" not in request.session:# 执行登录界面跳转return redirect(reverse('myadmin_login'))response = self.get_response(request)# Code to be executed for each request/response after# the view is called.return response
(2). 将自定义的中间件注册到项目中
- 编辑
myobject/settings.py
配置文件, 添加如下代码
...MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','common.shopmiddleware.ShopMiddleware', #注册中间件
]...
(3). 配置路由、模板并测试中间件
- 3.1 配置路由
myobject/myadmin/urls.py
加入如下代码
....# 后台管理员路由url(r'^login$', index.login, name="myadmin_login"),url(r'^dologin$', index.dologin, name="myadmin_dologin"),url(r'^logout$', index.logout, name="myadmin_logout"),....
- 3.2 编写视图
myobject/myadmin/views/index.py
文件 并加入如下代码:
...
# ==============后台管理员操作====================
# 会员登录表单
def login(request):return render(request,'myadmin/login.html')# 会员执行登录
def dologin(request):pass# 会员退出
def logout(request):pass
...
- 3.3 创建登录模板文件:
templates/myadmin/login.html
代码如下:
{% load static from staticfiles %}
<!DOCTYPE html>
<html lang="cn"><head><meta charset="utf-8"><title>Login - Akira</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><link href="{% static 'myadmin/css/bootstrap.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/bootstrap-responsive.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/site.css' %}" rel="stylesheet"><!--[if lt IE 9]><script src="{% static 'myadmin/js/html5.js' %}"></script><![endif]--></head><body><div id="login-page" class="container"><h1>商城后台管理登录</h1><form id="login-form" method="post" class="well" action="{% url 'myadmin_dologin' %}">{% csrf_token %}账号:<input type="text" name="username" class="span2" placeholder="输入账号" /><br />密码:<input type="password" name="password" class="span2" placeholder="输入密码" /><br /><label class="checkbox"> <input type="checkbox" /> Remember me </label><button type="submit" class="btn btn-primary">登录</button><button type="reset" class="btn">重置</button></form> <br/><span style="color:red">{{ info }}</span></div><script src="{% static 'myadmin/js/jquery.min.js' %}"></script><script src="{% static 'myadmin/js/bootstrap.min.js' %}"></script><script src="{% static 'myadmin/js/site.js' %}"></script></body>
</html>
(4). 启动服务测试,网站后台就进不去了,统一调跳转登录页面中
②. 登录与退出
(1). 配置路由(已配置过可省略)
- 配置路由
myobject/myadmin/urls.py
加入如下代码
....# 后台管理员路由url(r'^login$', index.login, name="myadmin_login"),url(r'^dologin$', index.dologin, name="myadmin_dologin"),url(r'^logout$', index.logout, name="myadmin_logout"),....
(2). 编写视图文件
- 编写视图
myobject/myadmin/views/index.py
文件 并加入如下代码:
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Users
import time,json...# ==============后台管理员操作====================
# 会员登录表单
def login(request):return render(request,'myadmin/login.html')# 会员执行登录
def dologin(request):try:#根据账号获取登录者信息user = Users.objects.get(username=request.POST['username'])#判断当前用户是否是后台管理员用户if user.state == 0:# 验证密码import hashlibm = hashlib.md5() m.update(bytes(request.POST['password'],encoding="utf8"))if user.password == m.hexdigest():# 此处登录成功,将当前登录信息放入到session中,并跳转页面request.session['adminuser'] = user.name#print(json.dumps(user))return redirect(reverse('myadmin_index'))else:context = {'info':'登录密码错误!'}else:context = {'info':'此用户非后台管理用户!'}except:context = {'info':'登录账号错误!'}return render(request,"myadmin/login.html",context)# 会员退出
def logout(request):# 清除登录的session信息del request.session['adminuser']# 跳转登录页面(url地址改变)return redirect(reverse('myadmin_login'))# 加载登录页面(url地址不变)#return render(request,"myadmin/login.html")
...
(3). 创建模板
- 创建登录模板文件:
templates/myadmin/login.html
代码如下:
{% load static from staticfiles %}
<!DOCTYPE html>
<html lang="cn"><head><meta charset="utf-8"><title>Login - Akira</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><link href="{% static 'myadmin/css/bootstrap.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/bootstrap-responsive.min.css' %}" rel="stylesheet"><link href="{% static 'myadmin/css/site.css' %}" rel="stylesheet"><!--[if lt IE 9]><script src="{% static 'myadmin/js/html5.js' %}"></script><![endif]--></head><body><div id="login-page" class="container"><h1>商城后台管理登录</h1><form id="login-form" method="post" class="well" action="{% url 'myadmin_dologin' %}">{% csrf_token %}账号:<input type="text" name="username" class="span2" placeholder="输入账号" /><br />密码:<input type="password" name="password" class="span2" placeholder="输入密码" /><br /><label class="checkbox"> <input type="checkbox" /> Remember me </label><button type="submit" class="btn btn-primary">登录</button><button type="reset" class="btn">重置</button></form> <br/><span style="color:red">{{ info }}</span></div><script src="{% static 'myadmin/js/jquery.min.js' %}"></script><script src="{% static 'myadmin/js/bootstrap.min.js' %}"></script><script src="{% static 'myadmin/js/site.js' %}"></script></body>
</html>
- 修改模板文件:
templates/myadmin/base.html
代码如下: - 代码在页头处,62~70行左右
...<ul class="nav pull-right"><li><a href="profile.htm">@{{ request.session.adminuser }}</a></li><li><a href="{% url 'myadmin_logout' %}">退出</a></li></ul>
...
(4). 启动服务测试,即可测试网站后台是否可以使用。注意只有管理员才开登录。
③. 添加验证码
(1). 配置路由
- 配置路由
myobject/myadmin/urls.py
加入如下代码
....# 后台管理员路由url(r'^login$', index.login, name="myadmin_login"),url(r'^dologin$', index.dologin, name="myadmin_dologin"),url(r'^logout$', index.logout, name="myadmin_logout"),url(r'^verify$', index.verify, name="myadmin_verify"), #验证码....
(2). 编写视图文件
- 编写视图
myobject/myadmin/views/index.py
文件 并加入如下代码: - 在
后台管理员操作
中添加输出验证码方法verify()
- 将字体文件
STXIHEI.TTF
复制到 static/目录下
...# ==============后台管理员操作====================
# 会员登录表单
def verify(request):#引入随机函数模块import randomfrom PIL import Image, ImageDraw, ImageFont#定义变量,用于画面的背景色、宽、高#bgcolor = (random.randrange(20, 100), random.randrange(# 20, 100),100)bgcolor = (242,164,247)width = 100height = 25#创建画面对象im = Image.new('RGB', (width, height), bgcolor)#创建画笔对象draw = ImageDraw.Draw(im)#调用画笔的point()函数绘制噪点for i in range(0, 100):xy = (random.randrange(0, width), random.randrange(0, height))fill = (random.randrange(0, 255), 255, random.randrange(0, 255))draw.point(xy, fill=fill)#定义验证码的备选值str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'#随机选取4个值作为验证码rand_str = ''for i in range(0, 4):rand_str += str1[random.randrange(0, len(str1))]#构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”font = ImageFont.truetype('static/STXIHEI.TTF', 21)#font = ImageFont.load_default().font#构造字体颜色fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))#绘制4个字draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)#释放画笔del draw#存入session,用于做进一步验证request.session['verifycode'] = rand_str"""python2的为# 内存文件操作import cStringIObuf = cStringIO.StringIO()"""# 内存文件操作-->此方法为python3的import iobuf = io.BytesIO()#将图片保存在内存中,文件类型为pngim.save(buf, 'png')#将内存中的图片数据返回给客户端,MIME类型为图片pngreturn HttpResponse(buf.getvalue(), 'image/png')...
(3). 在中间件设置放行
- 编写:myobject/common/shopmiddleware.py文件
- 在
__call__()
方法的urllist
变量中加入:/myadmin/verify
# 定义网站后台不用登录也可访问的路由urlurllist = ['/myadmin/login','/myadmin/dologin','/myadmin/logout','/myadmin/verify']
测试:http://localhost:8000/myadmin/verify
(4). 在登录模板中使用验证码
- 登录模板文件:
templates/myadmin/login.html
中加入代码如下:
....
<form id="login-form" method="post" class="well" action="{% url 'myadmin_dologin' %}">{% csrf_token %}账 号:<input type="text" name="username" class="span2" placeholder="输入账号" /><br />密 码:<input type="password" name="password" class="span2" placeholder="输入密码" /><br />验证码:<input type="text" name="code" class="span2" style="width:30px;" /><img src="{% url 'myadmin_verify'%}" onclick="this.src='{% url 'myadmin_verify' %}?sn='+Math.random()"/><br /><label class="checkbox"> <input type="checkbox" /> Remember me </label><button type="submit" class="btn btn-primary">登录</button><button type="reset" class="btn">重置</button>
</form>
...
(5). 验证码校验
- 编辑视图文件:
myobject/myadmin/views/index.py
文件 - 在视图文件中的会员执行登录方法
dologin()
中加入验证代码
...
# 会员执行登录
def dologin(request):# 校验验证码verifycode = request.session['verifycode']code = request.POST['code']if verifycode != code:context = {'info':'验证码错误!'}return render(request,"myadmin/login.html",context)try:#根据账号获取登录者信息user = Users.objects.get(username=request.POST['username'])#判断当前用户是否是后台管理员用户if user.state == 0:# 验证密码import hashlibm = hashlib.md5() m.update(bytes(request.POST['password'],encoding="utf8"))if user.password == m.hexdigest():# 此处登录成功,将当前登录信息放入到session中,并跳转页面request.session['adminuser'] = user.name#print(json.dumps(user))return redirect(reverse('myadmin_index'))else:context = {'info':'登录密码错误!'}else:context = {'info':'此用户非后台管理用户!'}except:context = {'info':'登录账号错误!'}return render(request,"myadmin/login.html",context)
....
(6). 启动服务测试,即可测试网站后台是否可以使用。注意只有管理员才开登录。
7. 项目实战后台之商品类别信息管理
后台商品类别信息管理
本页面完成项目后台管理的商品类别信息模块操作
(1). 商品类别信息数据表:type
- 在数据库
shopdb
中创建type表,若此表已存在请跳过
CREATE TABLE `type` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL, `pid` int(11) unsigned DEFAULT '0', `path` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
(2). 定义模型Model类
- 进入
common
应用目录中编辑:myobject/common/models.py
模型文件
from django.db import models#商品类别信息模型
class Types(models.Model):name = models.CharField(max_length=32)pid = models.IntegerField(default=0)path = models.CharField(max_length=255)class Meta:db_table = "type" # 更改表名
(3). 项目urls路由信息配置
- 打开根路由文件:myobject/myadmin/urls.py路由文件,编辑路由配置信息
from django.conf.urls import urlfrom myadmin.views import index,users,typeurlpatterns = [...# 后台商品类别信息管理url(r'^type$', type.index, name="myadmin_type_index"),url(r'^type/add/(?P<tid>[0-9]+)$', type.add, name="myadmin_type_add"),url(r'^type/insert$', type.insert, name="myadmin_type_insert"),url(r'^type/del/(?P<tid>[0-9]+)$', type.delete, name="myadmin_type_del"),url(r'^type/edit/(?P<tid>[0-9]+)$', type.edit, name="myadmin_type_edit"),url(r'^type/update/(?P<tid>[0-9]+)$', type.update, name="myadmin_type_update"),
]
(4). 编辑视图文件
- 新建视图文件:myobject/myadmin/views/type.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Types# 浏览商品类别信息
def index(request):# 执行数据查询,并放置到模板中list = Types.objects.extra(select = {'_has':'concat(path,id)'}).order_by('_has')# 遍历查询结果,为每个结果对象追加一个pname属性,目的用于缩进标题for ob in list:ob.pname ='. . . '*(ob.path.count(',')-1)# print(list[0].__dict__)context = {"typeslist":list}return render(request,'myadmin/type/index.html',context)# 商品类别信息添加表单
def add(request,tid):# 获取父类别信息,若没有则默认为根类别信息if tid == '0':context = {'pid':0,'path':'0,','name':'根类别'}else:ob = Types.objects.get(id=tid)context = {'pid':ob.id,'path':ob.path+str(ob.id)+',','name':ob.name}return render(request,'myadmin/type/add.html',context)#执行商品类别信息添加
def insert(request):try:ob = Types()ob.name = request.POST['name']ob.pid = request.POST['pid']ob.path = request.POST['path']ob.save()context = {'info':'添加成功!'}except Exception as err:print(err)context = {'info':'添加失败!'}return render(request,"myadmin/info.html",context)# 执行商品类别信息删除
def delete(request,tid):try:# 获取被删除商品的子类别信息量,若有数据,就禁止删除当前类别row = Types.objects.filter(pid=tid).count()if row > 0:context = {'info':'删除失败:此类别下还有子类别!'}return render(request,"myadmin/info.html",context)ob = Types.objects.get(id=tid)ob.delete()context = {'info':'删除成功!'}except Exception as err:print(err)context = {'info':'删除失败!'}return render(request,"myadmin/info.html",context)# 打开商品类别信息编辑表单
def edit(request,tid):try:ob = Types.objects.get(id=tid)context = {'type':ob}return render(request,"myadmin/type/edit.html",context)except Exception as err:print(err)context = {'info':'没有找到要修改的信息!'}return render(request,"myadmin/info.html",context)# 执行商品类别信息编辑
def update(request,tid):try:ob = Types.objects.get(id=tid)ob.name = request.POST['name']ob.save()context = {'info':'修改成功!'}except Exception as err:print(err)context = {'info':'修改失败!'}return render(request,"myadmin/info.html",context)
(5). 编写模板文件
- 5.1. 打开父类模板:/templates/myadmin/base.html ,编辑导航栏代码
...<li class="nav-header">商品类别管理</li><li><a href="{% url 'myadmin_type_index' %}"><i class="icon-envelope"></i> 浏览商品类别</a></li><li><a href="{% url 'myadmin_type_add' 0 %}"><i class="icon-file"></i> 添加商品类别</a></li>...
- 5.2. 后台商品类别信息浏览页模板:/templates/myadmin/type/index.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h4>商品类别信息管理</h4><table class="table table-bordered table-striped"><thead><tr><th>ID号</th><th>类别名称</th><th>父类别id</th><th>路径</th><th>操作</th></tr></thead><tbody>{% for vo in typeslist %}<tr><td>{{ vo.id }}</td><td>{{ vo.pname}}|-- {{ vo.name }}</td><td>{{ vo.pid }}</td><td>{{ vo.path }}</td><td width="30%"><a href="{% url 'myadmin_type_add' vo.id %}" class="view-link">添加子类别</a><a href="{% url 'myadmin_type_del' vo.id %}" class="view-link">删除</a><a href="{% url 'myadmin_type_edit' vo.id %}" class="view-link">编辑</a></td></tr>{% endfor %}</tbody></table> <div class="pagination"><ul><li class="disabled"><a href="#">«</a></li><li class="active"><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">»</a></li></ul></div>
{% endblock %}
- 5.3. 后台商品类别信息添加表单页模板:/templates/myadmin/type/add.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>商品类别信息管理</h3><form id="edit-profile" action="{% url 'myadmin_type_insert' %}" class="form-horizontal" method="post"><input type="hidden" name="pid" value="{{ pid }}"/><input type="hidden" name="path" value="{{ path }}"/>{% csrf_token %}<fieldset><legend>添加商品类别信息</legend><div class="control-group"><label class="control-label" for="input01">父类别名称:</label><div class="controls"><input type="text" name="pname" class="input-xlarge" id="input01" value="" placeholder="{{name}}"/></div></div><div class="control-group"><label class="control-label" for="input01">类别名称:</label><div class="controls"><input type="text" name="name" class="input-xlarge" id="input01"/></div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">添加</button> <button type="reset" class="btn">重置</button></div></fieldset></form>
{% endblock %}
- 5.4. 后台商品信息编辑模板:/templates/myadmin/type/edit.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>商品类别信息管理</h3><form id="edit-profile" action="{% url 'myadmin_type_update' type.id %}" class="form-horizontal" method="post">{% csrf_token %}<fieldset><legend>编辑商品类别信息</legend><div class="control-group"><label class="control-label" for="input01">类别名称:</label><div class="controls"><input type="text" name="name" class="input-xlarge" id="input01" value="{{ type.name }}" /></div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">保存</button> <button type="reset" class="btn">重置</button></div></fieldset></form>
{% endblock %}
(6). 运行测试
- 在项目根目录下启动服务,并使用浏览器访问测试:http://localhost:8000/myadmin
[root@localhost myobject]# pwd
/python/myobject
[root@localhost myobject]# ls
manage.py myadmin myobject myweb static templates
[root@localhost myobject]# python3 manage.py runserver
Performing system checks...System check identified no issues (0 silenced).April 07, 2018 - 16:29:36
Django version 1.11, using settings 'myobject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
^C[root@localhost myobject]#
8. 项目实战后台之商品信息管理
- 本页面完成项目后台管理的商品信息模块操作
(1). 商品信息数据表:goods
- 在数据库
shopdb
中创建goods
表,若此表已存在请跳过
CREATE TABLE `goods` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `typeid` int(11) unsigned NOT NULL, `goods` varchar(32) NOT NULL, `company` varchar(50) DEFAULT NULL, `content` text, `price` double(6,2) unsigned NOT NULL, `picname` varchar(255) DEFAULT NULL, `store` int(11) unsigned NOT NULL DEFAULT '0', `num` int(11) unsigned NOT NULL DEFAULT '0', `clicknum` int(11) unsigned NOT NULL DEFAULT '0', `state` tinyint(1) unsigned NOT NULL DEFAULT '1', `addtime` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `typeid` (`typeid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
(2). 定义模型Model类
- 进入common应用目录中,编辑:
myobject/common/models.py
模型文件,添加如下代码
from django.db import modelsfrom datetime import datetime#商品信息模型
class Goods(models.Model):typeid = models.IntegerField()goods = models.CharField(max_length=32)company = models.CharField(max_length=50)content = models.TextField()price = models.FloatField()picname = models.CharField(max_length=255)store = models.IntegerField(default=0)num = models.IntegerField(default=0)clicknum = models.IntegerField(default=0)state = models.IntegerField(default=1)addtime = models.DateTimeField(default=datetime.now)def toDict(self):return {'id':self.id,'typeid':self.typeid,'goods':self.goods,'company':self.company,'price':self.price,'picname':self.picname,'store':self.store,'num':self.num,'clicknum':self.clicknum,'state':self.state}class Meta:db_table = "goods" # 更改表名
(3). 项目urls路由信息配置
- 打开根路由文件:myobject/myadmin/urls.py路由文件,编辑路由配置信息
from django.conf.urls import urlfrom myadmin.views import index,users,type,goodsurlpatterns = [...# 后台商品信息管理url(r'^goods$', goods.index, name="myadmin_goods_index"),url(r'^goods/add$', goods.add, name="myadmin_goods_add"),url(r'^goods/insert$', goods.insert, name="myadmin_goods_insert"),url(r'^goods/del/(?P<gid>[0-9]+)$', goods.delete, name="myadmin_goods_del"),url(r'^goods/edit/(?P<gid>[0-9]+)$', goods.edit, name="myadmin_goods_edit"),url(r'^goods/update/(?P<gid>[0-9]+)$', goods.update, name="myadmin_goods_update"),
]
(4). 编辑视图文件
- 新建视图文件:myobject/myadmin/views/goods.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Types,Goods
from PIL import Image
from datetime import datetime
import time,json,os# ==============后台商品信息管理======================
# 浏览商品信息
def index(request):# 执行数据查询,并放置到模板中list = Goods.objects.all()for ob in list:ty = Types.objects.get(id=ob.typeid)ob.typename = ty.namecontext = {"goodslist":list}return render(request,'myadmin/goods/index.html',context)# 商品信息添加表单
def add(request):# 获取商品的类别信息list = Types.objects.extra(select = {'_has':'concat(path,id)'}).order_by('_has')context = {"typelist":list}return render(request,'myadmin/goods/add.html',context)#执行商品类别信息添加
def insert(request):try:# 判断并执行图片上传,缩放等处理myfile = request.FILES.get("pic", None)if not myfile:return HttpResponse("没有上传文件信息!")# 以时间戳命名一个新图片名称filename= str(time.time())+"."+myfile.name.split('.').pop()destination = open(os.path.join("./static/goods/",filename),'wb+')for chunk in myfile.chunks(): # 分块写入文件 destination.write(chunk) destination.close()# 执行图片缩放im = Image.open("./static/goods/"+filename)# 缩放到375*375:im.thumbnail((375, 375))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/"+filename, 'jpeg')# 缩放到220*220:im.thumbnail((220, 220))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/m_"+filename, 'jpeg')# 缩放到75*75:im.thumbnail((75, 75))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/s_"+filename, 'jpeg')# 获取商品信息并执行添加ob = Goods()ob.goods = request.POST['goods']ob.typeid = request.POST['typeid']ob.company = request.POST['company']ob.price = request.POST['price']ob.store = request.POST['store']ob.content = request.POST['content']ob.picname = filenameob.state = 1ob.addtime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")ob.save()context = {'info':'添加成功!'}except Exception as err:print(err)context = {'info':'添加失败!'}return render(request,"myadmin/info.html",context)# 执行商品信息删除
def delete(request,gid):try:# 获取被删除商品信的息量,先删除对应的图片ob = Goods.objects.get(id=gid)#执行图片删除os.remove("./static/goods/"+ob.picname) os.remove("./static/goods/m_"+ob.picname) os.remove("./static/goods/s_"+ob.picname)#执行商品信息的删除 ob.delete()context = {'info':'删除成功!'}except Exception as err:print(err)context = {'info':'删除失败!'}return render(request,"myadmin/info.html",context)# 打开商品类别信息编辑表单
def edit(request,gid):try:# 获取要编辑的信息ob = Goods.objects.get(id=gid)# 获取商品的类别信息list = Types.objects.extra(select = {'_has':'concat(path,id)'}).order_by('_has')# 放置信息加载模板context = {"typelist":list,'goods':ob}return render(request,"myadmin/goods/edit.html",context)except Exception as err:print(err)context = {'info':'没有找到要修改的信息!'}return render(request,"myadmin/info.html",context)# 执行商品类别信息编辑
def update(request,gid):try:b = Falseoldpicname = request.POST['oldpicname']if None != request.FILES.get("pic"):myfile = request.FILES.get("pic", None)if not myfile:return HttpResponse("没有上传文件信息!")# 以时间戳命名一个新图片名称filename = str(time.time())+"."+myfile.name.split('.').pop()destination = open(os.path.join("./static/goods/",filename),'wb+')for chunk in myfile.chunks(): # 分块写入文件 destination.write(chunk) destination.close()# 执行图片缩放im = Image.open("./static/goods/"+filename)# 缩放到375*375:im.thumbnail((375, 375))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/"+filename, 'jpeg')# 缩放到220*220:im.thumbnail((220, 220))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/m_"+filename, 'jpeg')# 缩放到75*75:im.thumbnail((75, 75))# 把缩放后的图像用jpeg格式保存:im.save("./static/goods/s_"+filename, 'jpeg')b = Truepicname = filenameelse:picname = oldpicnameob = Goods.objects.get(id=gid)ob.goods = request.POST['goods']ob.typeid = request.POST['typeid']ob.company = request.POST['company']ob.price = request.POST['price']ob.store = request.POST['store']ob.content = request.POST['content']ob.picname = picnameob.state = request.POST['state']ob.save()context = {'info':'修改成功!'}if b:os.remove("./static/goods/m_"+oldpicname) #执行老图片删除 os.remove("./static/goods/s_"+oldpicname) #执行老图片删除 os.remove("./static/goods/"+oldpicname) #执行老图片删除 except Exception as err:print(err)context = {'info':'修改失败!'}if b:os.remove("./static/goods/m_"+picname) #执行新图片删除 os.remove("./static/goods/s_"+picname) #执行新图片删除 os.remove("./static/goods/"+picname) #执行新图片删除 return render(request,"myadmin/info.html",context)
(5). 编写模板文件
- 5.1. 打开父类模板:/templates/myadmin/base.html ,编辑导航栏代码
...<li class="nav-header">商品信息管理</li><li><a href="{% url 'myadmin_goods_index' %}"><i class="icon-list-alt"></i> 浏览商品信息</a></li><li><a href="{% url 'myadmin_goods_add' %}"><i class="icon-list-alt"></i> 添加商品信息</a></li>...
- 5.2. 后台商品信息浏览页模板:/templates/myadmin/goods/index.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h4>商品信息管理</h4><table class="table table-bordered table-striped"><thead><tr><th>id号</th><th>商品名称</th><th>商品类别</th><th>图片</th><th>单价</th><th>点击量</th><th>状态</th><th>操作</th></tr></thead><tbody>{% for vo in goodslist %}<tr><td>{{ vo.id }}</td><td>{{ vo.goods }}</td><td>{{ vo.typename }}</td><td><img src="/static/goods/s_{{ vo.picname }}" width="60"/></td><td>{{ vo.price }}</td><td>{{ vo.clicknum }}</td><td>{% if vo.state == 1 %}新添加{% elif vo.state == 2 %}在售{% else %}下架{% endif %}</td><td><a href="{% url 'myadmin_goods_del' vo.id %}" class="view-link">删除</a><a href="{% url 'myadmin_goods_edit' vo.id %}" class="view-link">编辑</a></td></tr>{% endfor %}</tbody></table> <div class="pagination"><ul><li class="disabled"><a href="#">«</a></li><li class="active"><a href="#">1</a></li><li><a href="#">2</a></li><li><a href="#">3</a></li><li><a href="#">4</a></li><li><a href="#">»</a></li></ul></div>
{% endblock %}
- 5.3. 后台商品信息添加表单页模板:/templates/myadmin/goods/add.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>商品信息管理</h3><form id="edit-profile" action="{% url 'myadmin_goods_insert' %}" class="form-horizontal" method="post" enctype="multipart/form-data">{% csrf_token %}<fieldset><legend>添加商品信息</legend><div class="control-group"><label class="control-label" for="input01">商品类别:</label><div class="controls"><select name="typeid">{% for vo in typelist %}<option {% if vo.pid == 0 %}disabled{% endif %} value="{{ vo.id }}">{{ vo.name }}</option>{% endfor %}</select></div></div><div class="control-group"><label class="control-label" for="input01">商品名称:</label><div class="controls"><input type="text" name="goods" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">生产厂家:</label><div class="controls"><input type="text" name="company" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">单价:</label><div class="controls"><input type="text" name="price" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">库存量:</label><div class="controls"><input type="text" name="store" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">商品图片:</label><div class="controls"><input type="file" name="pic" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">商品简介:</label><div class="controls"><textarea cols="40" style="width:450px" rows="10" name="content"></textarea></div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">添加</button> <button type="reset" class="btn">重置</button></div></fieldset></form>
{% endblock %}
- 5.4. 后台商品信息编辑模板:/templates/myadmin/goods/edit.html
{% extends "myadmin/base.html" %}{% block mainbody %} <h3>商品信息管理</h3><form id="edit-profile" action="{% url 'myadmin_goods_update' goods.id %}" class="form-horizontal" method="post" enctype="multipart/form-data">{% csrf_token %}<input type="hidden" name="oldpicname" value="{{ goods.picname }}"/><fieldset><legend>编辑商品信息</legend><div class="control-group"><label class="control-label" for="input01">商品类别:</label><div class="controls"><select name="typeid">{% for vo in typelist %}<option {% if vo.pid == 0 %}disabled{% endif %}{% if vo.id == goods.typeid %}selected {% endif %}value="{{ vo.id }}">{{ vo.name }}</option>{% endfor %}</select></div></div><div class="control-group"><label class="control-label" for="input01">商品名称:</label><div class="controls"><input type="text" name="goods" value="{{ goods.goods }}" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">生产厂家:</label><div class="controls"><input type="text" name="company" value="{{ goods.company }}" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">单价:</label><div class="controls"><input type="text" name="price" value="{{ goods.price }}" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">库存量:</label><div class="controls"><input type="text" name="store" value="{{ goods.store }}" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">商品图片:</label><div class="controls"><input type="file" name="pic" class="input-xlarge" id="input01"/></div></div><div class="control-group"><label class="control-label" for="input01">状态:</label><div class="controls"><input type="radio" name="state" class="input-xlarge" id="input01" {% if goods.state == 1 %}checked {% endif %}value="1" /> 新商品 <input type="radio" name="state" class="input-xlarge" id="input01" {% if goods.state == 2 %}checked {% endif %}value="2" /> 在售<input type="radio" name="state" class="input-xlarge" id="input01" {% if goods.state == 3 %}checked {% endif %}value="3" /> 已下架</div></div> <div class="control-group"><label class="control-label" for="input01">商品简介:</label><div class="controls"><textarea cols="40" style="width:450px" rows="10" name="content">{{ goods.content }}</textarea></div></div> <div class="form-actions"><button type="submit" class="btn btn-primary">保存</button> <button type="reset" class="btn">重置</button></div></fieldset></form><br/><img src="/static/goods/m_{{ goods.picname }}"/>
{% endblock %}
(6). 运行测试
- 在项目根目录下启动服务,并使用浏览器访问测试:http://localhost:8000/myadmin
[root@localhost myobject]# pwd
/python/myobject
[root@localhost myobject]# ls
manage.py myadmin myobject myweb static templates
[root@localhost myobject]# python3 manage.py runserver
Performing system checks...System check identified no issues (0 silenced).April 08, 2018 - 12:20:30
Django version 1.11, using settings 'myobject.settings'
Starting development server at http://0:8000/
Quit the server with CONTROL-C.
^C[root@localhost myobject]#
①. 搜索分页浏览商品信息(附加)
8.1 搜索&分页浏览商品信息(附加)
- 本节案例是建立在第八节《商品信息管理》之上继续开发的,具体效果如下:
(1). 编辑项目urls路由信息配置
- 打开根路由文件:myobject/myadmin/urls.py路由文件,编辑路由配置信息:
- 为商品信息浏览路由添加页码参数:
url(r'^goods/(?P<pIndex>[0-9]+)$', ... ... ),
,具体如下:
from django.conf.urls import urlfrom myadmin.views import index,users,type,goodsurlpatterns = [...# 后台商品信息管理url(r'^goods/(?P<pIndex>[0-9]+)$', goods.index, name="myadmin_goods_index"),url(r'^goods/add$', goods.add, name="myadmin_goods_add"),url(r'^goods/insert$', goods.insert, name="myadmin_goods_insert"),url(r'^goods/del/(?P<gid>[0-9]+)$', goods.delete, name="myadmin_goods_del"),url(r'^goods/edit/(?P<gid>[0-9]+)$', goods.edit, name="myadmin_goods_edit"),url(r'^goods/update/(?P<gid>[0-9]+)$', goods.update, name="myadmin_goods_update"),
]
(2). 编辑视图文件
- 新建视图文件:myobject/myadmin/views/goods.py 视图文件,并进行编辑index方法中代码
- 导入查询
Q
和分页Paginator
:
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.core.paginator import Paginatorfrom common.models import Types,Goods
from PIL import Image
from datetime import datetime
import time,json,os# ==============后台商品信息管理======================
# 浏览商品信息
def index(request,pIndex):'''浏览信息'''#获取商品类别信息tlist = Types.objects.extra(select={'_has':'concat(path,id)'}).order_by('_has')for ob in tlist:ob.pname = '. . .'*(ob.path.count(',')-1)#获取商品信息查询对象mod = Goods.objectsmywhere=[] #定义一个用于存放搜索条件列表# 获取、判断并封装关keyword键搜索kw = request.GET.get("keyword",None)if kw:# 查询商品名中只要含有关键字的都可以list = mod.filter(goods__contains=kw)mywhere.append("keyword="+kw)else:list = mod.filter()# 获取、判断并封装商品类别typeid搜索条件typeid = request.GET.get('typeid','0')if typeid != '0':tids = Types.objects.filter(Q(id=typeid) | Q(pid=typeid)).values_list('id',flat=True)list = list.filter(typeid__in=tids)mywhere.append("typeid="+typeid)# 获取、判断并封装商品状态state搜索条件state = request.GET.get('state','')if state != '':list = list.filter(state=state)mywhere.append("state="+state)#执行分页处理pIndex = int(pIndex)page = Paginator(list,5) #以5条每页创建分页对象maxpages = page.num_pages #最大页数#判断页数是否越界if pIndex > maxpages:pIndex = maxpagesif pIndex < 1:pIndex = 1list2 = page.page(pIndex) #当前页数据plist = page.page_range #页码数列表#遍历商品信息,并获取对应的商品类别名称,以typename名封装for vo in list2:ty = Types.objects.get(id=vo.typeid)vo.typename = ty.name#封装信息加载模板输出context = {'typelist':tlist,"goodslist":list2,'plist':plist,'pIndex':pIndex,'maxpages':maxpages,'mywhere':mywhere,'typeid':int(typeid)}return render(request,"myadmin/goods/index.html",context)# 商品信息添加表单
....
....
(3). 编写模板文件
- 3.1. 打开父类模板:/templates/myadmin/base.html ,编辑导航栏代码
- 将为路由
myadmin_goods_index
添加一个默认页号参数1:
...<li class="nav-header">商品信息管理</li><li><a href="{% url 'myadmin_goods_index' 1 %}"><i class="icon-list-alt"></i> 浏览商品信息</a></li><li><a href="{% url 'myadmin_goods_add' %}"><i class="icon-list-alt"></i> 添加商品信息</a></li>...
- 3.2. 后台商品信息浏览页模板:/templates/myadmin/goods/index.html
- 在里面添加
搜索表单
和页码信息
, 注意:{ { mywhere|join:'&' } }
是为了下一页维持搜索条件用的:
{% extends "myadmin/base.html" %}{% block mainbody %}
<h2>商品信息浏览
</h2>
<form class="form-inline" action="{% url 'myadmin_goods_index' 1 %}" method="get"><label>关键字:</label><input type="text" name="keyword" value="{{request.GET.keyword}}" class="input-small" placeholder="商品名称"><label> 类别:</label><select name="typeid" class="span2"><option value="0">全部</option>{% for vo in typelist %}<option value="{{ vo.id }}" {% if typeid == vo.id %}selected{% endif %}>{{vo.pname}}|--{{ vo.name }}</option>{% endfor %}</select><label> 状态:</label><select name="state" class="span1"><option value="">全部</option><option value="1" {% if request.GET.state == '1' %}selected{% endif %}>新商品</option><option value="2" {% if request.GET.state == '2' %}selected{% endif %}>在售</option><option value="3" {% if request.GET.state == '3' %}selected{% endif %}>已下架</option></select><button type="submit" class="btn">搜索</button><a href="{% url 'myadmin_goods_index' 1 %}" class="btn">全部</a>
</form>
<table class="table table-bordered table-striped"><thead><tr><th>id号</th><th>商品名称</th><th>商品类别</th><th>图片</th><th>价格</th><th>点击量</th><th>状态</th><th>操作</th></tr></thead><tbody>{% for vo in goodslist %}<tr><td>{{ vo.id }}</td><td>{{ vo.goods }}</td><td>{{ vo.typename }}</td><td><img src="/static/goods/s_{{ vo.picname }}" width="40"/></td><td>{{ vo.price }}</td><td>{{ vo.clicknum }}</td><td>{% if vo.state == 1 %}<span style="color:green">新商品</span>{% elif vo.state == 2 %}在售{% elif vo.state == 3 %}已下架{% else %}<span style="color:red">无效状态</span>{% endif %}</td><td><a href="{% url 'myadmin_goods_edit' vo.id %}" class="btn btn-mini btn-primary">编辑</a><a href="{% url 'myadmin_goods_del' vo.id %}" class="btn btn-mini btn-danger">删除</a></td></tr>{% endfor %}</tbody>
</table>
<div class="pagination"><ul><li><a href="{% url 'myadmin_goods_index' pIndex|add:-1 %}?{{ mywhere|join:'&' }}">«</a></li>{% for p in plist %}<li {% if pIndex == p %}class="active"{% endif %}><a href="{% url 'myadmin_goods_index' p %}?{{ mywhere|join:'&' }}">{{p}}</a></li>{% endfor %}<li><a href="{% url 'myadmin_goods_index' pIndex|add:1 %}?{{ mywhere|join:'&' }}">»</a></li></ul>
</div>
{% endblock %}
(4). 运行测试
- 在项目根目录下启动服务,并使用浏览器访问测试:http://localhost:8000/myadmin
六、Django商城项目开发(下)
商城项目前台结构:
- 本次项目共计四个应用:中web应用为项目前台:
/myobject/├── manage.py├── myobject/ 项目总目录│ ├── ... 略│├── common/ 公共应用目录│ ├── ... 略│├── myadmin/ 网站后台应用目录│ ├── ... 略│├── web 网站前台应用│ ├── admin.py│ ├── apps.py│ ├── __init__.py│ ├── migrations│ ├── views│ │ ├── index.py web前台主视图│ │ ├── vip.py 会员操作视图│ │ ├── cart.py 购物车管理视图│ │ └── orders.py 订单处理视图│ ├── models.py│ ├── tests.py│ └── urls.py 网站前台的URL路由配置│├── ueditor 百度编辑器(富文本编辑器)目录│ ├── ... 略│├── templates 模板目录│ ├── myadmin 后台模板总目录│ │ ├── ... 略│ ││ ├── web 前台模板目录│ │ ├── base.html│ │ ├── index.html│ │ ├── list.html│ │ ├── detail.html│ │ ├── login.html│ │ ├── reg.html│ │ └── ......│├── static 静态资源目录│ ├── myadmin 后台静态资源 │ │ ├──....│ ││ ├── web 网站前台静态资源│ │ ├──....│ │ ├──....
项目前台的URL路由配置:
from django.conf.urls import urlfrom web.views import index,cart,orders,vipurlpatterns = [# 前台首页url(r'^$', index.index, name="index"), #商城首页url(r'^list$', index.lists, name="list"),# 商品列表url(r'^list/(?P<pIndex>[0-9]+)$', index.lists, name="list"),# 商品列表url(r'^detail/(?P<gid>[0-9]+)$', index.detail, name="detail"),#商品详情# 会员登录和退出路由配置url(r'^login$', index.login, name="login"),url(r'^dologin$', index.dologin, name="dologin"),url(r'^logout$', index.logout, name="logout"),# 购物车信息管理路由配置url(r'^cart$', cart.index, name="cart_index"),url(r'^cart/add/(?P<gid>[0-9]+)$', cart.add, name="cart_add"),url(r'^cart/del/(?P<gid>[0-9]+)$', cart.delete, name="cart_del"),url(r'^cart/clear$', cart.clear, name="cart_clear"),url(r'^cart/change$', cart.change, name="cart_change"),# 订单处理url(r'^orders/add$', orders.add,name='orders_add'), #订单的表单页url(r'^orders/confirm$', orders.confirm,name='orders_confirm'), #订单确认页url(r'^orders/insert$', orders.insert,name='orders_insert'), #执行订单添加操作# 会员中心url(r'^vip/orders$', vip.viporders,name='vip_orders'), #会员中心我的订单url(r'^vip/odstate$', vip.odstate,name='vip_odstate'), #修改订单状态(确认收货)#url(r'^vip/info$', vip.info,name='vip_info'), #会员中心的个人信息#url(r'^vip/update$', vip.update,name='vip_update'), #执行修改会员信息#url(r'^vip/resetps$', vip.resetps,name='vip_resetps'), #重置密码表单#url(r'^vip/doresetps$', vip.doresetps,name='vip_doresetps'), #执行重置密码
]
9. 项目实战前台搭建
- 本节是完成商城网站前台结构搭建,并且将网站首页,商品列表和详情页的界面摆放到web项目中
- 由于三个网页界面都有公共的页头和页脚,故采用模板继承来实现网页布局:
(1). 开发前的准备工作:
- 安装项目设计创建对象的文件和目录
- 将素材下的提前准备好模板目录中的静态资源目录:
css
、fonts
、img
、js
复制到项目的static/web/目录下。
(2). 目urls路由信息配置:
from django.conf.urls import urlfrom web.views import indexurlpatterns = [# 前台首页url(r'^$', index.index, name="index"), #商城首页url(r'^list$', index.lists, name="list"),# 商品列表url(r'^detail/(?P<gid>[0-9]+)$', index.detail, name="detail"),#商品详情
]
(3). 编辑视图文件
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def index(request):'''项目前台首页'''return render(request,"web/index.html")def lists(request,pIndex=1):'''商品列表页'''return render(request,"web/list.html")def detail(request,gid):'''商品详情页'''return render(request,"web/detail.html")
(4). 编写模板文件
- 使用模板继承套用模板文件:
base.html
、index.html
、list.html
、detail.html
具体参考老师的授课。 - 静态资源中的正则替换技巧:
"\./public/(.*?)"` 换成 `"{% static 'web/\1' %}"
10. 项目实战前台之会员注册与登陆
- 本节完成前台会员登录操作,关于会员注册留为练习由学员自行完成(可参考后台的会员信息添加)。
(1). 项目urls路由信息配置
- 在数据库
shopdb
中已存在数据表users
,并且内有测试数据。 - 在common应用目录中的
myobject/common/models.py
模型文件中,已存在Users
模型类的定义。 - 打开根路由文件:myobject/web/urls.py路由文件,编辑路由配置信息
from django.conf.urls import urlfrom web.views import indexurlpatterns = [#网站前台url(r'^$',index.index,name="index"), #首页url(r'^list$',index.lists,name="list"), #商品列表展示#url(r'^list/(?P<pIndex>[0-9]+)$',index.lists,name="list"), #分页商品列表展示url(r'^detail/(?P<gid>[0-9]+)$',index.detail,name="detail"), #商品详情# 会员及个人中心等路由配置url(r'^login$', index.login, name="login"),url(r'^dologin$', index.dologin, name="dologin"),url(r'^logout$', index.logout, name="logout"),]
(2). 编辑视图文件
- 新建视图文件:myobject/web/views/index.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Users# =============商品展示========================
def index(request):'''项目前台首页'''return render(request,"web/index.html")def lists(request,pIndex=1):'''商品列表页'''return render(request,"web/list.html")def detail(request,gid):'''商品详情页'''return render(request,"web/detail.html")# ==============前台会员登录====================
def login(request):'''会员登录表单'''return render(request,'web/login.html')def dologin(request):'''会员执行登录'''# 校验验证码verifycode = request.session['verifycode']code = request.POST['code']if verifycode != code:context = {'info':'验证码错误!'}return render(request,"web/login.html",context)try:#根据账号获取登录者信息user = Users.objects.get(username=request.POST['username'])#判断当前用户是否是后台管理员用户if user.state == 0 or user.state == 1:# 验证密码import hashlibm = hashlib.md5() m.update(bytes(request.POST['password'],encoding="utf8"))if user.password == m.hexdigest():# 此处登录成功,将当前登录信息放入到session中,并跳转页面request.session['vipuser'] = user.toDict()return redirect(reverse('index'))else:context = {'info':'登录密码错误!'}else:context = {'info':'此用户为非法用户!'}except:context = {'info':'登录账号错误!'}return render(request,"web/login.html",context)def logout(request):'''会员退出'''# 清除登录的session信息del request.session['vipuser']# 跳转登录页面(url地址改变)return redirect(reverse('login'))
(3). 编写模板文件
- 3.1. 打开父类模板:/templates/web/base.html ,编辑导航栏代码
...<li class="layout-header-service-item" id="layoutHeaderUser"><a class="layout-header-service-link g-user" style="background: #fff;width:auto;" href="#"><i class="glyphicon glyphicon-user"></i><span>{{request.session.vipuser.name}}</span></a><div class="layout-user-downmenu"><ul class="layout-user-downmenu-list">{% if request.session.vipuser %}<li class="layout-user-downmenu-item"><a href="#" class="layout-user-downmenu-link" data-mtype="wmz_public_grzx_myorder">个人中心</a></li><li class="layout-user-downmenu-item"><a href="#" class="layout-user-downmenu-link" data-mtype="wmz_public_grzx_myorder">我的订单</a></li><li class="layout-user-downmenu-item"><a href="{% url 'logout' %}" class="layout-user-downmenu-link" data-mtype="wmz_public_grzx_mformy">退出</a></li>{% else %}<li class="layout-user-downmenu-item"><a href="{% url 'login'%}" class="layout-user-downmenu-link">立即登录</a></li><li class="layout-user-downmenu-item"><a href="#" target="_blank" class="layout-user-downmenu-link" data-mtype="wmz_public_grzx_register">立即注册</a></li>{% endif %}</ul></div></li>...
- 3.2. 项目前台登录页模板:/templates/web/login.html
{% load static from staticfiles %}
<!DOCTYPE html>
<html lang="cn">
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --><title> Flyme 账号 - 登录</title><meta name="description" content="欢迎登录和注册 Flyme 账号,您可以体验手机云服务功能,包括:在线下载应用,同步手机数据和查找手机等,让您的手机管理更加智能。" /><meta name="keywords" content="魅族 meizu 登录flyme 云服务 查找手机 充值账号 MX M9 MX2" /> <link href="{% static 'web/img/favicon.ico' %}" rel="shortcut icon" type="image/x-icon"/><link href="{% static 'web/img/favicon.ico' %}" rel="icon" type="image/x-icon"><!-- Bootstrap --><link href="{% static 'web/css/bootstrap.min.css' %}" rel="stylesheet"><!-- jQuery (necessary for Bootstrap's JavaScript plugins) --><script src="{% static 'web/js/jquery-1.12.4.min.js' %}"></script><!-- Include all compiled plugins (below), or include individual files as needed --><script src="{% static 'web/js/bootstrap.min.js' %}"></script><!-- 兼任ie9以下 --><!--[if lt IE 9]><script src="http://cdn.bootcss.com/html5shiv/3.7.0/html5shiv.min.js"></script><script src="http://cdn.bootcss.com/respond.js/1.3.0/respond.min.js"></script><![endif]--><!-- 自定义 --><link rel="stylesheet" type="text/css" href="{% static 'web/css/global.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/register.css' %}"><script type="text/javascript" src="{% static 'web/js/rem.js' %}"></script><script type="text/javascript" src="{% static 'web/js/topNav.js' %}"></script></head>
<body><!-- 导航 --> <div class="layout-header hidden-xs hidden-sm" id="scroll-wrap"><nav class="navbar navbar-default header "><div class="container clearfix"><div class="layout-header-logo navbar-left"><a href="{% url 'index' %}" class="layout-header-logo-link" alt="魅族科技"><img src="{% static 'web/img/logo.png' %}"></a></div> </div></nav></div><!-- 导航 E--> <!-- 主内容区域 --><div id="content" class="content"> <div class="container-fluid"> <div class="banner-box hidden-xs hidden-sm"><div class="container"><form id="mainForm" name="mainForm" action="{% url 'dologin' %}" method="post" class="main-form">{% csrf_token %}<div class="tab-title"><a class="linkAGray" id="toAccountLogin" href="javascript:void(0);">账号登录</a></div><br/>{% if info %}<div class="tip-box"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><i class="glyphicon glyphicon-exclamation-sign"></i><span class="tip-font">{{info}}</span><span aria-hidden="true" class="cha">×</span></button></div>{% endif %}<div class="normalInput cycode-box fieldInput" id="cycode-box"><div class="cycode-selectbox"><input class="ipt-account inp-focus" name="username" id="account" maxlength="50" placeholder="登录账号" autocomplete="off"></div></div><div class="normalInput fieldInput passwd-box"><input class="inp-focus" name="password" id="password" maxlength="16" autocomplete="off" placeholder="登录密码" type="password"/></div><div class="normalInput fieldInput passwd-box"><input class="inp-focus" name="code" style="width:100px;" maxlength="16" placeholder="验证码" autocomplete="off" type="text" /><img src="{% url 'myadmin_verify' %}?id=1" onclick="this.src='{% url 'myadmin_verify' %}?sn='+Math.random()"/></div><a id="register" href="javascript:document.mainForm.submit();" class="fullBtnBlue">登录</a><div class="transferField"><a class="go2forgetpwd linkABlue rememberFieldForA" href="#">忘记密码?</a><a class="go2register linkABlue" href="./register.html" id="toRegister">注册</a><span>测试号:zhangsan 密码:123</span></div></form></div></div><!-- 移动端结构 --><form id="mainForm" class="main-form app-main-form"><div class="tab-title"><a class="linkAGray" id="toAccountLogin" href="javascript:void(0);">账号登录</a></div><div class="tip-box visiblility-hidden"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><i class="glyphicon glyphicon-exclamation-sign"></i><span class="tip-font"></span><span aria-hidden="true" class="cha">×</span></button></div><div class="normalInput cycode-box show-cycode" id="cycode-box"><div class="cycode-selectbox"><input id="phone" name="phone" class="ipt-phone inp-focus" maxlength="11" placeholder="手机号码" autocomplete="off"></div></div><div class="normalInput box-input"><input class="pswInput inp-focus" name="kapkey" id="kapkey" maxlength="6" placeholder="密码" autocomplete="off" tabindex="3" type="text"></div><a id="register" class="fullBtnBlue">登录</a><div class="transferField"><a class="go2forgetpwd linkABlue rememberFieldForA" href="#">忘记密码?</a><a class="go2register linkABlue" href="./register.html" id="toRegister">注册</a></div></form><!-- 移动端结构 E--></div></div><!-- 主内容区域 E--><!-- 底部区域 --><div id="flymeFooter " class="footerWrap hidden-xs hidden-sm"><div class="container"><div class="footer-layer1"><div class="footer-innerLink"><a href="#" target="_blank" title="关于魅族">关于魅族</a><img class="foot-line" src="{% static 'web/img/space.gif' %}"><a href="#" target="_blank" title="工作机会">工作机会</a><img class="foot-line" src="{% static 'web/img/space.gif' %}"><a href="#" target="_blank" title="联系我们">联系我们</a><img class="foot-line" src="{% static 'web/img/space.gif' %}"><a href="#" target="_blank" title="法律声明">法律声明</a><img class="foot-line" src="{% static 'web/img/space.gif' %}"><div href="javascript:void(0);" id="globalName" class="footer-language" title="简体中文">简体中文 <div id="globalContainer" class="footer-language_menu"><a href="#" id="i18n-link" title="English" class="ClobalItem">English</a></div></div></div><div class="footer-service"><span class="service-label">客服热线</span><span class="service-num">400-888-6666</span><a id="service-online" class="service-online" href="javascript:void(0);" title="在线客服">在线客服</a></div><div class="footer-outerLink"><a class="footer-sinaMblog" href="#" target="_blank"><i class="i_icon"></i></a><a id="footer-weChat" class="footer-weChat" href="javascript:void(0);" target="_blank"><i class="i_icon"></i></a><a class="footer-qzone" href="#" target="_blank"><i class="i_icon"></i></a></div></div><div class="clear"></div><div id="flymeCopyright" class="copyrightWrap"><div class="copyrightInner"><span>©2018 Meizu Telecom Equipment Co., Ltd. All rights reserved.</span><a href="#" class="linkAGray" target="_blank">备案号: 京ICP备123456789号-4</a><a href="#" class="linkAGray" target="_blank">经营许可证编号: 京A1-20280198</a><a target="_blank" href="#" class="linkAGray">营业执照</a></div></div></div></div><!-- 底部区域 E --><script type="text/javascript">//nLogin();
</script>
</body>
</html>
11. 项目实战前台之商品展示
- 本节将实现商城项目前台:分类导航、商品列表和商品详情的功能实现,关于商城首页的商品信息展示将会在项目的后期完成。
- 分类导航:将商品的一级类别信息作为页面的导航链接信息显示
- 商品列表:在
/list
或/list/页号
请求中分类分页展示商品信息
- 商品详情:在
/detail/gid号
请求中展示指定商品id号的商品信息
- 商城首页:输出部分最新商品、热卖商品、推荐商品或点击量最高的信息,由于目前数据信息不完善,故后期完成。
(1). 项目urls路由信息配置
- 在数据库
shopdb
中已存在数据表goods
和type
,并且内有测试数据。 - 在common应用目录中的
myobject/common/models.py
模型文件中,已存在Goods
和Types
模型类的定义。 - 打开根路由文件:myobject/web/urls.py路由文件,编辑路由配置信息
from django.conf.urls import urlfrom web.views import indexurlpatterns = [#网站前台url(r'^$',index.index,name="index"), #首页url(r'^list$',index.lists,name="list"), #商品列表展示#url(r'^list/(?P<pIndex>[0-9]+)$',index.lists,name="list"), #分页商品列表展示url(r'^detail/(?P<gid>[0-9]+)$',index.detail,name="detail"), #商品详情# 会员及个人中心等路由配置url(r'^login$', index.login, name="login"),url(r'^dologin$', index.dologin, name="dologin"),url(r'^logout$', index.logout, name="logout"),]
(2). 编辑视图文件
- 新建视图文件:myobject/web/views/index.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from django.core.paginator import Paginatorfrom common.models import Users,Types,Goods# 公共信息加载
def loadinfo(request):'''公共信息加载'''context = {}lists = Types.objects.filter(pid=0)context['typelist'] = listsreturn context# =============商品展示========================
def index(request):'''项目前台首页'''context = loadinfo(request)return render(request,"web/index.html",context)def lists(request,pIndex=1):'''商品列表页(搜索&分页)'''context = loadinfo(request)#获取商品信息查询对象mod = Goods.objectsmywhere=[] #定义一个用于存放搜索条件列表#判断添加搜索条件tid = int(request.GET.get('tid',0))if tid > 0:list = mod.filter(typeid__in=Types.objects.only('id').filter(pid=tid))mywhere.append("tid="+str(tid))else:list = mod.filter()#获取、判断并封装关keyword键搜索kw = request.GET.get("keyword",None)if kw:# 查询商品名中只要含有关键字的都可以list = list.filter(goods__contains=kw)mywhere.append("keyword="+kw)#执行分页处理pIndex = int(pIndex)page = Paginator(list,5) #以5条每页创建分页对象maxpages = page.num_pages #最大页数#判断页数是否越界if pIndex > maxpages:pIndex = maxpagesif pIndex < 1:pIndex = 1list2 = page.page(pIndex) #当前页数据plist = page.page_range #页码数列表#封装信息加载模板输出context['goodslist'] = list2context['plist'] = plistcontext['pIndex'] = pIndexcontext['maxpages'] = maxpagescontext['mywhere'] = mywherecontext['tid'] = int(tid)return render(request,"web/list.html",context)def detail(request,gid):'''商品详情页'''context = loadinfo(request)#加载商品详情信息ob = Goods.objects.get(id=gid)ob.clicknum += 1 # 点击量加1ob.save()context['goods'] = obreturn render(request,"web/detail.html",context)# ==============前台会员登录====================
# 略(上节中已编写)... ...
(3). 编写模板文件
- 3.1. 打开父类模板:/templates/web/base.html ,编辑导航栏代码
...<ul class="nav navbar-nav navbar-right layout-header-nav clearfix"><li class="layout-header-nav-item"><a href="{% url 'index' %}" class="layout-header-nav-link">网站首页</a><p class="line-top hidden-xs"></p></li><li class="layout-header-nav-item"><a href="{% url 'list' %}" class="layout-header-nav-link">全部商品</a></li>{% for type in typelist %}<li class="layout-header-nav-item"><a href="{% url 'list' %}?tid={{ type.id }}" class="layout-header-nav-link">{{ type.name }}</a></li>{% endfor %}<li class="layout-header-nav-item"><a href="#" class="layout-header-nav-link">社区</a></li> </ul> ...
- 3.2. 商品列表信息显示模板:/templates/web/list.html
...<!-- 商品列表 --><div class="goods-list"><div class="row">{% for goods in goodslist %}<div class="col-md-3 col-sm-6 col-xs-6"><div class="gl-item"><div class="compare-btn-list" ><i class="iconfont icon-duibi compare-duibi"></i><span class="hidden-xs hidden-sm">对比</span></div><div class="gl-item-wrap"><!-- Tab panes --><div class="tab-content"><div role="tabpanel" class="tab-pane active mod-pic" id="list-p1"><a href="{% url 'detail' goods.id %}"><img class="lazy j-modProduct" src="/static/goods/m_{{ goods.picname }}" width="220" height="220"></a></div></div><!-- Nav tabs --><div class="item-slide j-pro-wrap hidden-xs hidden-sm"><ul class="nav nav-tabs " role="tablist"><li role="presentation" class="active"><a href="#list-p1" aria-controls="list-p1" role="tab" data-toggle="tab"><img class="lazy" src="/static/goods/s_{{ goods.picname }}" style="display: inline;" width="40" height="40"></a></li></ul></div><div class="slide-btn j-modBtns" style="display: none;"><span class="prev iconfont disabled"></span><span class="next iconfont"></span></div><h2>{{ goods.goods}}</h2><h3 class="red" title="双11促销:满500,减100!">双11促销:满500,减100!</h3><dd class="mod-price"><span>¥</span><span class="vm-price">{{ goods.price }}</span><span class="vm-start">起</span></dd></div></div></div>{% endfor %}</div></div><!-- 商品列表 --><nav aria-label="Page navigation" class="text-center"><ul class="pagination"><li><a href="{% url 'list' pIndex|add:-1 %}?{{ mywhere|join:'&' }}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>{% for p in plist %}<li {% if pIndex == p %}class="active"{% endif %}><a href="{% url 'list' p %}?{{ mywhere|join:'&' }}">{{p}}</a></li>{% endfor %}<li><a href="{% url 'list' pIndex|add:1 %}?{{ mywhere|join:'&' }}" aria-label="Next"><span aria-hidden="true">»</span></a></li></ul></nav>
...
- 3.3. 商品详情信息显示模板:/templates/web/detail.html
在详情模板中输出部分商品信息即可
12. 项目实战前台之购物车实战
- 本节将实现商城项目前台的购物车管理模块:添加、浏览、删除、修改和清空等购物车操作。
(1). 开发前的准备工作:
- 在数据库
shopdb
中已存在数据表goods
,并且内有测试数据。 - 默认开启了session,并且执行了数据迁移,数据库中已存在
django_session
表。 - 在common应用目录中的
myobject/common/models.py
模型文件中,已存在Goods
模型类的定义。 - 并且在
Goods
模型类中已经定义了toDict(self)
方法:
# 注意:返回此商品的字典格式def toDict(self):return {'id':self.id,'typeid':self.typeid,'goods':self.goods,'company':self.company,'price':self.price,'picname':self.picname,'store':self.store,'num':self.num,'clicknum':self.clicknum,'state':self.state}
- 在商品详情页中处理
立即购买
按钮,完成向添加购物车操作的传值和跳转:
<form action="{% url 'cart_add' goods.id %}" method="post">{% csrf_token %}<div class="property-buy"><p class="vm-message" id="J_message"></p><dl class="property-buy-quantity"><dt class="vm-metatit">数<span class="s-space"></span><span class="s-space"></span>量:</dt><dd class="clearfix"><div class="mod-control"><a title="减少" href="javascript:;" class="vm-minus disabled">-</a><input value="1" name="m" id="J_quantity" data-max="5" type="text"><a title="增加" href="javascript:;" class="vm-plus">+</a></div></dd></dl><div class="property-buy-action"><button data-mtype="store_de_buy" type="submit" id="J_btnBuy" class="btn btn-danger btn-lg mr20">立即购买</button><a data-mtype="store_de_cart" href="javascript:void(0);" id="J_btnAddCart" class="btn btn-primary btn-lg hide" style="display:inline-block;"><i></i>加入购物车</a><span class="vm-service" id="J_panicBuyingWrap"></span></div></div></form>
(2). 项目urls路由信息配置
- 打开根路由文件:myobject/web/urls.py路由文件,编辑路由配置信息:
from django.conf.urls import urlfrom web.views import index,carturlpatterns = [#网站前台# ... ...# 会员及个人中心等路由配置# ... ...# 购物车路由url(r'^cart$', cart.index,name='cart_index'), #浏览购物车url(r'^cart/add/(?P<gid>[0-9]+)$', cart.add,name='cart_add'), #添加购物车url(r'^cart/del/(?P<gid>[0-9]+)$', cart.delete,name='cart_del'), #从购物车中删除一个商品url(r'^cart/clear$', cart.clear,name='cart_clear'), #清空购物车url(r'^cart/change$', cart.change,name='cart_change'), #更改购物车中商品数量]
(3). 编辑视图文件
- 新建视图文件:myobject/web/views/cart.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Goods,Types# 公共信息加载
def loadinfo(request):'''公共信息加载'''context = {}lists = Types.objects.filter(pid=0)context['typelist'] = listsreturn contextdef index(request):'''浏览购物车'''context = loadinfo(request)if 'shoplist' not in request.session:request.session['shoplist']={}return render(request,"web/cart.html",context)def add(request,gid):'''在购物车中放入商品信息'''#获取要放入购物车中的商品信息goods = Goods.objects.get(id=gid)shop = goods.toDict();shop['m'] = int(request.POST.get('m',1)) #添加一个购买量属性m#从session获取购物车信息,没有默认空字典shoplist = request.session.get('shoplist',{})#判断此商品是否在购物车中if gid in shoplist:#商品数量加shoplist[gid]['m']+=shop['m']else:#新商品添加shoplist[gid]=shop#将购物车信息放回到sessionrequest.session['shoplist'] = shoplist#重定向到浏览购物车页return redirect(reverse('cart_index'))#return render(request,"web/cart.html")def delete(request,gid):'''删除一个商品'''shoplist = request.session['shoplist']del shoplist[gid]request.session['shoplist'] = shoplistreturn redirect(reverse('cart_index'))def clear(request):'''清空购物车'''context = loadinfo(request)request.session['shoplist'] = {}return render(request,"web/cart.html",context)def change(request):'''更改购物车中的商品信息'''#context = loadinfo(request)shoplist = request.session['shoplist']#获取信息shopid = request.GET.get('gid','0')num = int(request.GET['num'])if num<1:num = 1shoplist[shopid]['m'] = num #更改商品数量request.session['shoplist'] = shoplistreturn redirect(reverse('cart_index'))#return render(request,"web/cart.html",context)
(4). 编写模板文件
- 4.1. 打开父类模板:/templates/web/base.html ,编辑导航栏代码
...<li class="layout-header-service-item layout-header-service-cart" id="layoutHeaderCart"><a class="layout-header-service-link" href="{% url 'cart_index' %}" data-mtype="wmz_public_yt_cart"><i class="glyphicon glyphicon-shopping-cart"></i><span class="layout-header-service-cart-num">{{ request.session.shoplist|length}}</span></a></li>...
- 4.2. 购物车页面信息显示模板:/templates/web/cart.html
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/cart.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/cart-app.css' %}">
{% endblock %}{% block mainbody %}
<div class="mainbody cart" style="margin-top: 80px;"><div class="container"><!-- 购物车详情头 --><table class="cart-header"><tbody><tr><td class="cart-col-select col-md-3 col-xs-3 col-sm-3"><div class="cart-select-all JSelectAll"><div class="mz-checkbox"></div><span class="cart-select-title">全选</span></div></td><td class="cart-col-name col-md-3 hidden-xs hidden-sm">商品</td><td class="cart-col-price col-md-2 hidden-xs hidden-sm">单价(元)</td><td class="cart-col-number col-md-2 hidden-xs hidden-sm">数量</td><td class="cart-col-total col-md-1 hidden-xs hidden-sm">小计(元)</td><td class="cart-col-ctrl col-md-1 hidden-xs hidden-sm">操作</td></tr></tbody></table><!-- 购物车详情头 E--><!-- 购物清单信息列表 --><div class="cart-merchant-list"><div class="cart-merchant"><table class="cart-merchant-body"><tbody>{% for shop in request.session.shoplist.values %}<tr class="cart-product"><td class="cart-col-select col-md-3 col-xs-4 col-sm-4"> <div class="mz-checkbox" gid="{{shop.id}}" price="{% widthratio shop.price 1 shop.m %}"></div> <a href="{% url 'detail' shop.id %}" class="cart-product-link" target="_blank"><img src="/static/goods/s_{{ shop.picname }}" class="cart-product-img" alt="{{ shop.goods }}" width="50"></a></td><td class="cart-col-name col-md-3 col-xs-8 col-sm-8"><a href="{% url 'detail' shop.id %}" class="cart-product-link" target="_blank"><p>{{ shop.goods }}</p></a><p class=""><span class="cart-product-price">{{ shop.price }}</span></p><div class="cart-col-number"><div class="cart-product-number-adder"><p class="cart-product-number-max show"></p><div class="mz-adder"><button class="mz-adder-subtract disabled"></button><div class="mz-adder-num"><input class="mz-adder-input" value="1" type="text"></div><button class="mz-adder-add"></button></div></div></div></td><td class="cart-col-price col-md-2 hidden-xs hidden-sm"><p><span class="cart-product-price">{{ shop.price}}</span></p></td><td class="cart-col-number col-md-2 hidden-xs hidden-sm"><div class="cart-product-number-adder"><p class="cart-product-number-max show"></p><div class="mz-adder"><button onclick="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num={{shop.m|add:-1}}'" class="mz-adder-subtract"></button><div class="mz-adder-num"><input class="mz-adder-input" value="{{ shop.m }}" onblur="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num='+this.value" type="text"></div><button onclick="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num={{shop.m|add:1}}'" class="mz-adder-add"></button></div></div></td><td class="cart-col-total col-md-1 hidden-xs hidden-sm"><span class="cart-product-price total">{% widthratio shop.price 1 shop.m %}</span></td><td class="cart-col-ctrl col-md-1 hidden-xs hidden-sm"><a href="{% url 'cart_del' shop.id %}" title="删除"><div class="cart-product-remove"><span class="glyphicon glyphicon-remove"></span></div></a></td></tr>{% endfor %}</tbody></table></div></div><!-- 购物清单信息列表 E--></div><!-- 结算详情 --><div class="cart-footer" id="cartFooter"><div class="container"><div class="cart-footer-left col-md-6 col-xs-4 col-sm-4"><div class="cart-select-all JSelectAll" data-mdesc="全选按钮" data-mtype="store_cart_all"><div class="mz-checkbox"></div><span class="cart-select-title">全选</span></div><!-- <span class="cart-remove-selected" id="removeSelected">删除选中的商品</span> --><span class="cart-footer-count">共<span class="cart-footer-num" id="totalCount"></span>件商品</span><div class="mz-btn btn-danger" onclick="window.location='{% url 'cart_clear' %}'" id="cartSubmit">清空购物车</div></div><div class="cart-footer-right col-md-5 col-md-offset-1 col-sm-offset-2 col-xs-8 col-sm-6"><span class="cart-footer-sum"><span class="cart-footer-text">已优惠</span><span class="cart-footer-num red" id="totalDiscount">0.00</span><span class="cart-footer-text">元, 合计(不含运费):</span><span class="cart-footer-total" id="totalPrice">0.0</span></span><div onclick="window.location='/orders/add?ids='+loadTotal().join(',')" class="mz-btn btn-success" id="cartSubmit">去结算</div></div></div></div><!-- 结算详情 E-->
</div>
{% endblock %}{% block myjs %}//全选allSelect();//登录图片鼠标经过//topLogin();//商品数量加减//cartAddMin()//loadTotal();var gidlist = [];
{% endblock %}
13. 项目实战前台之下单操作
- 本节将实现商城项目中会员下单操作模块:填写收货地址、确认订单信息和执行下单等操作。
(1). 开发前的准备工作:
- 在数据库 shopdb 中已存在订单表orders和订单详情表detail。
- 在执行下单操作前要确认会员必须在登录后状态(使用中间件验证)。
#在myobject/common/shopmiddleware.py中的__call__()方法中条件如下代码
# ... ... # 网站前台登录用户判断(订单操作和会员中心操作需登录)
if re.match("^/orders",path) or re.match("^/vip",path):# 判断当前用户是否没有登录if "vipuser" not in request.session:# 执行登录界面跳转return redirect(reverse('login'))response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
- 在common应用目录中的myobject/common/models.py 模型文件中,已存在Orders和Detail模型类的定义。
# ... ...# 订单模型
class Orders(models.Model):uid = models.IntegerField()linkman = models.CharField(max_length=32)address = models.CharField(max_length=255)code = models.CharField(max_length=6)phone = models.CharField(max_length=16)addtime = models.DateTimeField(default=datetime.now)total = models.FloatField()state = models.IntegerField()class Meta:db_table = "orders" # 更改表名#订单详情模型
class Detail(models.Model):orderid = models.IntegerField()goodsid = models.IntegerField()name = models.CharField(max_length=32)price = models.FloatField()num = models.IntegerField()class Meta:db_table = "detail" # 更改表名
在商品购物车页中处理下单按钮,完成向下单操作界面的传值和跳转:
首先将实现准备的
topNav.js
替换掉项目中的web/js/topNav.js
<div onclick="window.location='/orders/add?ids='+loadTotal().join(',')" class="mz-btn btn-success" id="cartSubmit">去结算</div>
(2). 项目urls路由信息配置
- 打开根路由文件:myobject/web/urls.py路由文件,编辑路由配置信息:
from django.conf.urls import urlfrom web.views import index,cart,ordersurlpatterns = [#网站前台# ... ...# 会员及个人中心等路由配置# ... ...# 购物车路由# ... ...# 订单处理url(r'^orders/add$', orders.add,name='orders_add'), #订单的表单页url(r'^orders/confirm$', orders.confirm,name='orders_confirm'), #订单确认页url(r'^orders/insert$', orders.insert,name='orders_insert'), #执行订单添加操作
]
(3). 编辑视图文件
- 新建视图文件:myobject/web/views/orders.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Goods,Types,Orders,Detail
from datetime import datetime# 公共信息加载
def loadinfo(request):'''公共信息加载'''context = {}lists = Types.objects.filter(pid=0)context['typelist'] = listsreturn contextdef add(request):'''下订单第一步:订单表单'''context = loadinfo(request)# 获取要结算商品的id号ids = request.GET.get("ids",'')if len(ids) == 0:context = {"info":"请选择要结算的商品!"}return render(request,"web/ordersinfo.html",context)gidlist = ids.split(',')# 从购物车获取要结算所有商品,并放入到orderslist中,并且累计总金额shoplist = request.session['shoplist']orderslist = {}total = 0.0for gid in gidlist:orderslist[gid] = shoplist[gid]total += shoplist[gid]['price']*shoplist[gid]['m']# 将这些信息放入到session中request.session['orderslist'] = orderslistrequest.session['total'] = totalreturn render(request,"web/ordersadd.html",context)def confirm(request):context = loadinfo(request)return render(request,"web/ordersconfirm.html",context)def insert(request):context = loadinfo(request)try:# 执行订单信息添加操作od = Orders()od.uid = request.session['vipuser']['id'] #当前登录者的id号od.linkman = request.POST.get('linkman')od.address = request.POST.get('address')od.code = request.POST.get('code')od.phone = request.POST.get('phone')od.addtime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")od.total = request.session['total']od.state = 0od.save()# 执行订单详情添加orderslist = request.session['orderslist']shoplist = request.session['shoplist']for shop in orderslist.values():del shoplist[str(shop['id'])]ov = Detail()ov.orderid = od.idov.goodsid = shop['id']ov.name = shop['goods']ov.price = shop['price']ov.num = shop['m']ov.save()del request.session['orderslist'] del request.session['total']request.session['shoplist'] = shoplistcontext = {"info":"订单添加成功!订单号:"+str(od.id)}return render(request,"web/ordersinfo.html",context)except Exception as err:print(err)context = {"info":"订单添加失败,请稍后再试!"}return render(request,"web/ordersinfo.html",context)
(4). 编写模板文件
- 4.1. 打开购物车模板:/templates/web/cart.html ,编辑js代码,替换topNav.js文件
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/cart.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/cart-app.css' %}">
{% endblock %}{% block mainbody %}
<div class="mainbody cart" style="margin-top: 80px;"><div class="container"><!-- 购物车详情头 --><table class="cart-header"><tbody><tr><td class="cart-col-select col-md-3 col-xs-3 col-sm-3"><div class="cart-select-all JSelectAll"><div class="mz-checkbox"></div><span class="cart-select-title">全选</span></div></td><td class="cart-col-name col-md-3 hidden-xs hidden-sm">商品</td><td class="cart-col-price col-md-2 hidden-xs hidden-sm">单价(元)</td><td class="cart-col-number col-md-2 hidden-xs hidden-sm">数量</td><td class="cart-col-total col-md-1 hidden-xs hidden-sm">小计(元)</td><td class="cart-col-ctrl col-md-1 hidden-xs hidden-sm">操作</td></tr></tbody></table><!-- 购物车详情头 E--><!-- 购物清单信息列表 --><div class="cart-merchant-list"><div class="cart-merchant"><table class="cart-merchant-body"><tbody>{% for shop in request.session.shoplist.values %}<tr class="cart-product"><td class="cart-col-select col-md-3 col-xs-4 col-sm-4"> <div class="mz-checkbox" gid="{{shop.id}}" price="{% widthratio shop.price 1 shop.m %}"></div> <a href="{% url 'detail' shop.id %}" class="cart-product-link" target="_blank"><img src="/static/goods/s_{{ shop.picname }}" class="cart-product-img" alt="{{ shop.goods }}" width="50"></a></td><td class="cart-col-name col-md-3 col-xs-8 col-sm-8"><a href="{% url 'detail' shop.id %}" class="cart-product-link" target="_blank"><p>{{ shop.goods }}</p></a><p class=""><span class="cart-product-price">{{ shop.price }}</span></p><div class="cart-col-number"><div class="cart-product-number-adder"><p class="cart-product-number-max show"></p><div class="mz-adder"><button class="mz-adder-subtract disabled"></button><div class="mz-adder-num"><input class="mz-adder-input" value="1" type="text"></div><button class="mz-adder-add"></button></div></div></div></td><td class="cart-col-price col-md-2 hidden-xs hidden-sm"><p><span class="cart-product-price">{{ shop.price}}</span></p></td><td class="cart-col-number col-md-2 hidden-xs hidden-sm"><div class="cart-product-number-adder"><p class="cart-product-number-max show"></p><div class="mz-adder"><button onclick="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num={{shop.m|add:-1}}'" class="mz-adder-subtract"></button><div class="mz-adder-num"><input class="mz-adder-input" value="{{ shop.m }}" onblur="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num='+this.value" type="text"></div><button onclick="window.location='{% url 'cart_change' %}?gid={{shop.id}}&num={{shop.m|add:1}}'" class="mz-adder-add"></button></div></div></td><td class="cart-col-total col-md-1 hidden-xs hidden-sm"><span class="cart-product-price total">{% widthratio shop.price 1 shop.m %}</span></td><td class="cart-col-ctrl col-md-1 hidden-xs hidden-sm"><a href="{% url 'cart_del' shop.id %}" title="删除"><div class="cart-product-remove"><span class="glyphicon glyphicon-remove"></span></div></a></td></tr>{% endfor %}</tbody></table></div></div><!-- 购物清单信息列表 E--></div><!-- 结算详情 --><div class="cart-footer" id="cartFooter"><div class="container"><div class="cart-footer-left col-md-6 col-xs-4 col-sm-4"><div class="cart-select-all JSelectAll" data-mdesc="全选按钮" data-mtype="store_cart_all"><div class="mz-checkbox"></div><span class="cart-select-title">全选</span></div><!-- <span class="cart-remove-selected" id="removeSelected">删除选中的商品</span> --><span class="cart-footer-count">共<span class="cart-footer-num" id="totalCount"></span>件商品</span><div class="mz-btn btn-danger" onclick="window.location='{% url 'cart_clear' %}'" id="cartSubmit">清空购物车</div></div><div class="cart-footer-right col-md-5 col-md-offset-1 col-sm-offset-2 col-xs-8 col-sm-6"><span class="cart-footer-sum"><span class="cart-footer-text">已优惠</span><span class="cart-footer-num red" id="totalDiscount">0.00</span><span class="cart-footer-text">元, 合计(不含运费):</span><span class="cart-footer-total" id="totalPrice">0.0</span></span><div onclick="window.location='/orders/add?ids='+loadTotal().join(',')" class="mz-btn btn-success" id="cartSubmit">去结算</div></div></div></div><!-- 结算详情 E-->
</div>
{% endblock %}{% block myjs %}//全选allSelect();//登录图片鼠标经过//topLogin();//商品数量加减//cartAddMin()loadTotal();var gidlist = [];
{% endblock %}
- 4.2. 订单地址填写模板:/templates/web/ordersadd.html
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/cart.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/cart-app.css' %}">
{% endblock %}{% block mainbody %}
<form action="{% url 'orders_confirm' %}" method="post">
{% csrf_token %}
<div class="mainbody cart" style="margin-top: 80px;"><div class="container"><!-- 下订单的1/3步骤 --><table class="cart-header"><tbody><tr><td class="cart-col-select col-md-12">当前位置: 订单处理 > 1/3 填写收货地址:</td></tr></tbody></table><!-- 下订单的1/3步骤 E--><!-- 订单物流信息 --><div class="cart-merchant-list"><div class="cart-merchant"><table class="cart-merchant-body"><tbody><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">联系人:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" name="linkman" value="{{ request.session.vipuser.name}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">收货地址:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" name="address" value="{{ request.session.vipuser.address}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">联系电话:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" name="phone" value="{{ request.session.vipuser.phone}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">邮编:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" name="code" value="{{ request.session.vipuser.code}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">总金额:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" disabled value="{{ request.session.total }} 元" name="linkman" size="40"/></td></tr></tbody></table></div></div><!-- 订单物流信息 E--></div><!-- 操作按钮 --><div class="cart-footer" id="cartFooter"><div class="container"><div class="cart-footer-right col-md-12" style="text-align:center"><div onclick="window.history.go(-1)" class="mz-btn btn-success" id="cartSubmit">返回</div><button type="submit" class="mz-btn btn-success" id="cartSubmit">下一步</button></div></div></div><!-- 操作按钮 E-->
</div></form>
{% endblock %}
- 4.3. 订单确认模板:/templates/web/ordersconfirm.html
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/cart.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/cart-app.css' %}">
{% endblock %}{% block mainbody %}
<form action="{% url 'orders_insert' %}" method="post">
{% csrf_token %}
<div class="mainbody cart" style="margin-top: 80px;padding-bottom:5px;"><div class="container"><!-- 下订单的2/3步骤 --><table class="cart-header"><tbody><tr><td class="cart-col-select col-md-12">当前位置: 订单处理 > 2/3 确认订单信息:</td></tr></tbody></table><!-- 下订单的2/3步骤 E--><!-- 订单通信信息 --><div class="cart-merchant-list"><div class="cart-merchant"><table class="cart-merchant-body"><tbody><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">联系人:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input readonly type="text" name="linkman" value="{{ request.POST.linkman}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">收货地址:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input readonly type="text" name="address" value="{{ request.POST.address}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">联系电话:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input readonly type="text" name="phone" value="{{ request.POST.phone}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">邮编:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input readonly type="text" name="code" value="{{ request.POST.code}}" size="40"/></td></tr><tr class="cart-product" style="height:60px;border:none;"><td class="cart-col-select col-md-2 col-xs-3 col-sm-3" style="text-align: right;">总金额:</td><td class="cart-col-name col-md-3 col-xs-4 col-sm-4"><input type="text" disabled value="{{ request.session.total }} 元" name="linkman" size="40"/></td></tr></tbody></table></div></div><!-- 订单通信信息 E--></div><!-- 操作按钮 --><div class="cart-footer" id="cartFooter"><div class="container"><div class="cart-footer-right col-md-12" style="text-align:center"><div onclick="window.history.go(-1)" class="mz-btn btn-success" id="cartSubmit">返回修改</div><button type="submit" class="mz-btn btn-success" id="cartSubmit">确认下单</button></div></div></div><!-- 操作按钮 E-->
</div></form><div class="mainbody cart" style="padding-bottom:15px;"><div class="container"><!-- 订单信息头 --><table class="cart-header"><tbody><tr><td class="cart-col-name col-md-3 hidden-xs hidden-sm">商品</td><td class="cart-col-name col-md-3 hidden-xs hidden-sm">图片</td><td class="cart-col-price col-md-2 hidden-xs hidden-sm">单价(元)</td><td class="cart-col-number col-md-2 hidden-xs hidden-sm">数量</td><td class="cart-col-total col-md-1 hidden-xs hidden-sm">小计(元)</td></tr></tbody></table><!-- 订单信息头 E--><!-- 订单确认信息 --><div class="cart-merchant-list"><div class="cart-merchant"><table class="cart-merchant-body"><tbody>{% for shop in request.session.orderslist.values %}<tr class="cart-product" style="height:100px;"><td class="cart-col-name col-md-3 hidden-xs hidden-sm"><p><div class="mz-adder-num">{{ shop.goods }}</div></p></td><td class="cart-col-name col-md-3 hidden-xs hidden-sm"><p><div class="mz-adder-num"><img src="/static/goods/s_{{ shop.picname }}" alt="{{ shop.goods }}" width="50"></div></p></td><td class="cart-col-price col-md-2 hidden-xs hidden-sm"><p><span class="cart-product-price">{{ shop.price}}</span></p></td><td class="cart-col-number col-md-2 hidden-xs hidden-sm"><p><div class="mz-adder-num">{{ shop.m }}</div></p></td><td class="cart-col-total col-md-1 hidden-xs hidden-sm"><span class="cart-product-price total">{% widthratio shop.price 1 shop.m %}</span></td></tr>{% endfor %}</tbody></table></div></div><!-- 订单确认信息 E--></div>
</div>
{% endblock %}
- 4.4. 订单信息提示模板:/templates/web/ordersinfo.html
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/cart.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/cart-app.css' %}">
{% endblock %}{% block mainbody %}
<div class="mainbody cart" style="margin-top: 80px;"><div class="container"><!-- 下订单的3/3步骤 --><table class="cart-header"><tbody><tr><td class="cart-col-select col-md-12">当前位置: 订单处理 > 3/3 订单完成:</td></tr></tbody></table><!-- 下订单的3/3步骤 E--><!-- 下订单提示信息 --><div class="cart-merchant-list"><div class="cart-merchant text-center" style="font-size:30px;color:#fc0;line-height:100px;">{{ info }}</div></div><!-- 下订单提示信息 E--></div><!-- 操作按钮 --><div class="cart-footer" id="cartFooter"><div class="container"><div class="cart-footer-right col-md-12" style="text-align:center"><div onclick="window.history.go(-1)" class="mz-btn btn-success" id="cartSubmit">返回</div><a href="{% url 'index' %}" class="mz-btn btn-success">首页</a></div></div></div><!-- 操作按钮 E-->
</div>
{% endblock %}
14. 项目实战前台之个人中心
(1). 个人中心简介:
- 会员个人中心模块:浏览个人信息、修改个人信息、密码重置、查看个人订单和处理订单等处理操作。
- 由于个人中心的信息操作大部分都是在网站后台锻炼过,所以本节重点讲解个人中心的订单管理。
(2). 项目urls路由信息配置
- 打开根路由文件:myobject/web/urls.py路由文件,编辑路由配置信息:
from django.conf.urls import urlfrom web.views import index,cart,orders,vipurlpatterns = [#网站前台# ... ...# 会员及个人中心等路由配置# ... ...# 购物车路由# ... ...# 订单处理# ... ...# 会员中心url(r'^vip/orders$', vip.viporders,name='vip_orders'), #会员中心我的订单url(r'^vip/odstate$', vip.odstate,name='vip_odstate'), #修改订单状态(确认收货)#url(r'^vip/info$', vip.info,name='vip_info'), #会员中心的个人信息#url(r'^vip/update$', vip.update,name='vip_update'), #执行修改会员信息#url(r'^vip/resetps$', vip.resetps,name='vip_resetps'), #重置密码表单#url(r'^vip/doresetps$', vip.doresetps,name='vip_doresetps'), #执行重置密码
]
(3). 编辑视图文件
- 新建视图文件:myobject/web/views/vip.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from django.core.urlresolvers import reversefrom common.models import Users,Goods,Types,Orders,Detail# 公共信息加载
def loadinfo(request):'''公共信息加载'''context = {}lists = Types.objects.filter(pid=0)context['typelist'] = listsreturn context# 我的订单
def viporders(request):'''当前用户订单'''context = loadinfo(request)# 获取当前用户的所有订单信息odlist = Orders.objects.filter(uid=request.session['vipuser']['id'])# 遍历当前用户的所有订单,添加他的订单详情for od in odlist:delist = Detail.objects.filter(orderid=od.id)# 遍历每个商品详情,从Goods中获取对应的图片for og in delist:og.picname = Goods.objects.only('picname').get(id=og.goodsid).picnameod.detaillist = delist# 将整理好的订单信息放置到模板遍历中context['orderslist'] = odlistreturn render(request,"web/viporders.html",context)def odstate(request):''' 修改订单状态 '''try:oid = request.GET.get("oid",'0')ob = Orders.objects.get(id=oid)ob.state = request.GET['state']ob.save()return redirect(reverse('vip_orders'))except Exception as err:print(err)return HttpResponse("订单处理失败!")
(4). 编写模板文件
- 4.1. 新建订单信息显示模板:/templates/web/viporders.html。
{% extends "web/base.html" %}
{% load static from staticfiles %}{% block mylink %}<link rel="stylesheet" type="text/css" href="{% static 'web/css/order.css' %}"><link rel="stylesheet" type="text/css" href="{% static 'web/css/order-app.css' %}">
{% endblock %}{% block mainbody %}
<div class="mainbody order"><div class="container"><!-- 面包屑导航 --><div class="crumbs col-xs-12 col-sm-12"><ol class="breadcrumb"><li class="hidden-xs hidden-sm"><a href="index.html">首页</a></li><li class="hidden-xs hidden-sm"><a href="member.html">我的商城</a></li><li class="active">我的订单</li></ol></div><!-- 面包屑导航 E--><div class="main clearfix"><!-- 左侧导航 --><div class="left-nav f-fl col-md-4 hidden-xs hidden-sm"><div class="nav-main"><a href="javascript:;" class="type-title"><span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>订单中心</a><a href="order.html" class="ml active" >我的订单</a><a href="#" class="ml " >我的回购单</a><a href="#" class="ml " >我的意外保</a><a href="javascript:;" class="type-title"><span class="glyphicon glyphicon-user" aria-hidden="true"></span>个人中心</a><a href="/#" class="ml " >地址管理</a><a href="#" class="ml " >我的收藏</a><a href="#" class="ml " >消息提醒</a><a href="#" class="ml " >建议反馈</a></div></div><!-- 左侧导航 E--><!-- 右侧内容展示 --><div class="right-content f-fr col-md-8 col-xs-12 col-sm-12"><div class="order-main"><div class="type-tab-btn"><a href="javascript:;" class="allOrder active col-20" data-type="-1">全部订单</a><i class="line hidden-xs hidden-sm">|</i><a class="waitPay col-20" href="javascript:;" data-type="0">待付款<span class="amount _actAmount"></span></a><i class="line hidden-xs hidden-sm">|</i><a class="waitDeliver col-20" href="javascript:;" data-type="1">待发货</a><i class="line hidden-xs hidden-sm">|</i><a class="hasDeliver col-20" href="javascript:;" data-type="2">已发货</a><i class="line hidden-xs hidden-sm">|</i><a class="other col-20" href="javascript:;" data-type="99">其他</a></div><div class="list-head hidden-xs hidden-sm"><ul class="clearfix"><li class="w50"><select id="checkType" class="check-type"><option value="0">近三个月的订单</option><option value="1">全部订单</option></select>订单明细</li><li class="w125">售后</li><li class="w125">金额</li><li class="w125">状态</li><li class="w125">操作</li></ul></div><div id="tableList" class="type-contain ui-load-container"><!-- 每个订单信息 -->{% for orders in orderslist %}<div class="ui-load-content" style="margin-top: 20px"><table class="orderItem"><tbody><tr class="trHead hidden-xs hidden-sm"><td colspan="4" class="title clearfix"><div class="f-fl">订单号:<span class="time">201700{{ orders.id }}</span>收货人:<span class="orderNumber">{{ orders.linkman }}</span>收货地址:<span class="orderNumber">{{ orders.address }}</span>联系电话:<span class="orderNumber">{{ orders.phone }}</span></div></td></tr><tr class="list-box b-l b-r b-b"><td class="list b-r j-iamCart"><div class="cart-wrap j-CartWrap"><div class="shop j-shop j-amLight">{% for detail in orders.detaillist %}<div class="item b-t clearfix j-item j-iamMain" style="height:110px;"><a class="productDetail nameWidth col-xs-4 col-sm-4" href="{% url 'detail' detail.goodsid %}" target="_blank"><img src="/static/goods/s_{{detail.picname}}" style="width:75px;height:75px" class="f-fl"/></a><div class="describe f-fl col-xs-8 col-sm-8"><div class="vertic clearfix"><span class="clearfix"><a class="productDetail nameWidth" href="#" target="_blank"><i>{{ detail.name }}</i></a><p>¥{{ detail.price}}×{{ detail.num}}</p></span></div></div></div>{% endfor %}</div></div></td><td class="b-r w125 center price b-t hidden-xs hidden-sm"><div class="priceDiv">¥ {{ orders.total }} 元</div></td><td class="b-r w125 center state b-t hidden-xs hidden-sm"><div class="stateDiv"><div>{% if orders.state == 0 %}新订单 <br/><br/><br/>【<a href="{% url 'vip_odstate' %}?oid={{orders.id}}&state=3">撤销订单</a>】{% elif orders.state == 1 %}已发货 <br/><br/>【<a href="{% url 'vip_odstate' %}?oid={{orders.id}}&state=2">确认收货</a>】{% elif orders.state == 2 %}已完成{% elif orders.state == 3 %}无效订单{% else %}未知{% endif %}</div></div></td><td class="w125 center opreat b-t hidden-xs hidden-sm"><ul><li class="more"><a href="#" target="_blank">查看详情</a></li></ul></td></tr></tbody></table></div>{% endfor %}<!-- 每个订单信息 end--></div></div></div></div></div>
</div>
<!-- 主内容区域 E-->
{% endblock %}
15. 项目实战后台之订单处理
(1). 后台订单处理说明:
- 后台订单处理模块:浏览订单(搜索&分页)、查看订单详情、订单处理(确认发货,撤销订单)等处理操作。
(2). 项目urls路由信息配置
- 打开根路由文件:myobject/myadmin/urls.py路由文件,编辑路由配置信息:
from django.conf.urls import urlfrom myadmin.views import index,users,type,goods,ordersurlpatterns = [...# 订单信息管理路由url(r'^orders$', orders.index, name="myadmin_orders_index"),url(r'^orders/(?P<pIndex>[0-9]+)$', orders.index, name="myadmin_orders_index"),url(r'^orders/detail/(?P<oid>[0-9]+)$', orders.detail, name="myadmin_orders_detail"),url(r'^orders/state$',orders.state, name="myadmin_orders_state"),
]
(3). 编辑视图文件
- 新建视图文件:myobject/myadmin/views/orders.py 视图文件,并进行编辑
from django.shortcuts import render
from django.http import HttpResponse
from django.db.models import Q
from django.core.paginator import Paginatorfrom common.models import Goods,Users,Orders,Detail# Create your views here.
def index(request,pIndex=1):'''浏览信息'''#获取订单信息mod = Orders.objectsmywhere=[]# 获取、判断并封装关keyword键搜索kw = request.GET.get("keyword",None)if kw:# 查询收件人和地址中只要含有关键字的都可以list = mod.filter(Q(linkman_contains=kw) | Q(address__contains=kw))mywhere.append("keyword="+kw)else:list = mod.filter()# 获取、判断并封装订单状态state搜索条件state = request.GET.get('state','')if state != '':list = list.filter(state=state)mywhere.append("state="+state)#执行分页处理pIndex = int(pIndex)page = Paginator(list,5) #以5条每页创建分页对象maxpages = page.num_pages #最大页数#判断页数是否越界if pIndex > maxpages:pIndex = maxpagesif pIndex < 1:pIndex = 1list2 = page.page(pIndex) #当前页数据plist = page.page_range #页码数列表# 遍历订单信息并追加 下订单人姓名信息for od in list2:user = Users.objects.only('name').get(id=od.uid)od.name = user.name#封装信息加载模板输出context = {"orderslist":list2,'plist':plist,'pIndex':pIndex,'maxpages':maxpages,'mywhere':mywhere}return render(request,"myadmin/orders/index.html",context)def detail(request,oid):''' 订单详情信息 '''try:# 加载订单信息orders = Orders.objects.get(id=oid)if orders != None:user = Users.objects.only('name').get(id=orders.uid)orders.name = user.name# 加载订单详情dlist = Detail.objects.filter(orderid=oid)# 遍历每个商品详情,从Goods中获取对应的图片for og in dlist:og.picname = Goods.objects.only('picname').get(id=og.goodsid).picname# 放置模板变量,加载模板并输出context = {'orders':orders,'detaillist':dlist}return render(request,"myadmin/orders/detail.html",context)except Exception as err:print(err)context = {'info':'没有找到要修改的信息!'}return render(request,"myadmin/info.html",context)def state(request):''' 修改订单状态 '''try:oid = request.GET.get("oid",'0')ob = Orders.objects.get(id=oid)ob.state = request.GET['state']ob.save()context = {'info':'修改成功!'}except Exception as err:print(err)context = {'info':'修改失败!'}return render(request,"myadmin/info.html",context)
(4). 编写模板文件
- 4.1. 订单信息浏览显示模板:/templates/myadmin/orders/index.html。
{% extends "myadmin/base.html" %}{% block mainbody %} <h4>订单信息管理</h4><form class="form-inline" action="{% url 'myadmin_orders_index'%}" method="get"><label>关键字:</label><input type="text" name="keyword" value="{{request.GET.keyword}}" class="input-small" placeholder="收货人或地址"/><label> 状态:</label><select name="state" class="span1" style="width:100px;"><option value="">全部</option><option value="1" {% if request.GET.state == '0' %}selected{% endif %}>未发货</option><option value="1" {% if request.GET.state == '1' %}selected{% endif %}>已发货</option><option value="2" {% if request.GET.state == '2' %}selected{% endif %}>已完成</option><option value="3" {% if request.GET.state == '3' %}selected{% endif %}>已作废</option></select><button type="submit" class="btn">搜索</button><a href="{% url 'myadmin_goods_index' 1 %}" class="btn">全部</a></form><table class="table table-bordered table-striped"><thead><tr><th>订单号</th><th>下单人</th><th>收货人</th><th>收货地址</th><th>联系电话</th><th>时间</th><th>状态</th><th>操作</th></tr></thead><tbody>{% for vo in orderslist %}<tr><td>{{ vo.id }}</td><td>{{ vo.name }}</td><td>{{ vo.linkman }}</td><td>{{ vo.address }}</td><td>{{ vo.phone }}</td><td>{{ vo.addtime|date:'Y-m-d H:i:s' }}</td><td>{% if vo.state == 0 %}新订单{% elif vo.state == 1 %}已发货{% elif vo.state == 2 %}已完成{% elif vo.state == 3 %}无效订单{% else %}未知{% endif %}</td><td><a href="{% url 'myadmin_orders_detail' vo.id %}" class="view-link">查看详情</a></td></tr>{% endfor %}</tbody></table> <div class="pagination"><ul><li><a href="{% url 'myadmin_orders_index' pIndex|add:-1 %}?{{ mywhere|join:'&' }}">«</a></li>{% for p in plist %}<li {% if pIndex == p %}class="active"{% endif %}><a href="{% url 'myadmin_orders_index' p %}?{{ mywhere|join:'&' }}">{{p}}</a></li>{% endfor %}<li><a href="{% url 'myadmin_orders_index' pIndex|add:1 %}?{{ mywhere|join:'&' }}">»</a></li></ul></div>
{% endblock %}
- 4.2. 订单详情信息显示模板:/templates/myadmin/orders/detail.html。
{% extends "myadmin/base.html" %}{% block mainbody %} <h4>订单信息:</h4><table class="table table-bordered"><tr><th width="12%" style="text-align:right;background-color:#eee;">订单号:</th><td width="25%">201700{{ orders.id }}</td><th width="12%" style="text-align:right;background-color:#eee;">下单人:</th><td width="51%">{{ orders.name }}</td></tr><tr><th style="text-align:right;background-color:#eee;">收货人:</th><td>{{ orders.linkman }}</td><th style="text-align:right;background-color:#eee;">订单地址:</th><td>{{ orders.address }}</td></tr><tr><th style="text-align:right;background-color:#eee;">邮政编码:</th><td>{{ orders.code }}</td><th style="text-align:right;background-color:#eee;">下单时间:</th><td>{{ orders.addtime }}</td></tr><tr><th style="text-align:right;background-color:#eee;">总计金额:</th><td>{{ orders.total }}</td><th style="text-align:right;background-color:#eee;">订单状态:</th><td>{% if orders.state == 0 %}新订单 【<a href="{% url 'myadmin_orders_state' %}?oid={{orders.id}}&state=1">确认发货</a>】 【<a href="{% url 'myadmin_orders_state' %}?oid={{orders.id}}&state=3">订单作废</a>】{% elif orders.state == 1 %}已发货{% elif orders.state == 2 %}已完成{% elif orders.state == 3 %}无效订单{% else %}未知{% endif %}</td></tr></table><br/> <h4>订单详情信息:</h4><table class="table table-bordered table-striped"><thead><tr><th>id号</th><th>图片</th><th>商品名称</th><th>单价</th><th>数量</th><th>小计</th></tr></thead><tbody>{% for vo in detaillist %}<tr><td>{{ vo.id }}</td><td><img src="/static/goods/s_{{ vo.picname }}" width="35" /></td><td>{{ vo.name }}</td><td>{{ vo.price }}</td><td>{{ vo.num }}</td><td>{{ vo.price }}</td></tr>{% endfor %}</tbody></table><div style="text-align:center"><button onclick="window.history.back()">返回</button><button >打印订单</button></div>
{% endblock %}
16. 项目实战总结
1 本次项目完成的模块介绍:
(1). 项目中还有那些需要开发
- 网站首页:各种商品展示、轮播图片展示
- 个人中心:注册、个人信息,修改,密码重置和收藏等
- 商品详情: 商品参数、商品清单、售后服务和详情图片
- 扩展模块:会员多地址、商品多图片,商品评论、商城支付、友情链接、导航标签 … …
(2). 项目中的优化:
- 项目前台的表单验证
- 使用缓存
- … …
Published with GitBook
三、Python复习教程(重点)- 前端框架实战相关推荐
- 二、Python复习教程(重点)- 前端框架
目录导航: 文章目录 目录导航: 三.Web前端 1.1 Web前端开发介绍 1. Web网站介绍 2. 动态网站开发所需的Web构件 3. Web的工作原理 1.2 HTML基础语法 (缺) 1.3 ...
- 四、Python复习教程(重点)-爬虫框架
目录导航: 文章目录 七.Python网络爬虫基础(上) 1. Python中的正则表达式 2. 正则表达式基础语法介绍 2.1 原子 非打印字符: 通用字符: 2.2 元字符 元字符: 2.3 模式 ...
- python接口测试_Python接口自动化测试框架实战开发(一)
目录 一丶叙述 二丶接口基础知识 三丶接口测试工具 四丶Fiddler的使用 五丶unittest使用 六丶mock服务入门到实战 七丶接口自动化框架设计到开发 一丶叙述 1.项目介绍 整个项目分为四 ...
- python自动化教程_Python自动化开发实战视频课程-全新基础篇_Python教程
教程名称:Python自动化开发实战视频课程-全新基础篇 课程目录: 0001.51CTO学院-01Pythons10 day1 开课前言- _* N, R+ w/ T 0001.51CTO学院-01 ...
- python单元测试教程_Python单元测试框架unittest使用方法讲解
概述 1.测试脚手架(test fixture) 测试准备前要做的工作和测试执行完后要做的工作.包括setUp()和tearDown(). 2.测试案例(test case) 最小的测试单元. 3.测 ...
- React、Angular和Vue三种最流行的前端框架哪一个最好
这是三种最流行的工具,可以帮助开发人员构建Web应用程序.仔细阅读,看哪一个最适合您的需求. 在当今的发展世界中,技术发展非常迅速并且变化迅速,许多开发工具似乎可以解决不同的开发问题.在本次讨论中,我 ...
- python爬虫教程:Scrapy框架爬取Boss直聘网Python职位信息的源码
今天小编就为大家分享一篇关于Scrapy框架爬取Boss直聘网Python职位信息的源码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 分析 使用Crawl ...
- python基础教程:Django框架的中的setting.py文件说明详解
这篇文章主要介绍了Django框架的中的setting.py文件说明详解,这个文件包含了所有有关这个Django项目的配置信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 1.加载数据库,数据库 ...
- python爬虫scrapy框架教程_Python爬虫教程-30-Scrapy 爬虫框架介绍
从本篇开始学习 Scrapy 爬虫框架 Python爬虫教程-30-Scrapy 爬虫框架介绍 框架:框架就是对于相同的相似的部分,代码做到不出错,而我们就可以将注意力放到我们自己的部分了 常见爬虫框 ...
最新文章
- Python 的编码问题UnicodeDecodeError: 'ascii' codec can't decode byte ××× in postition
- Linux: debian/ubuntu下安装Neo4j
- 2009-ISIS命令与配置实验手册(可下载)
- php的引用变量与销毁机制
- 使用快嘉框架开发项目示例
- 学习如何写PHP MVC框架(1) -- 路由
- zabbix的rc控制脚本
- js ws 状态_node.js中ws模块创建服务端和客户端,网页WebSocket客户端
- UML 类图符号简介-符号 各种关系说明以及举例
- Audio播放流程(三)---NuPlayer流程之setAudioStreamType以及prepare
- 整数划分之四 【区间dp】讲解于思考方法
- 利用XML文件的一个写日志的类!!!!!
- 华为交换机默认BOOTROM密码
- php iis7.5_浅析iis7.5安装配置php环境
- Keil:Undefined symbol ......(referred from......)解决
- iptables 删除规则
- SQL SERVER 多字段不为空COALESCE用法
- 流利阅读 2019.1.30 China’s Baidu pledges to improve search service after complaint
- ftdi android,FTDI D2xx android java not reading
- centos光盘修复引导_CentOs7 修复 引导启动
热门文章
- 电脑双屏开机后副屏黑屏_电脑两个显示器怎么设置,电脑显示器黑屏
- 微信摇一摇服务器实现,微信摇一摇事件通知
- 【论文合集】2022年10月医学影像期刊论文合集
- 从《人民的名义》看声纹识别技术在案件侦查中的应用
- 书摘---网络搜集整理 (11--20)
- tensorflow+python flask进行手写识别_python+flask搭建CNN在线识别手写中文网站!简直太屌了!...
- Unirech腾讯云代充-关于腾讯云国际版云服务器实例调整配置常见问题
- Bean无法注入,‘sqlSessionFactory‘ threw exception,‘dataSource‘ threw exception大坑
- CAN 总线的常用拓扑
- Android手机应用CTA认证自测