Django项目
一、 git的使用:
1.1 安装git:
Ubuntu下安装git
sudo apt-get install git
Windows下安装git
进入官网,下载安装包,选好路径傻瓜安装
1.2 查看是否安装成功
--version git
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjDghJAj-1588223223775)(/../../../../AppData/Local/Temp/1564464652239.png)]
1.3 创建本地仓库
1.3.1 创建本地仓库
创建一个用于存放项目的文件夹(Django_project_test)
进入到项目文件夹,右键打开git bush
(一般情况下文件夹以 . 开头的都是隐藏文件夹, 里面的文件切记不可以修改。)
Git init # 初始化会创建一个.git隐藏文件夹 这个文件夹为版本库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTxHa1vO-1588223223780)(/1564464822626.png)]
1.3.2 配置个人信息
# 配置全局信息
git config --global user.name 'xiaofei'
git config --global user.email 'izhangtengfei@163.com'
# 配置信息会保存在家目录下面
~/.gitconfig
# 配置个人项目信息
git config user.name 'xiaofei'
git config user.email 'izhangtengfei@163.com'
# 配置信息会保存在当前目录下的./git/config下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZJmNAoQF-1588223223782)(/1564466169672.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xa0MbzDq-1588223223786)(/1564466511165.png)]
1.3.3 添加文件
创建好了本地仓库,就 准备开始开发了。
在项目文件夹下创建readme.txt 文件, 并输入内容。
将文件添加到代码库分两步
①添加到暂存区
git add readme.txt # 将文件添加到暂存区
②将暂存区的文件提交到仓库。
git commit -m '备注' # 备注处写入备注信息
git commit 命令 -m 参数后输入的是提交的说明。 命令执行成功后显示几个文件被改动,加了多少行,少了多少行。每次提交都会生成一个新的版本。
(此次修改之前readme.txt是一个空的文件)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ph8FBnkm-1588223223788)(/1564468015460.png)]
修改后的文件为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9S9h9D2a-1588223223789)(/1564468123232.png)]
1.3.4历史版本
工作一段时间后,我们提交了很多次到本地仓库,也会产生很多的版本。怎么查看记录。
git log # 查看历史操作记录 不可以查看删除的commit记录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AJXBX74f-1588223223790)(/1564468383357.png)]
git reflog # git reflog 可以查看所有分支的操作记录,包含已经删除的commit记录
1.3.5 版本回退
① git reset --hard HEAD^
# 使用这种回退没命令会把回退完的节点作为当前节点,进行回退,例如现在1.3使用 git reset --hard HEAD^ 会回退到1.2版本。如果再次使用 git reset --head HEAD^ 版本就会回退到1.1以此类推。
HEAD
表示当前最新版本
HEAD^
表示当前最新版本的前一个版本
HEAD^^
表示当前最新版本的前两个版本,有几个^就回退几个版本
HEAD~1
表示最新版本的前一个版本
HEAD~3
表示最新版本的前3个版本, 后面数字是几就代表最新新版本之前的第几个版本
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vQ3p4oAd-1588223223791)(/1564474137454.png)]
执行命令完
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i496Fdg9-1588223223792)(/1564474104120.png)]
②git reset--hard 版本号
(版本号就是reflog中的版本号)
版本非常多时选择这种方法。版本号就是每次commit生成的哈希(hash)值,只取用前几位数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBcWKQNz-1588223223793)(/1564474725121.png)]
回退完的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hx27iITp-1588223223794)(/1564474758460.png)]
1.3.6 撤销修改
①查看状态
运行git status
命令会显示当前工作区,暂存区,仓库的状态。当工作区的所有代码都提交到仓库 并和仓库保持一致时会显示:
On branch master
nothing to commit, working tree clean
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJEAfuPS-1588223223795)(/1564476920664.png)]
修改之前:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Kr69uUA-1588223223797)(/1564477007021.png)]
修改之后的:
# 修改完之后记得ctrl+s保存
# 之后执行 git status查看状态
git status
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e3PPxYSl-1588223223798)(/1564477127496.png)]
bush窗口会显示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szfpjyTP-1588223223799)(/1564477287358.png)]
②撤销工作区的修改
# 只进行了保存操作,没有进行git add .(添加到暂存区)的操作。
# 直接执行 git checkout 文件名,即可撤销修改。
git checkout readme.txt
# 如多打开文件没有执行任何改动直接执行回退命令,会直接将整个文件清空。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O61t9rVr-1588223223800)(/1564477632643.png)]
修改之前的样子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7tj6RAKy-1588223223801)(/1564477905800.png)]
修改之后
工作区:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q3up2wYD-1588223223802)(/1564477989929.png)]
进入bush进行状态查看:
# git 会提醒你如何保存修改到本地仓库。我们想执行的是撤销操作不是添加操作。不必理会这里的提示
执行以下代码会将
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fRZnkKAn-1588223223803)(/1564478069021.png)]
③撤销暂存区的代码修改
工作区:
修改之前的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOI8qw13-1588223223804)(/1564479231904.png)]
修改之后的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F82PChA0-1588223223805)(/1564479050323.png)]
bush:
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 查看状态
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 添加到暂存区
$ git add .
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 查看状态确认是否添加到暂存区
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: readme.txt
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 撤回到工作区
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 确认状态是否已经撤回到工作区
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
Fly@DESKTOP-G76LKOK MINGW64 /d/all/Django_project_test (master)
# 执行工作区的修改撤回命令
$ git checkout readme.txt
Updated 1 path from the index
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mGMbKkeq-1588223223806)(/1564480056766.png)]
1.3.7 对比文件
对比本地仓库与工作区
# 注意!!! 创建文件时不要用文档打开,打开后再用notepad编辑会出现乱码,直接用notepad打开不会出现中文乱码 -- 文件名 # 没有产生修改不会显示 git diff HEAD
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOf9JQ9Z-1588223223807)(/1564481673195.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-alMei6TF-1588223223810)(/1564481724616.png)]
对比本地仓库个版本代码
进入cd到文件所在的夹才可以进行对比
^ -- 文件名 git diff HEAD HEAD
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aFQYW80i-1588223223811)(/1564481844704.png)]
1.3.8 文件删除
①没有添加到库中的文件
# 直接删除即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKn2h6M6-1588223223812)(/1564485120860.png)]
②添加到暂存区但是没有提交的文件
# 先撤回到工作区
git reset HEAD 文件名# 直接执行删除
①中的操作
③已经提交到版本库
# 删除文件
①的操作# 运行git add .
# 提交
-m '删除版本库'
git commit (这个方法类似于覆盖)
1.4远程仓库
1.4.1 添加远程仓库
① 克隆
克隆就是将远程的代码仓库拉回到本地仓库,这种方式适用于远程仓库已经有东西了
进入到项目所在文件夹打开bash窗口。
# clone的http地址
git clone https://gitee.com/itengfei/first_test.git
执行完以上命令的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCEwiUkT-1588223223814)(/1564561104558.png)]
②本地已经初始化了一个仓库,与远程仓库建立连接再push
使用http连接
每次push都会输入用户名和密码
# 创建仓库
git init
# 建立远程连接
git remote add origin https://gitee.com/itengfei/first_test.git
# 将代码推送上去 origin是远程仓库的名字,master是推送的分支
git push -u origin master
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHGqJ4k5-1588223223816)(/1564562718031.png)]
用户名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qNBp9b3B-1588223223817)(/1564562954745.png)]
密码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4EjStpf-1588223223818)(/1564565420742.png)]
将远程仓库拉到本地仓库
git pull origin master
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vLcOLOIu-1588223223819)(/1564565931844.png)]
使用ssh连接
公钥管理 :https://gitee.com/help/categories/38
添加个人公钥
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sBJpg55U-1588223223821)(/1564567213412.png)]
点击添加个人公钥接下来进入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kXIQ4F5B-1588223223822)(/1564567384146.png)]
生成公钥: https://gitee.com/help/articles/4181#article-header0
①生成秘钥
# 生成公钥 "邮箱"
ssh-keygen -t rsa -C "izhangtengfei@163.com"
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZxrzWCm-1588223223823)(/1564567870692.png)]
②进入到家目录查看生成的秘钥
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5KmrHX7a-1588223223824)(/1564567851652.png)]
推荐notepad打开 .pub
文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrE7X4R4-1588223223826)(/1564568079139.png)]
把.pub
文件中的内容全部复制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H9dlXbzX-1588223223827)(/1564568499541.png)]
粘贴到网站的ssh公钥中
图上漏了 ssh-rsa
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7tcRXx0-1588223223828)(/1564568295187.png)]
输入密码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oj8KXoUA-1588223223829)(/1564568642602.png)]
添加完成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQRIi3gP-1588223223831)(/1564568676759.png)]
连接
复制ssh
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RuRpJCzL-1588223223832)(/1564568952113.png)]
①删除原先http建立的连接
# 查看远程连接
git remote
# 删除origin这个远程连接
git remote remove origin
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tLeF3zwT-1588223223834)(/1564569486795.png)]
②建立连接
# 建立连接
git remote add origin git@gitee.com:itengfei/first_test.git
# 推送代码 推送到的地址 master 本地推送上去的分支
git push origin master
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dmUq3BLM-1588223223835)(/1564569731810.png)]
修改内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D75ziSnV-1588223223836)(/1564569903274.png)]
查看修改结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lT6pfxLx-1588223223837)(/1564569936912.png)]
1.5 分支管理
正常的开发项目中都是多人协作,每个人的任务一般不会一天就完成,如果把没有完成的代码提交到远程仓库会影响被人工作。git提供了分支的功能就不用担心了,可以创建一个自己的分支,在上面干活,想提交就提交,等到工作完成再一次性合并到原来的分支。
①创建分支
新建git仓库时会默认创建一个master分支,他叫主分支。
一般情况下我们不会直接在主分支上干活,它主要用来发布版本。
使用 git branch
命令查看当前分支
# 创建一个开发分支
git branch develop
②切换分支
# 切换到develop分支
git checkout develop
③ 可以把①和②合并
创建并切换到新建分支
-b
表示 创并切换。
# ①②合并成一条语句 创建并切换到新建分支
git checkout -b develop
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDJCMZmJ-1588223223838)(/1564566781773.png)]
④合并分支
创建好develop
分支后,你开始干活,完成上级领导交给你的任务,根据用户的手机壳颜色更换app主题,5分钟之后开发完毕,提交:
$ git add change_theme.py
Administrator@DESKTOP-F3CCKFR MINGW64 ~/Desktop/haha (develop)
$ git commit -m 'complete change theme'
[develop 5b83e32] complete change theme
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 change_theme.py
经过测试功能完成,现在我们要合并到master
分支
首先切换到master
$ git checkout master
Switched to branch 'master'
查看工作区,你会发现刚才开发的功能文件没有了,不要惊慌,因为那个提交是在develop
分支上,现在我们把develop
分支的工作合并到master
分支上:
$ git merge develop
Updating 7173db6..5b83e32
Fast-forward
change_theme.py | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 change_theme.py
git merge
命令用于合并指定分支到当前分支。合并后,在查看文件夹发现,change_theme.py
文件又回来了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OStZW0z-1588223223839)(/1564632106820.png)]
⑤删除分支
合并完之后你也可以删除掉develop
分支:
$ git branch -d develop
Deleted branch develop (was 5b83e32).
$ git branch
* master
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1T99hEi-1588223223840)(/1564632274888.png)]
二、项目创建
2.1 创建Django项目
在Ubuntu上创建项目,实际部署大多是linux系统
# 复制本机的Python环境 -p后面是 Python所在的路径 后面试复制后的环境名
-p /usr/bin/python3.6 tzproject mkvirtualenv
2.1.1安装Django
选择Django2.1.x最新版本,我们用的是2.1.10
# 安装
==2.1.10 pip install django
2.1.2 创建Django项目
# 进入到存放Django项目的文件夹
~/dj_project/
cd # 创建Django项目
-admin startproject tz_project
django# 查看环境
workon# 进入到环境
workon tz_project
2.1.3创建pycharm项目
通过pycharm的ssh连接虚拟机(服务器)
①选择项目目录
选择一个存项目的本地文件,夹注意django项目和pycharm项目的根目录一定要保持一致,不要用一个pycharm的项目,管理多个django项目。
②配置远程解释器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIDWEsDn-1588223223842)(/1565081046814.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9r12HJNZ-1588223223843)(/1565081616004.png)]
③配置远程项目路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hP6raF3l-1588223223844)(/1565081700289.png)]
④设置同步配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4QdxbLCM-1588223223845)(/1565081832839.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgQLYdcg-1588223223846)(/1565082202430.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41b5u4Ma-1588223223847)(/1565081924013.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAcIw3pj-1588223223848)(/1565082109829.png)]
⑤下载代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLqIkl03-1588223223849)(/1565082467843.png)]
⑥创建Djangosever
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8m27THfv-1588223223849)(/1565083200722.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-45PhqKNr-1588223223850)(/1565083261276.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ns3oqlGh-1588223223851)(/1565083309002.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4h20zbx-1588223223852)(/1565083378768.png)]
2.1.4 配置数据库
①创建数据库
create database test_1
②创建用户
# 创建一个名为fly可以远程访问的用户密码为Pythonvip
create user 'fly'@'%' identified by 'pythonvip'
③授权
https://www.cnblogs.com/wuxunyan/p/9095016.html
# 所有权限给fly
grant all privileges on test_1.* to 'fly'@'%' ;
④ 配置settings文件
安装mysqlclient
# 首先更新ubuntu
sudo apt-get update
# 然后按照依赖库
sudo apt-get install default-libmysqlclient-dev
# 再切换到虚拟环境中
workon tzproject
# 最后安装mysqlclient
pip install mysqlclient -i https://pypi.doubanio.com/simple
# 方法一
= {
DATABASES 'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'test_1', # 数据库名
'USER': 'fly', # 用户名
'PASSWORD': 'pythonvip', # 密码
'HOST': '127.0.0.1', # 主机IP
'PORT': 3306 # 端口
} }
方法二:
创建utils工具文件夹,存放工具
将数据库配置信息存到一个文件,在settings文件中将其引入。(推荐)
新建数据库配置文件db.cnf
(名字随意)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ye6aG9rg-1588223223853)(/1565084327733.png)]
# 方法二db.cnf文件
[client]= tzproject
database = dj_user
user = pythonvip
password = 127.0.0.1
host = 3306
port -character-set = utf8 default
pymysql的使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zWlo4cN8-1588223223854)(/1565084964896.png)]
2.1.5 配置redis缓存
用于存放用户session信息,以及需要缓存的各种信息。
# 在虚拟机中安装django-redis
pip install django-redis
# settings.py文件中指定redis配置
= {
CACHES "default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},'session': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
},
}
# session存储缓存设置
= 'django.contrib.sessions.backends.cache'
SESSION_ENGINE = 'session' SESSION_CACHE_ALIAS
文档地址:https://django-redis-chs.readthedocs.io/zh_CN/latest/
django文档:https://docs.djangoproject.com/en/2.2/topics/http/sessions/#using-cached-sessions
2.1.6 配置日志器
用于记录系统运行过程中的各种日志信息。
在项目根目录中创建一个logs文件夹,用于存放日志文件
# 日志
= {
LOGGING # 版本
'version': 1,
# 是否禁用已存在的日志器
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {lineno:d} {message}',
'style': '{',
},'simple': {
'format': '{levelname} {module} {lineno:d} {message}',
'style': '{',
},
},'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},'handlers': {
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},'file': {
'level': 'INFO',
# 这个handler可以记录一组日志文件
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, 'logs/tz_django.log'),
# 单个日志文件最大字节数
'maxBytes': 300*1024*1024,
# 日志文件个数
'backupCount': 10,
'formatter': 'verbose'
},
},'loggers': {
'django': {
'handlers': ['console', 'file'],
'level': 'INFO', # 日志器接收的最低级别
'propagate': True,
},
}, }
# 使用方法
# import the logging library
import logging
# Get an instance of a logger
# 此处的django为,settings.py文件中,LOGGING配置下的loggers中定义的日志器名称
= logging.getLogger('django')
logger
def my_view(request, arg1, arg):
...if ***:
# Log an error message
'Something went wrong!') logger.error(
官方文档:https://docs.djangoproject.com/en/2.2/topics/logging/#module-django.utils.log
2.1.7 时区配置
# 修改语言
= 'zh-hans'
LANGUAGE_CODE # 修改时区
= 'Asia/Shanghai' TIME_ZONE
2.1.8 静态文件配置
在项目根目录创建一个static文件夹, 用来存放静态文件(css, js, img, font 等等)
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
2.1.9 加载优化
接着分别在apps文件夹和项目根目录文件夹上右键,加入到Source Root中,优化导入路径(pycharm提示)。
import os
import sys
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
= os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_DIR # 将app添加到sys中,优化调用
0, BASE_DIR)
sys.path.insert(1, os.path.join(BASE_DIR, 'apps')) sys.path.insert(
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATw9Q2y1-1588223223856)(/1565086240145.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UF97hUlH-1588223223857)(/1565086403244.png)]
添加apps
将创建的app放到apps中
= [
INSTALLED_APPS 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'news',
]
三、模板抽取
3.1 创建templates文件夹
创建templates文件夹用来存放html文件
3.1.1 创建base模板
用来继承页面中的相同文件,减少代码的冗余
3.1.2 设置templates路径
记得配置templates在settings文件中的路径
= [
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',
],
},
}, ]
3.1.3 分析页面,抽取出相同的部分
利用 block 名字 和 endblock 来分离出不同的部分
然后根据每个页面的不同填入不同的东西
并修改硬写部分
路径结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QyzJ1EOW-1588223223858)(/1565757006289.png)]
①base.html文件
<!--base.html文件-->
{{% load static %}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{% block title %}}{{% endblock title %}}</title>
<link rel="stylesheet" href={{% static "css/base/reset.css" %}}>
<link rel="stylesheet" href={{% static "css/base/common.css" %}}>
<link rel="stylesheet" href={{% static "css/base/side.css" %}}>
<link rel="stylesheet" href="http://at.alicdn.com/t/font_684044_un7umbuwwfp.css">
<!--特殊的css-->
{{% block css %}}
{{% endblock css %}}</head>
<body>
<!-- header start -->
<header id="header">
<div class="mw1200 header-contain clearfix">
<!-- logo start -->
<h1 class="logo">
<a href="javascript:void(0);" class="logo-title">Python</a>
</h1>
<!-- logo end -->
<!-- nav start -->
<nav class="nav">
<ul class="menu">
<li><a href="{{% url 'news:index' %}}">首页</a></li>
<li><a href="{{% url 'course:index' %}}">在线课堂</a></li>
<li><a href="{{% url 'doc:index' %}}">下载文档</a></li>
<li><a href="search.html">搜索</a></li>
</ul>
</nav>
<!-- nav end -->
<!-- login start -->
<div class="login-box">
<div>
<i class="PyWhich py-user"></i>
<span>
<a href="{{% url 'user:login' %}}" class="login">登录</a> / <a href="{{% url 'user:register' %}}"
class="reg">注册</a>
</span>
</div>
<div class="author hide">
<i class="PyWhich py-user"></i>
<span>qwertyui</span>
<ul class="author-menu">
<li><a href="javascript:void(0);">后台管理</a></li>
<li><a href="javascript:void(0);">退出登录</a></li>
</ul>
</div>
</div>
<!-- login end -->
</div>
</header>
<!-- header end -->
<!-- main start -->
<!-- 除去页眉页脚的内容 -->
{{% block main %}}<main id="main">
<div class="w1200 clearfix">
<!-- main-contain start -->
<!-- 主体内容 start -->
{{% block main_contain %}}
{{% endblock main_contain %}}<!-- 主体内容 end -->
<!-- main-contain end -->
<!-- side start -->
<!-- 边上的内容 -->
{{% block side %}}<aside class="side">
<div class="side-activities">
<h3 class="activities-title">在线课堂<a href="javascript:void(0)">更多</a></h3>
<div class="activities-img">
<a href="javascript:void(0);" target="_blank">
<img src={{% static "images/english.jpg" %}} alt="title">
</a>
<p class="activities-tips">对话国外小姐姐</p>
</div>
<ul class="activities-list">
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-start">报名中</span>
<span class="active-title"><a
href="https://www.shiguangkey.com/course/2432"> Django 项目班</a></span>
</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-end">已结束</span>
<span class="active-title"><a
href="https://www.shiguangkey.com/course/2321">Python入门基础班</a></span>
</a>
</li>
</ul>
</div>
<div class="side-attention clearfix">
<h3 class="attention-title">关注我</h3>
<ul class="side-attention-address">
<li>
<a href="javascript:void(0);" target="_blank"><i
class="PyWhich py-GitHub"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-zhihu"
style="color:rgb(0, 108, 226);"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-weibo"
style="color:rgb(245,92,110);"></i>XinLan</a>
</li>
</ul>
<div class="side-attention-qr">
<p>扫码关注</p>
</div>
</div>
<!--hot_news模板-->
{{% block hotnews %}}
{{% endblock hotnews %}}
</aside>
{{% endblock side %}}<!-- side end -->
</div>
</main>
{{% endblock main %}}<!-- main end -->
<!-- footer start -->
<!-- 页脚 start -->
{{% block foot %}}
{{% endblock foot %}}<!-- footer end -->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="{{% static 'js/base/common.js' %}}"></script>#}
{#<script src="{{% static 'js/base/message.js' %}}"></script>
<!-- js start -->
{{% block script %}}
{{% endblock script %}}</body>
</html>
②news.html文件
{{% extends 'base/base.html' %}}
{{% load static %}}
{{% block title %}}
IndexPage
{{% endblock title %}}
{{% block css %}}<link rel="stylesheet" href="{{% static 'css/news/index.css' %}}">
<script>IMemuIndex=0</script>
{{% endblock css %}}
<!-- main start -->
{{% block main %}}<main id="main">
<div class="w1200 clearfix">
<!-- main-contain start -->
{{% block main_contain %}}<div class="main-contain">
<!-- banner start -->
<div class="banner">
<ul class="pic">
<!--淡入淡出banner-->
<li><a href="javascript:void(0);"><img src={{% static "images/linux.jpg" %}} alt="test"></a>
</li>
<li><a href="javascript:void(0);"><img src={{% static "images/python_gui.jpg" %}} alt="test"></a>
</li>
<li><a href="javascript:void(0);"><img
src={{% static "images/python_function.jpg" %}} alt="test"></a></li>
<li><a href="javascript:void(0);"><img
src={{% static "images/python_advanced.jpg" %}} alt="test"></a></li>
<li><a href="javascript:void(0);"><img
src={{% static "images/jichujiaochen.jpeg" %}} alt="test"></a></li>
<li><a href="javascript:void(0);"><img src={{% static "images/python_web.jpg" %}} alt="test"></a>
</li>
</ul>
<a href="javascript:void(0);" class="btn prev">
<i class="PyWhich py-arrow-left"></i></a>
<a href="javascript:void(0);" class="btn next">
<i class="PyWhich py-arrow-right"></i></a>
<ul class="tab">
<!-- 按钮数量必须和图片一致 -->
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<!-- banner end -->
<!-- content start -->
<div class="content">
<!-- recommend-news start -->
<ul class="recommend-news">
<li>
<a href="https://www.shiguangkey.com/course/2432" target="_blank">
<div class="recommend-thumbnail">
<img src={{% static "images/python_gui.jpg" %}} alt="title">
</div>
<p class="info">Python GUI 教程 25行代码写一个小闹钟</p>
</a>
</li>
<li>
<a href="https://www.shiguangkey.com/course/2432" target="_blank">
<div class="recommend-thumbnail">
<img src={{% static "images/python_advanced.jpg" %}} alt="title">
</div>
<p class="info">python高性能编程方法一</p>
</a>
</li>
<li>
<a href="https://www.shiguangkey.com/course/2432" target="_blank">
<div class="recommend-thumbnail">
<img src={{% static "images/jichujiaochen.jpeg" %}} alt="title">
</div>
<p class="info">python基础 split 和 join函数比较</p>
</a>
</li>
</ul>
<!-- recommend-news end -->
<!-- news-nav start-->
<nav class="news-nav">
<ul class="clearfix">
<li class="active"><a href="javascript:void(0)">最新资讯</a></li>
<li><a href="javascript:void(0)" data-id="1">python框架</a>
</li>
<li><a href="javascript:void(0)" data-id="2">Python基础</a>
</li>
<li><a href="javascript:void(0)" data-id="3">Python高级</a>
</li>
<li><a href="javascript:void(0)" data-id="4">Python函数</a>
</li>
<li><a href="javascript:void(0)" data-id="5">PythonGUI</a>
</li>
<li><a href="javascript:void(0)" data-id="6">Linux教程</a>
</li>
</ul>
</nav>
<!-- news-nav end -->
<!-- news-contain start -->
<div class="news-contain">
<ul class="news-list">
<li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src={{% static "images/linux.jpg" %}} alt="linux查找文件或目录命令"
title="linux查找文件或目录命令">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="#">linux查找文件或目录命令</a>
</h4>
<p class="news-details">linux查找文件或目录命令,前提:知道文件或者目录的具体名字,例如:sphinx.conffind
查找find / -name</p>
dirname 查找目录find -name...<div class="news-other">
<span class="news-type">Linux教程</span>
<span class="news-time">11/11 18:24</span>
<span class="news-author">python</span>
</div>
</div>
</li>
<li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src={{% static "images/linux.jpg" %}} alt="linux下svn命令的使用"
title="linux下svn命令的使用">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="https://www.shiguangkey.com/course/2432/887">linux下svn命令的使用</a>
</h4>
<p class="news-details">1、将文件checkout到本地目录svn checkout path(path是服务器上的目录) 例如:svn
checkout
svn://192.168.1.1/pro/domain 简写:svn co2、往版本库中添加新的文件 svn addfile 例如:svn add</p>
te...<div class="news-other">
<span class="news-type">Linux教程</span>
<span class="news-time">11/11 18:24</span>
<span class="news-author">python</span>
</div>
</div>
</li>
<li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src={{% static "images/linux.jpg" %}} alt="实现linux和windows文件传输"
title="实现linux和windows文件传输">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="https://www.shiguangkey.com/course/2432/886">实现linux和windows文件传输</a>
</h4>
<p class="news-details">
</p>
其实这个题目有点大,这里介绍的只是linux和windows文件传输中的一种,但是这种方法却非常实用,那就是:ZModem协议具体是linux命令是:rz...<div class="news-other">
<span class="news-type">Linux教程</span>
<span class="news-time">11/11 18:24</span>
<span class="news-author">python</span>
</div>
</div>
</li>
<li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src={{% static "images/linux.jpg" %}} alt=".htaccess配置详解"
title=".htaccess配置详解">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="https://www.shiguangkey.com/course/2432">.htaccess配置详解</a>
</h4>
<p class="news-details"> .htaccess文件设置基础教程 如果你设置好了比如常用的404页面 301重定向
页面还有500页面等会设置了"分布式...</p>
无非对你的seo技术有很大帮助那么 .htaccess文件到底怎么设置呢 - .htaccess 文件(或者<div class="news-other">
<span class="news-type">Linux教程</span>
<span class="news-time">11/11 18:24</span>
<span class="news-author">python</span>
</div>
</div>
</li>
<li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src={{% static "images/linux.jpg" %}} alt="使用nohup命令让linux程序后台运行"
title="使用nohup命令让linux程序后台运行">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="https://www.shiguangkey.com/course/2432">使用nohup命令让linux程序后台运行</a>
</h4>
<p class="news-details">使用nohup让程序永远后台运行Unix/Linux下一般比如想让某个程序在后台运行,很多都是使用 &
在程序结尾来让程序自动运行。比如我们要运行mysql在后台:/usr/local/mysql/bin/mysqld_safe --user=mysql&但是...</p>
<div class="news-other">
<span class="news-type">Linux教程</span>
<span class="news-time">11/11 18:24</span>
<span class="news-author">python</span>
</div>
</div>
</li>
</ul>
</div>
<!-- news-contain end -->
<!-- btn-more start -->
<a href="javascript:void(0);" class="btn-more">加载更多</a>
<!-- btn-more end -->
</div>
<!-- content end -->
</div>
{{% endblock main_contain %}}<!-- main-contain end -->
<!-- side start -->
{{% block side %}}<aside class="side">
<div class="side-activities">
<h3 class="activities-title">在线课堂<a href="javascript:void(0)">更多</a></h3>
<div class="activities-img">
<a href="javascript:void(0);" target="_blank">
<img src={{% static "images/english.jpg" %}} alt="title">
</a>
<p class="activities-tips">对话国外小姐姐</p>
</div>
<ul class="activities-list">
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-start">报名中</span>
<span class="active-title"><a
href="https://www.shiguangkey.com/course/2432"> Django 项目班</a></span>
</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-end">已结束</span>
<span class="active-title"><a
href="https://www.shiguangkey.com/course/2321">Python入门基础班</a></span>
</a>
</li>
</ul>
</div>
<div class="side-attention clearfix">
<h3 class="attention-title">关注我</h3>
<ul class="side-attention-address">
<li>
<a href="javascript:void(0);" target="_blank"><i
class="PyWhich py-GitHub"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-zhihu"
style="color:rgb(0, 108, 226);"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-weibo"
style="color:rgb(245,92,110);"></i>XinLan</a>
</li>
</ul>
<div class="side-attention-qr">
<p>扫码关注</p>
</div>
</div>
<div class="side-hot-recommend">
<h3 class="hot-recommend">热门推荐</h3>
<ul class="hot-news-list">
<li>
<a href="javascript:void(0)" class="hot-news-contain clearfix">
<div class="hot-news-thumbnail">
<img src={{% static "images/python_web.jpg" %}}
alt="">
</div>
<div class="hot-news-content">
<p class="hot-news-title">Django调试工具django-debug-toolbar安装使用教程</p>
<div class="hot-news-other clearfix">
<span class="news-type">python框架</span>
<!-- 自带的 -->
<time class="news-pub-time">11月11日</time>
<span class="news-author">python</span>
</div>
</div>
</a>
</li>
</ul>
</div>
</aside>
{{% endblock side %}}<!-- side end -->
</div>
</main>
{{% endblock main %}}<!-- main end -->
<!-- footer start -->
{{% block foot %}}<footer id="footer">
<div class="footer-box">
<div class="footer-content">
<p class="top-content">
<span class="link">
<a href="javascript:void(0)">关于Python</a> |
<a href="javascript:void(0)">我就是我</a> |
<a href="javascript:void(0)">人生苦短</a> |
<a href="javascript:void(0)">我用Python</a>
</span>
<span class="about-me">关于我: <i class="PyWhich py-wechat"></i> XinLan</span>
</p>
<p class="bottom-content">
<span>地址: xxxx</span>
<span>联系方式: <a href="tel:400-1567-315">400-1567-315</a> (24小时在线)</span>
</p>
</div>
<p class="copyright-desc">
© 2008 - 2018 xxx有限公司. All Rights Reserved
Copyright </p>
</div>
</footer>
{{% endblock foot %}}<!-- footer end -->
{{% block script %}}<script src="{{% static 'js/news/index.js' %}}"></script>
<script src="{{% static 'js/base/common.js' %}}"></script>
{{% endblock script %}}
③doc.html文件
{{% extends 'base/base.html' %}}
{{% load static %}}
{{% block title %}}
payInfo
{{% endblock title %}}
{{% block css %}}<link rel="stylesheet" href="{{% static 'css/doc/docDownload.css' %}}">
<script>IMemuIndex = 2</script>
{{% endblock css %}}<body>
<!-- main start -->
{{% block main %}}<main id="main">
<div class="w1200 clearfix">
<!-- main-contain start -->
{{% block main_contain %}}<div class="main-contain ">
<div class="banner">
<img src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1802845035,3786939119&fm=26&gp=0.jpg"
alt="">
</div>
<div class="pay-doc-contain">
<ul class="pay-list">
<li class="pay-item">
<div class="pay-img doc"></div>
<div class="d-contain">
<p class="doc-title">python cookbook 3.0 教程</p>
<p class="doc-desc">强烈推荐的python 教程。</p>
<!-- /www/?xxx -->
<a href="#" class="pay-price">下载</a>
</div>
</li>
<li class="pay-item">
<div class="pay-img doc"></div>
<div class="pay-contain">
<p class="pay-title">流畅的Python</p>
<p class="pay-desc">【本书特色】
本书由奋战在Python开发一线近20年的Luciano Ramalho执笔,Victor Stinner、Alex
Martelli等Python大咖担纲技术审稿人,从语言设计层面剖析编程细节,兼顾Python 3和Python</p>
2,告诉你Python中不亲自动手实践就无法理解的语言陷阱成因和解决之道,教你写出风格地道的Python代码。
<!-- /www/?xxx -->
<a href="#" class="pay-price">下载</a>
</div>
</li>
<li class="pay-item">
<div class="pay-img doc"></div>
<div class="pay-contain">
<p class="pay-title">深入Flask</p>
<p class="pay-desc">深入Flask,强烈推荐!</p>
<!-- /www/?xxx -->
<a href="#" class="pay-price">下载</a>
</div>
</li>
</ul>
</div>
</div>
{{% endblock main_contain %}}<!-- main-contain end -->
<!-- side start -->
{{% block side %}}<aside class="side">
<div class="side-activities">
<h3 class="activities-title">在线课堂<a href="javascript:void(0)">更多</a></h3>
<div class="activities-img">
<a href="javascript:void(0);" target="_blank">
<img src="https://res.shiguangkey.com//file/201804/26/20180426142628123364782.jpg"
alt="title">
</a>
<p class="activities-tips">对话国外小姐姐</p>
</div>
<ul class="activities-list">
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-start">报名中</span>
<span class="active-title"><a href="https://www.shiguangkey.com/course/2432"> Django 项目班</a></span>
</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank">
<span class="active-status active-end">已结束</span>
<span class="active-title"><a href="https://www.shiguangkey.com/course/2321">Python入门基础班</a></span>
</a>
</li>
</ul>
</div>
<div class="side-attention clearfix">
<h3 class="attention-title">关注我</h3>
<ul class="side-attention-address">
<li>
<a href="javascript:void(0);" target="_blank"><i
class="PyWhich py-GitHub"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-zhihu"
style="color:rgb(0, 108, 226);"></i>XinLan</a>
</li>
<li>
<a href="javascript:void(0);" target="_blank"><i class="PyWhich py-weibo"
style="color:rgb(245,91,94)"></i>XinLan</a>
</li>
</ul>
<div class="side-attention-qr">
<p>扫码关注</p>
</div>
</div>
</aside>
{{% endblock side %}}<!-- side end -->
</div>
</main>
{{% endblock main %}}
<!-- main end -->
<!-- footer start -->
{{% block foot %}}<footer id="footer">
<div class="footer-box">
<div class="footer-content">
<p class="top-content">
<span class="link">
<a href="javascript:void(0)">关于Python</a> |
<a href="javascript:void(0)">我就是我</a> |
<a href="javascript:void(0)">人生苦短</a> |
<a href="javascript:void(0)">我用Python</a>
</span>
<span class="about-me">关于我: <i class="PyWhich py-wechat"></i> XinLan</span>
</p>
<p class="bottom-content">
<span>地址: xxxx</span>
<span>联系方式: <a href="tel:400-1567-315">400-1567-315</a> (24小时在线)</span>
</p>
</div>
<p class="copyright-desc">
© 2008 - 2018 xxx有限公司. All Rights Reserved
Copyright </p>
</div>
</footer>
{{% endblock foot %}}<!-- footer end -->
{{% block script %}}<script src="{{% static 'js/base/common.js' %}}"></script>
{{% endblock script %}}
④user/login.html文件
{{% extends 'base/base.html' %}}
{{% load static %}}
{{% block css %}}<link rel="stylesheet" href="{{% static 'css/user/auth.css' %}}">
{{% endblock css %}}
{{% block title %}}
login
{{% endblock %}}
<!-- container start -->
{{% block main %}}<main id="container">
<div class="login-contain">
<div class="top-contain">
<h4 class="please-login">请登录</h4>
<a href="javascript:void(0);" class="register">立即注册 ></a>#}
{# <a href="{{% url 'user:register' %}}" class="register">立即注册 ></a>
</div>
<form action="" method="post" class="form-contain">
<div class="form-item">
<input type="tel" placeholder="请输入手机号" name="mobile" class="form-control" autocomplete="off">
</div>
<div class="form-item">
<input type="password" placeholder="请输入密码" name="password" class="form-control">
</div>
<div class="form-item clearfix">
<label>
<input type="checkbox" name="remember">
<span>记住我</span>
</label>
<a href="javascript:void(0);" class="forget-password">忘记密码?</a>
</div>
<div class="form-login">
<input type="submit" value="登录" class="login-btn">
</div>
</form>
</div>
</main>
{{% endblock main %}}<!-- container end -->
<!-- footer start -->
{{% block foot %}}<footer id="footer">
<div class="footer-box">
<div class="footer-content">
<p class="top-content">
<span class="link">
<a href="javascript:void(0)">关于Python</a> |
<a href="javascript:void(0)">我就是我</a> |
<a href="javascript:void(0)">人生苦短</a> |
<a href="javascript:void(0)">我用Python</a>
</span>
<span class="about-me">关于我: <i class="PyWhich py-wechat"></i> XinLan</span>
</p>
<p class="bottom-content">
<span>地址: xxxx</span>
<span>联系方式: <a href="tel:400-1567-315">400-1567-315</a> (24小时在线)</span>
</p>
</div>
<p class="copyright-desc">
© 2008 - 2018 xxx有限公司. All Rights Reserved
Copyright </p>
</div>
</footer>
{{% endblock %}}
<!-- footer end -->
{{% block script %}}<script src="{{% static 'js/user/register.js' %}}"></script>#}
{#<script src="{{% static 'js/user/login.js' %}}"></script>
{{% endblock script %}}
⑤register.html文件
{{% extends 'base/base.html' %}}
{{% load static %}}
{{% block title %}}
Register
{{% endblock title %}}
{{% block css %}}<link rel="stylesheet" href="{{% static 'css/user/auth.css' %}}">
<script>IMemuIndex=false</script>
{{% endblock css %}}
<!-- container start -->
{{% block main %}}<main id="container">
<div class="register-contain">
<div class="top-contain">
<h4 class="please-register">请注册</h4>
<a href="javascript:void(0);" class="login">立即登录 ></a>#}
{# <a href="{{% url 'user:login' %}}" class="login">立即登录 ></a>
</div>
<form action="" method="post" class="form-contain">
{{% csrf_token %}}
<div class="form-item">
<input type="text" placeholder="请输入用户名" name="username" class="form-control" id="username" autocomplete="off">
</div>
<div class="form-item">
<input type="password" placeholder="请输入密码" name="password" class="form-control">
</div>
<div class="form-item">
<input type="password" placeholder="请输入确认密码" name="password_repeat" class="form-control">
</div>
<div class="form-item">
<input type="tel" placeholder="请输入手机号" name="mobile" class="form-control" autocomplete="off" >
</div>
<div class="form-item">
<input type="text" placeholder="请输入图形验证码" name="captcha_graph" class="form-captcha">
<a href="javascript:void(0);" class="captcha-graph-img">
<img src="{{% url 'image_code:image_code' %}}" alt="验证码" title="点击刷新">
</a>
</div>
<div class="form-item">
<input type="text" placeholder="请输入短信验证码" name="sms_captcha" class="form-captcha" autocomplete="off">
<a href="javascript:void(0);" class="sms-captcha" title="发送验证码">获取短信验证码</a>
</div>
<div class="form-item">
<input type="submit" value="立即注册" class="register-btn">
</div>
</form>
</div>
</main>
{{% endblock main %}}<!-- container end -->
<!-- footer start -->
{{% block foot %}}<footer id="footer">
<div class="footer-box">
<div class="footer-content">
<p class="top-content">
<span class="link">
<a href="javascript:void(0)">关于Python</a> |
<a href="javascript:void(0)">我就是我</a> |
<a href="javascript:void(0)">人生苦短</a> |
<a href="javascript:void(0)">我用Python</a>
</span>
<span class="about-me">关于我: <i class="PyWhich py-wechat"></i> XinLan</span>
</p>
<p class="bottom-content">
<span>地址: xxxx</span>
<span>联系方式: <a href="tel:400-1567-315">400-1567-315</a> (24小时在线)</span>
</p>
</div>
<p class="copyright-desc">
© 2008 - 2018 xxx有限公司. All Rights Reserved
Copyright </p>
</div>
</footer>
{{% endblock foot %}}<!-- footer end -->
{{% block script %}}<script src="{{% static 'js/base/message.js' %}}"></script>#}
{# <script src="{{% static 'js/user/register.js' %}}"></script>
<script src="{{% static 'js/base/common.js' %}}"></script>
{{% endblock script %}}
⑥course.html文件
{{% extends 'base/base.html' %}}
{{% load static %}}
{{% block title %}}
coursePage
{{% endblock title %}}
{{% block css %}}<link rel="stylesheet" href="{{% static 'css/course/course.css' %}}">
<script>IMemuIndex = 1</script>
{{% endblock css %}}
{{% block main %}}<main id="course-container">
<div class="w1200">
<ul class="course-list">
<li class="course-item">
<a href="https://www.shiguangkey.com/course/2432">
<img class="course-img" src={{% static "images/python_advanced.jpg" %}}
alt="潭州英语">
<div class="course-content">
<p class="course-info">python 全栈开发</p>
<p class="course-author">不动(python金牌讲师)</p>
<p class="course-price free">免费</p>
</div>
</a>
</li>
<li class="course-item">
<a href="https://www.shiguangkey.com/course/2432">
<img class="course-img" src={{% static "images/python_web.jpg" %}}
alt="潭州英语">
<div class="course-content">
<p class="course-info">django 项目</p>
<p class="course-author">XinLan(python讲师)</p>
<p class="course-price free">免费</p>
</div>
</a>
</li>
</ul>
</div>
</main>
{{% endblock main %}}
<!-- footer start -->
{{% block foot %}}<footer id="footer">
<div class="footer-box">
<div class="footer-content">
<p class="top-content">
<span class="link">
<a href="javascript:void(0)">关于Python</a> |
<a href="javascript:void(0)">我就是我</a> |
<a href="javascript:void(0)">人生苦短</a> |
<a href="javascript:void(0)">我用Python</a>
</span>
<span class="about-me">关于我: <i class="PyWhich py-wechat"></i> XinLan</span>
</p>
<p class="bottom-content">
<span>地址: xxxx</span>
<span>联系方式: <a href="tel:400-1567-315">400-1567-315</a> (24小时在线)</span>
</p>
</div>
<p class="copyright-desc">
© 2008 - 2018 xxx有限公司. All Rights Reserved
Copyright </p>
</div>
</footer>
{{% endblock foot %}}<!-- footer end -->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
{{% block script %}}<script src="{{% static 'js/base/common.js' %}}"></script>
{{% endblock script %}}
3.2 创建static文件夹
创建static文件夹用来存放静态文件(css/js/img/)
文件结构,每个模板的静态文件创建并放到不同的文件夹中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8aQddVf6-1588223223861)(/1565757977142.png)]
①css文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2uT6VJ3e-1588223223862)(/1565758060491.png)]
②js文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-22AmnnTu-1588223223863)(/1565758133004.png)]
③images文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GDefwPC-1588223223864)(/1565758178816.png)]
3.3 编写views文件和路由配置(编写urls文件)
以news为例,其他类推
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xueBXiwF-1588223223865)(/1565758673646.png)]
3.3.1 views.py
from django.shortcuts import render
# Create your views here.
# news主页
def index(request):
return render(request, 'news/index.html')
3.3.2 urls.py
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GndDBNH0-1588223223866)(/1565758901074.png)]
# 主路由
from django.contrib import admin
from django.urls import path, include
from . import views
= [
urlpatterns #
# path('admin', admin.site.urls),
# 分配news子路由
'news/', include('news.urls')),
path(# 分配course子路由
'course/', include('course.urls')),
path(# 分配doc子路由
'doc/', include('doc.urls')),
path(# 分配user子路由
'user/', include('user.urls')),
path(# 分配image_code子路由
'verification/', include('verification.urls'))
path( ]
# news的路由
from django.urls import path
from . import views
= 'news'
app_name
= [
urlpatterns '', views.index, name='index')
path( ]
3.4 填上缺少的block
根据每个页面的不同填上不同的内容
3.1.3中已经填上
四、注册功能
4.1 模型设置
4.1.1 字段分析
-用户名
-密码
-手机号
-邮箱
4.1.2 模型设计
django的强大之处在于开发效率高,内置了权限模块之类的很多常用功能。在开始一个新的django项目时,如果权限模块中的User模型不满足项目要求,我们需要扩展或者自定义User模型。
扩展User模型有两种方法:
- 如果你不需要改变数据库存储内容,只是改变行为,那么可以建立有一个基于User模型的代理模型。
- 如果想存储与User模型关联的信息,可以使用OneToOneField到包含其他信息字段的模型。这种one-to-one模型经常被称作Profile模型,因为它可能存储站点用户的非身份验证的相关信息。例如:
from django.contrib.auth.models import User
class Employee(models.Model):
= models.OneToOneField(User, on_delete=models.CASCADE)
user = models.CharField(max_length=100) department
自定义User模型:
如果不想使用django内置的权限系统,当然你需要自定义用户模型,这种情况不讨论。当然也不建议这么做,django内置权限系统有大的自定义功能扩展,而不是重复造轮子。
开启一个新项目,官方强烈推荐用户自定义用户模型,即是默认的用户模型目前已经足够,但是未来可能会要扩展。
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
注意:不要忘记在settings.py中设置AUTH_USER_MODEL
指向它。
一旦已经创立数据库表之后再去修改AUTH_USER_MODEL
,会困难很多,因为它会影响外键和多对多关系。这个改动并不能自动完成,需要手动修复(巨坑)。
4.1.3 user的models文件
设置models文件来建立模型,这里用Django内置的User一定要注意!!!!!
我们重写了User类,我们要让整个框架知道我们重写了User类,就要在settings文件中配置
②settings.py
# 自定义用户模型
= 'user.User' AUTH_USER_MODEL
①models.py
from django.db import models
# 导入Django的内置User模型类 取个别名因为下面会用到相同的名冲突
from django.contrib.auth.models import AbstractUser, UserManager as _UserManager
# 这个类继承_UserManager类
class UserManger(_UserManager):
""""
修改必须输入email的这个行为
重写create_superuser方法,去掉创建super_user必须的email的行为
"""
def create_superuser(self, username, password, email=None, **extra_fields):
super().create_superuser(username=username, password=password, email=email, **extra_fields)
class User(AbstractUser):
"""
自定义user模型, 添加手机,email_active
"""
= models.CharField(verbose_name='手机号', max_length=11, unique=True, help_text='手机号', error_messages={'unique': '此手机号码已注册'})
mobile
= models.BooleanField(verbose_name='邮箱状态', default=False)
email_active
class Meta:
= 'tb_user' # 指定数据库表名
db_table = '用户' # 在admin站点中的显示名称
verbose_name = verbose_name # 复数
verbose_name_plural
# 返回的字段名
def __str__(self):
return self.username
# 通过createsuperuser 这个命令创建用户时,需要的字段
= ['mobile']
REQUIRED_FIELDS
# 通过管理器来执行
= UserManger()
objects
③迁移
# 数据库迁移
python manage.py makemigrations
# 迁移生效
python manage.py migrate
我们这里用的是自己写的admin后台,没有用Django内置的后台
所以我们将settings.py—-> INSTALLED_APPS—->django.contrib.admin 注释掉(删掉),urls.py 主路由中的admin路由也一定要注释掉,要不然无法迁移!!!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nK23FfrY-1588223223867)(/1565761073556.png)]
去掉admin路由
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYU6CJHf-1588223223868)(/1565761243867.png)]
④创建一个用户
(tzproject) ~/code/tztz$ python manage.py createsuperuser
用户名: admin
手机号: 158xxxxxxxx
Password:
Password (again):
密码长度太短。密码必须包含至少 8 个字符。
这个密码太常见了。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
4.2 功能需求分析
4.2.1 接口设计思路
- 分析业务逻辑,明确在这个业务中需要涉及到几个相关子业务,将每个子业务当做一个接口来设计
- 分析接口的功能任务,明确接口的访问方式与返回数据:
- 接口的请求方式,如GET,POST,PUT等
- 接口的URL路径定义
- 需要接受的参数及参数格式(如路径参数,查询字符串,请求表单,JSON等)
- 返回的数据及数据格式
4.2.2 注册功能分析
①流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f1t4hlXN-1588223223869)(/登录注册流程图.png)]
②功能
根据流程图结构分析注册业务包含以下功能
- 注册页面
- 图片验证码
- 用户名检测是否注册
- 手机号检测是否注册
- 短信验证码
- 注册保存用户数据
因为图片验证码,短信验证码考虑到后续可能会在其他业务中用到,因此将验证码功能独立出来,创建一个新应用verification用来校验
4.3 图形验证码功能实现
4.3.1 接口设计
接口说明:
类目 | 说明 |
---|---|
请求方式 | GET |
url定义 | /verification/image_code/ |
参数格式 | 查询参数 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
rand | 字符串 | 否 | 随机值 |
4.3.2后端代码
①将验证码生成模块复制到根目录utils文件夹下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UejbHgeM-1588223223870)(/1565762750062.png)]
②创建新的app verification专门用来处理验证
记得在settings文件中注册app
cd ~/code/tztz/apps/
python ../manage.py startapp verification
③verification/views.py代码如下:
import logging
from django.http import HttpResponse
from utils.captcha.captcha import captcha
from . import constants
# 拿到Django的日志器
= logging.getLogger('django')
logger
def image_code_view(request):
"""
生成图片验证码
url:/image_code/
:param request:
:return:
"""
# 返回两个值,一个是生成的text文本,另一个是image图片
= captcha.generate_captcha()
text, image # 将验证码存入session中name为'image_code'
'image_code'] = text
request.session[# 设置session过期时间 单位秒
# constants设置常量便于后期修改数值
request.session.set_expiry(constants.IMAGE_CODE_EXPIRES)# 将生成的image_code的text记录到日志器中
'Image code:{}'.format(text))
logger.info(# 返回响应为二进制数据,数据类型为image/jpg,这样返回的数据可以直接渲染到浏览器页面上
return HttpResponse(content=image, content_type='image/jpg')
④verification/urls.py代码如下:
from django.urls import path
from . import views
# url的命名空间
= 'verification'
app_name
= [
urlpatterns 'image_code/', views.image_code_view, name='image_code'),
path( ]
⑤主urls文件
from django.contrib import admin
from django.urls import path, include
from . import views
= [
urlpatterns #
# path('admin', admin.site.urls),
# 分配news子路由
'news/', include('news.urls')),
path(# 分配course子路由
'course/', include('course.urls')),
path(# 分配doc子路由
'doc/', include('doc.urls')),
path(# 分配user子路由
'user/', include('user.urls')),
path(# 分配verification子路由
'verification/', include('verification.urls'))
path( ]
4.4 注册页面
4.4.1 接口设计
①接口说明
类目 | 说明 |
---|---|
请求方式 | GET |
url定义 | /verification/register/ |
参数格式 | 无参数 |
②返回结果:
注册页面
4.4.2后端代码
①user/views.py
from django.shortcuts import render
from django.views import View
class RegisterView(View):
def get(self, request):
return render(request, 'user/register.html')
②user/urls.py
from django.urls import path, include
from . import views
= 'user'
app_name
= [
urlpatterns 'register/', views.RegisterView.as_view(), name='register')
path( ]
③根urls.py
from django.urls import path, include
= [
urlpatterns
'user/', include('user.urls'))
path( ]
4.4.3 前端页面代码
①user/register.html代码如:
3.1.3中的⑤
4.4.4 js代码
点击验证码图片刷新的js代码如下:
$(() => {
// 1.点击刷新图像验证码
let $img = $('.form-contain .form-item .captcha-graph-img img');
.click(function () {
$img// 加入rand随机数防止浏览器认为是相同的请求
.attr('src', '/verification/image_code/?rand=' + Math.random())
$img;
}); })
4.5 json响应数据结构设计
4.5.1 结构设计
实际项目是多人协同开发,特别是前后端交互,后端返回数据结构要一致。
{"errno": "0", "errmsg": "OK", "data": {...}}
字段 | 类型 | 说明 |
---|---|---|
errno | 字符串 | 错误编码 |
errmsg | 字符串 | 错误信息 |
data | json | 返回数据 |
在项目根目录中utils文件夹下创建res_code.py文件,用于定义错误编码,代码如下:
class Code:
= "0"
OK = "4001"
DBERR = "4002"
NODATA = "4003"
DATAEXIST = "4004"
DATAERR = "4005"
METHERR = "4006"
SMSERROR = "4007"
SMSFAIL
= "4101"
SESSIONERR = "4102"
LOGINERR = "4103"
PARAMERR = "4104"
USERERR = "4105"
ROLEERR = "4106"
PWDERR
= "4500"
SERVERERR = "4501"
UNKOWNERR
= {
error_map "成功",
Code.OK: "数据库查询错误",
Code.DBERR: "无数据",
Code.NODATA: "数据已存在",
Code.DATAEXIST: "数据错误",
Code.DATAERR: "方法错误",
Code.METHERR: "发送短信验证码异常",
Code.SMSERROR: "发送短信验证码失败",
Code.SMSFAIL:
"用户未登录",
Code.SESSIONERR: "用户登录失败",
Code.LOGINERR: "参数错误",
Code.PARAMERR: "用户不存在或未激活",
Code.USERERR: "用户身份错误",
Code.ROLEERR: "密码错误",
Code.PWDERR:
"内部错误",
Code.SERVERERR: "未知错误",
Code.UNKOWNERR: }
4.5.2 .快捷方法
为了方便定义一个快捷方法,在utils目录下创建json_res.py文件中添加如下代码:
from django.http import JsonResponse
from .res_code import Code
# 返回json——Response数据
def json_response(errno=Code.OK, errmsg='', data=None, kwargs=None):
= {
json_dict 'errno': errno,
'errmsg': errmsg,
'data': data,
}# 判断是否有kwargs 并且是否为字典
if kwargs and isinstance(kwargs, dict):
# 将kwargs更新到json_dict中
json_dict.update(kwargs)return JsonResponse(json_dict)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7nppCtHa-1588223223871)(/1565765018299.png)]
4.6 判断用户是否注册的功能
4.6.1 接口设计
①接口说明
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | verification/username/(?P<username>\w{5,20})/ |
参数格式 | url路径参数 |
②参数说明
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
username | 字符串 | 是 | 输入的用户名 |
返回结果:
{
'errno': errno,
'errmsg': errmsg,
'data': {
'username': username,
'count': User.objects.filter(username=username).count()
},
}
4.6.2 后端代码
①创建新的app verification专门用来处理验证
cd ~/code/tztz/apps/
python ../manage.py startapp verification
② verification/views.py代码
from user.models import User
from utils.json_res import json_response
# 验证用户名
def check_username(request, username):
= {
data 'username': username,
'count':
# 去数据库中过滤username=username的数量有多少
filter(username=username).count()
User.objects.
}# 返回json数据
return json_response(data=data)
③verification/urls.py代码
from django.urls import path, re_path
from . import views
= 'image_code'
app_name
= [
urlpatterns # 图片验证码生成
'image_code/', views.image_code, name='image_code'),
path(# 用户名校验
'username/(?P<username>\w{5,20})/', views.check_username, name='check_username'),
re_path(
]
4.6.3 前端页面代码
user/register.html代码如3.1.3中的⑤
4.6.4 前端js代码
$(()=>{
// 定义状态变量
let isUsernameReady = false,
= false,
isPasswordReady = false,
isMobileReady
// 2. 用户名校验, 光标离开就进行校验
let $username = $('#username');
// blur()光标移开username的反应
.blur(fnCheckUsername);
$username
//反应是
function fnCheckUsername() {
// 进行校验之前先把值设置为false
= false;
isUsernameReady // 拿到username的值
let sUsername = $username.val();
if (sUsername === '') {
.showError('用户名不能为空');
messagereturn
}if (!(/^\w{5,20}$/).test(sUsername)) {
.showError('请输入5-11位的用户名');
message
}.ajax({
$// 前面的'/'一定不能少!!!!!!!
// 前面的'/'一定不能少!!!!!!!
// 前面的'/'一定不能少!!!!!!!
url: '/verification/username/' + sUsername + '/',
type: 'GET',
dataType: 'json',
success: function (res) {
if (res.data.count === 0) {
.showInfo(res.data.username + '可以注册');
messageelse {
} .showError(res.data.username + '该用户名已经注册');
message
}
}
})
}; })
4.7 判断手机号码是否注册功能
4.7.1 接口设计
接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | verification/mobile/(?P<mobile>\1[3-9]\d{9})/ |
参数格式 | url路径参数 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
moblie | 字符串 | 是 | 输入的手机号码 |
返回结果:
= {
json_dict 'errno': errno,
'errmsg': errmsg,
'data': {
'mobile': 138xxxxxx,
'count': 查询数据库中的手机号码数量
}, }
4.7.2 后端代码
①verification/views.py代码
import logging
import random
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
from django.views import View
from django_redis import get_redis_connection
from utils.captcha.captcha import captcha
from . import constants
from user.models import User
from utils.res_code import json_response, Code, error_map
from .forms import CheckImageForm
# 手机号码校验
def check_mobile(request, mobile):
"""
校验手机号是否存在
url:/verification/mobile/(?P<mobile>1[3-9]\d{9})/
:param request:
:param mobile:
:return:
"""
= {
data 'mobile': mobile,
'count':
# 到数据库中查询手机数量
filter(mobile=mobile).count(),
User.objects.
}return json_response(data=data)
② verification/urls.py
from django.urls import path, re_path
from . import views
= 'image_code'
app_name
= [
urlpatterns # 图片验证码生成
'image_code/', views.image_code, name='image_code'),
path(# 用户名校验
'username/(?P<username>\w{5,20})/', views.check_username, name='check_username'),
re_path(# 手机号码校验
'mobile/(?P<mobile>1[3-9]\d{9})/', views.check_mobile, name='check_mobile'),
re_path('sms_code/', views.SmsCodeView.as_view(), name='sms_codeView')
path( ]
4.7.3 前端js代码
// 定义状态变量
let isUsernameReady = false,
= false,
isPasswordReady = false,
isMobileReady
// 3. 手机号码校验
let $mobile = $('input[name="mobile"]');
.blur(fnCheckMobile);
$mobile
function fnCheckMobile(res) {
// 先设置false
= false;
isMobileReady // 拿到input框里的value
let sMobile = $mobile.val();
// 进行判断
if (sMobile === '') {
.showError(
message'手机号不能为空'
;
)return;
}if (!(/^1[3-9]\d{9}$/).test(sMobile)) {
.showError(
message'请输入正确的11位手机号码'
;
)return;
}if((/^1[3-9]\d{9}$/).test(sMobile)){
.showSuccess(
message'手机号码可以使用'
;
)
}
// 方法一(推荐)
.ajax({
$url: '/verification/mobile/' + sMobile + '/',
type: 'GET',
dataType: 'json',
})
.done((res) => {
// alert(res.data.count);
if (res.data.count !== 0) {
// 拿到res传递过来的json数据res.mobile就是json数据中的data.mobile
.showError(res.data.mobile + '已经注册,请重新输入!')
message
else {
} .showInfo(res.data.mobile + '可以使用');
message= true
isMobileReady
}
}).fail(() => {
.showError('服务器超时')
message;
})
// 方法二
// $.ajax({
// url: '/verification/mobile/'+ sMobile + '/',
// type: 'GET',
// dataType: 'json',
// success: function (data) {
// // alert(data.count);
// if(data.count !== 0){
// message.showError(data.mobile + '已经注册,请重新输入!')
// }else {
// message.showInfo(data.mobile + '可以正常使用!');
// isMobileReady = true
// }
// },
// error: function (xhr, msg) {
// message.showError('服务器超时,请重试!')
// }
// });
}
4.8 获取短信验证码功能
4.8.1 业务流程分析
- 检查图片验证码是否正确
- 检查是否在60s内发送记录
- 生成短信验证码
- 发送短信
- 保存短信验证码与发送记录
4.8.2 接口设计
接口说明:
类目 | 说明 |
---|---|
请求方法 | POST |
url定义 | verification/sms_code/ |
参数格式 | 表单 |
参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
moblie | 字符串 | 是 | 用户输入的手机号码 |
captcha | 字符串 | 是 | 用户输入的验证码文本 |
返回结果:
{
'errno': '0',
'errmsg': '短信发送成功',
}
4.8.3 后端代码
①verification/views.py代码如下:
import logging
import random
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
from django.views import View
from django_redis import get_redis_connection
from utils.captcha.captcha import captcha
from . import constants
from user.models import User
from utils.res_code import json_response, Code, error_map
from .forms import CheckImageForm
# 创建日志器
= logging.getLogger('django')
logger
# 检验手机验证码
class SmsCodeView(View):
"""
url: /sms_code/
"""
# 校验手机号码
def post(self, request):
"""
生成短信验证码
发送短信验证码
保存在什么地方
:param request:
:return:
"""
# 拿到checkImageForm里面的数据对象实例化给form
= CheckImageForm(request.POST, request=request)
form
# 成功
if form.is_valid():
# 类似字典取值拿到mobile
= form.cleaned_data.get('mobile')
mobile # 随机生成4位数验证码,列表推导式
= ''.join([random.choice('0123456789') for i in range(constants.SMS_CODE_LENGTH)])
sms_code # 将生成的短信随机码打印出来
'发送短信验证码【成功】:{} 【验证码】:{}'.format(mobile, sms_code))
logger.info(# print(sms_code)
# 短信验证码缓存到Redis中,用Redis,设置时限
# 创建短信验证码的发送记录的key
= 'sms_flag_{}'.format(mobile)
sms_flag_key # 创建短信验证码的值的发送记录的key
= 'sms_text_{}'.format(mobile)
sms_text_key # 保存验证码到Redis alias是指哪一个库,之前在settings文件中配置的Redis缓存名字
= get_redis_connection(alias='verification')
redis_conn # 创建redis管道
= redis_conn.pipeline()
pl try:
1)
pl.setex(sms_flag_key, constants.SMS_CODE_INTERVAL, *60, sms_code)
pl.setex(sms_text_key, constants.SMS_CODE_EXPIRES
pl.execute()return json_response(errmsg='短信验证码发送成功' )
except Exception as e:
'Redis执行异常: {}'.format(e))
logger.error(return json_response(errno=Code.UNKOWNERR, errmsg=error_map[Code.UNKOWNERR])
# 失败
else:
# 将表单的报错信息拼接 可能不止一条
= []
err_msg_list # errors 是一个字典,通过values可以拿到所有值
for item in form.errors.values():
# 将拿到的item(值)添加到list中
0])
err_msg_list.append(item[
# 这里加 的'/'是为了便于区分不同的报错信息
= '/'.join(err_msg_list)
err_msg_str print(err_msg_str)
return json_response(errno=Code.PARAMERR, errmsg=err_msg_str)
② verification/forms.py文件代码如下:
from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from user.models import User
# 创建手机号码校验器
= RegexValidator(r'^1[3-9]\d{9}$', '手机号码格式不正确')
mobile_validator
class CheckImageForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
# 这里的名字要和register.js中的json中传递回来的name一致
= forms.CharField(max_length=11, min_length=11, validators=[mobile_validator, ], error_messages={
mobile 'min_length': '输入的手机号码长度有误',
'max_length': '输入的手机号码长度有误',
'required': '输入的手机号码不得为空',
})
# 这里的名字要和register.js中的json中传递回来的name一致
= forms.CharField(max_length=4, min_length=4, error_messages={
captcha 'min_length': '输入的图片验证码长度有误',
'max_length': '输入的图片验证码长度有误',
'required': '图片验证码不得为空',
})
def clean(self):
= super().clean()
clean_data = clean_data.get('mobile')
mobile = clean_data.get('captcha')
captcha # 如果校验失败就会返回 none的结果
# 如果前面的校验失败了的话就没有必要往下执行
if mobile and captcha:
# 拿到保存在session中的图形验证码的value
= self.request.session.get('image_code')
image_code # session中的图形验证码和request中发送过来的captcha不一样,返回'验证码错误'
if image_code.upper() != captcha.upper():
raise forms.ValidationError('图形验证码错误!')
# 如果超过设定时间,图形验证码失效
if not captcha:
raise forms.ValidationError('图形验证码失效')
# 判断短信验证码是否过期
= get_redis_connection(alias='verification')
redis_conn if redis_conn.get('sms_flag_{}'.format(mobile)):
raise forms.ValidationError('获取短信验证码过于频繁')
# 校验手机号码是否过期
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('该手机号码已注册')
return clean_data
4.8.verification/constants.py代码如下:
from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from user.models import User
# 创建手机号码校验器
= RegexValidator(r'^1[3-9]\d{9}$', '手机号码格式不正确')
mobile_validator
class CheckImageForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
# 这里的名字要和register.js中的json中传递回来的name一致
= forms.CharField(max_length=11, min_length=11, validators=[mobile_validator, ], error_messages={
mobile 'min_length': '输入的手机号码长度有误',
'max_length': '输入的手机号码长度有误',
'required': '输入的手机号码不得为空',
})
# 这里的名字要和register.js中的json中传递回来的name一致
= forms.CharField(max_length=4, min_length=4, error_messages={
captcha 'min_length': '输入的图片验证码长度有误',
'max_length': '输入的图片验证码长度有误',
'required': '图片验证码不得为空',
})
def clean(self):
= super().clean()
clean_data = clean_data.get('mobile')
mobile = clean_data.get('captcha')
captcha # 如果校验失败就会返回 none的结果
# 如果前面的校验失败了的话就没有必要往下执行
if mobile and captcha:
# 拿到保存在session中的图形验证码的value
= self.request.session.get('image_code')
image_code # session中的图形验证码和request中发送过来的captcha不一样,返回'验证码错误'
if image_code.upper() != captcha.upper():
raise forms.ValidationError('图形验证码错误!')
# 如果超过设定时间,图形验证码失效
if not captcha:
raise forms.ValidationError('图形验证码失效')
# 判断短信验证码是否过期
= get_redis_connection(alias='verification')
redis_conn if redis_conn.get('sms_flag_{}'.format(mobile)):
raise forms.ValidationError('获取短信验证码过于频繁')
# 校验手机号码是否过期
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('该手机号码已注册')
return clean_data
mobile = clean_data.get('mobile')
captcha = clean_data.get('captcha')
# 如果校验失败就会返回 none的结果
# 如果前面的校验失败了的话就没有必要往下执行
if mobile and captcha:
# 拿到保存在session中的图形验证码的value
image_code = self.request.session.get('image_code')
# session中的图形验证码和request中发送过来的captcha不一样,返回'验证码错误'
if image_code.upper() != captcha.upper():
raise forms.ValidationError('图形验证码错误!')
# 如果超过设定时间,图形验证码失效
if not captcha:
raise forms.ValidationError('图形验证码失效')
# 判断短信验证码是否过期
redis_conn = get_redis_connection(alias='verification')
if redis_conn.get('sms_flag_{}'.format(mobile)):
raise forms.ValidationError('获取短信验证码过于频繁')
# 校验手机号码是否过期
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('该手机号码已注册')
return clean_data
4.8.verification/constants.py代码如下:
```python
from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from user.models import User
# 创建手机号码校验器
mobile_validator = RegexValidator(r'^1[3-9]\d{9}$', '手机号码格式不正确')
class CheckImageForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
# 这里的名字要和register.js中的json中传递回来的name一致
mobile = forms.CharField(max_length=11, min_length=11, validators=[mobile_validator, ], error_messages={
'min_length': '输入的手机号码长度有误',
'max_length': '输入的手机号码长度有误',
'required': '输入的手机号码不得为空',
})
# 这里的名字要和register.js中的json中传递回来的name一致
captcha = forms.CharField(max_length=4, min_length=4, error_messages={
'min_length': '输入的图片验证码长度有误',
'max_length': '输入的图片验证码长度有误',
'required': '图片验证码不得为空',
})
def clean(self):
clean_data = super().clean()
mobile = clean_data.get('mobile')
captcha = clean_data.get('captcha')
# 如果校验失败就会返回 none的结果
# 如果前面的校验失败了的话就没有必要往下执行
if mobile and captcha:
# 拿到保存在session中的图形验证码的value
image_code = self.request.session.get('image_code')
# session中的图形验证码和request中发送过来的captcha不一样,返回'验证码错误'
if image_code.upper() != captcha.upper():
raise forms.ValidationError('图形验证码错误!')
# 如果超过设定时间,图形验证码失效
if not captcha:
raise forms.ValidationError('图形验证码失效')
# 判断短信验证码是否过期
redis_conn = get_redis_connection(alias='verification')
if redis_conn.get('sms_flag_{}'.format(mobile)):
raise forms.ValidationError('获取短信验证码过于频繁')
# 校验手机号码是否过期
if User.objects.filter(mobile=mobile).count():
raise forms.ValidationError('该手机号码已注册')
return clean_data