Flask、sqlite3、pipenv实现用户注册和登录(HandBook,菜鸟都会的)

Ubuntu 16.04+Python 3.5.2+Vim

github URL查看每个步骤的代码

一、环境搭建
/usr/ccdocs下新建一个目录【myproject】,并将其更改为一个Python项目的文件夹,启动Pipenv:

chenchen@chenchen-ubuntu:~$ cd /usr/ccdocs
chenchen@chenchen-ubuntu:/usr/ccdocs$ sudo mkdir myproject
chenchen@chenchen-ubuntu:/usr/ccdocs$ sudo chmod 777 myproject
chenchen@chenchen-ubuntu:/usr/ccdocs$ cd myproject
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv --three
Creating a virtualenv for this project…
Pipfile: /usr/ccdocs/myproject/Pipfile
Using /usr/bin/python3.5 (3.5.2) to create virtualenv…
⠼Running virtualenv with interpreter /usr/bin/python3.5
Using base prefix '/usr'
New python executable in /home/chenchen/.local/share/virtualenvs/myproject-f5Hwi5Rz/bin/python3.5
Also creating executable in /home/chenchen/.local/share/virtualenvs/myproject-f5Hwi5Rz/bin/python
Installing setuptools, pip, wheel...
done.

Virtualenv location: /home/chenchen/.local/share/virtualenvs/myproject-f5Hwi5Rz
Creating a Pipfile for this project…
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ ll
总用量 12
drwxrwxrwx 2 root     root     4096 11月 14 16:49 ./
drwxr-xr-x 4 root     root     4096 11月 14 15:58 ../
-rw-rw-r-- 1 chenchen chenchen  138 11月 14 16:49 Pipfile
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv lock
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (a79791)!
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ ll
总用量 16
drwxrwxrwx 2 root     root     4096 11月 14 17:16 ./
drwxr-xr-x 4 root     root     4096 11月 14 15:58 ../
-rw-rw-r-- 1 chenchen chenchen  138 11月 14 16:49 Pipfile
-rw-r--r-- 1 chenchen chenchen  453 11月 14 17:16 Pipfile.lock
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv shell
Launching subshell in virtual environment…
chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$  . /home/chenchen/.local/share/virtualenvs/myproject-f5Hwi5Rz/bin/activate
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$

安装Flask:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv install flask
Installing flask…
Collecting flask
...
...
Successfully installed Jinja2-2.10 MarkupSafe-1.1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-1.1.0

Adding flask to Pipfile's [packages]…
Pipfile.lock (e239e5) out of date, updating to (a79791)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (e239e5)!
Installing dependencies from Pipfile.lock (e239e5)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 6/6 — 00:00:01

二、注册登录项目 创建过程
1、

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ sudo mkdir app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ sudo chmod 777 app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim __init__.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ ll
总用量 12
drwxrwxrwx 2 root     root     4096 11月 14 18:39 ./
drwxrwxrwx 3 root     root     4096 11月 14 18:31 ../
-rw-rw-r-- 1 chenchen chenchen   71 11月 14 18:39 __init__.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cat __init__.py
from flask import Flask

app = Flask(__name__)

from app import routes
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim routes.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cat routes.py
from app import app

@app.route('/')
@app.route('/index')

def index():
	return "Hello, World!"
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/$ vim run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/$ cat run.py
from app import app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree#展示项目结构图
.
├── app
│   ├── __init__.py
│   └── routes.py
├── Pipfile
├── Pipfile.lock
└── run.py

1 directory, 5 files
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$

运行程序

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask run
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [14/Nov/2018 18:53:29] "GET / HTTP/1.1" 200 -

Chrome浏览器输入:127.0.0.1:5000
在这里插入图片描述
运行OK。
接着实现git 分支管理:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git init
已初始化空的 Git 仓库于 /usr/ccdocs/myproject/.git/
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ ll
总用量 32
drwxrwxrwx 4 root     root     4096 11月 14 22:36 ./
drwxr-xr-x 4 root     root     4096 11月 14 15:58 ../
drwxrwxrwx 2 root     root     4096 11月 14 18:50 app/
drwxrwxr-x 7 chenchen chenchen 4096 11月 14 22:36 .git/
-rw-rw-r-- 1 chenchen chenchen  150 11月 14 17:36 Pipfile
-rw-r--r-- 1 chenchen chenchen 4564 11月 14 17:37 Pipfile.lock
-rw-rw-r-- 1 chenchen chenchen   20 11月 14 18:44 run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 master

尚无提交

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	Pipfile
	Pipfile.lock
	app/
	run.py

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile.lock
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "搭建初始框架"
[master(根提交) 6596460] 搭建初始框架
 5 files changed, 115 insertions(+)
 create mode 100644 Pipfile
 create mode 100644 Pipfile.lock
 create mode 100644 app/__init__.py
 create mode 100644 app/routes.py
 create mode 100644 run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 master
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v01
切换到一个新分支 'v01'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v01
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git branch
  master
* v01
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v02
切换到一个新分支 'v02'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git branch
  master
  v01
* v02
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v02
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ 

2、模板定义

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v02
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ cd app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo mkdir templates
[sudo] chenchen 的密码: 
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo chmod 777 templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ vim index.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ cat index.html
<html>
	<head>
		<title>{{ title }}-Home </title>
	</head>
	<body>
		<h1>Hello, {{ user.username }}!</h1>
	</body>
</html>
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim routes.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cat routes.py
from app import app
from flask import render_template

@app.route('/')
@app.route('/index')

def index():
	user = {'username':'chen'}
	return render_template('index.html', title='首页', user=user)
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask run
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [14/Nov/2018 23:14:18] "GET / HTTP/1.1" 200 -

在这里插入图片描述

在templates下定义一个基础模板base.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ cd app/templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ vim base.html

代码如下:

<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			<a href="#">登录</a> | <a href="#">注册</a>
		</div>
		<hr>
		{%  block content %}
		{% endblock %}
	</body>
</html>

有了模板就可以简化index.html了:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ vim index.html

代码如下:

{% extends "base.html" %}

{% block content %}
	<h1>这里是index页面,我在完成注册、登录功能</h1>
{% endblock %}

修改routes.py文件,代码如下:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim routes.py
from app import app
from flask import render_template

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

运行程序,效果如下:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask run
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [15/Nov/2018 11:11:03] "GET / HTTP/1.1" 200 -

在这里插入图片描述

提交git操作,并将分支v02合并到master:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v02
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git checkout -- <文件>..." 丢弃工作区的改动)

	修改:     app/routes.py

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	app/templates/

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/templates/
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/routes.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v02
要提交的变更:
  (使用 "git reset HEAD <文件>..." 以取消暂存)

	修改:     app/routes.py
	新文件:   app/templates/base.html
	新文件:   app/templates/index.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "使用模板"
[v02 a3858ea] 使用模板
 3 files changed, 20 insertions(+), 2 deletions(-)
 create mode 100644 app/templates/base.html
 create mode 100644 app/templates/index.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v02
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git branch
  master
  v01
* v02
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git merge v02
更新 6596460..a3858ea
Fast-forward
 app/routes.py            |  4 ++--
 app/templates/base.html  | 13 +++++++++++++
 app/templates/index.html |  5 +++++
 3 files changed, 20 insertions(+), 2 deletions(-)
 create mode 100644 app/templates/base.html
 create mode 100644 app/templates/index.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$

文件结构:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree
.
├── app
│   ├── __init__.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       └── index.html
├── Pipfile
├── Pipfile.lock
└── run.py

2 directories, 7 files

3、
新建分支v03

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ git status
位于分支 master
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ git checkout -b v03
切换到一个新分支 'v03'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ git diff master
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ git status
位于分支 v03
无文件要提交,干净的工作区

创建Web表单,用于接受用户输入。

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ pipenv install flask-wtf
Installing flask-wtf…
Collecting flask-wtf
...
...
Successfully installed WTForms-2.2.1 flask-wtf-0.14.2

Adding flask-wtf to Pipfile's [packages]…
Pipfile.lock (111144) out of date, updating to (e239e5)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (111144)!
Installing dependencies from Pipfile.lock (111144)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 8/8 — 00:00:01

根目录下,增加配置文件config.py

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim config.py
import os
class Config(object):
	SECRET_KEY = os.environ.get('SECRET_KEY') or 'you will never guess me'

Flask应用程序读取配置文件:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ cd app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim __init__.py
from flask import Flask
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

from app import routes

创建登录表单

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim forms.py
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,BooleanField,SubmitField
from wtforms.validators import DataRequired

class LoginForm(FlaskForm):
	username = StringField('用户名',validators=[DataRequired()])
	password = PasswordField('密码',validators=[DataRequired()])
	remember_me = BooleanField('记住我')
	submit = SubmitField('登录')

将登录表单添加到HTML模板中,呈现在网页上。

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ vim login.html

login.html代码:

{% extends "base.html" %}
{% block content %}
	<h1>登录</h1>
	<form action="" method="post" novalidate>
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}
		</p>
		<p>
			{{ form.remember_me() }}
			{{ form.remember_me.label }}
		</p>
		<p>
			{{ form.submit() }}
		</p>
{% endblock %}

编写一个登录的视图函数,用于渲染login.html模板:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim routes.py

routes.py代码:

from app import app
from flask import render_template
from app.forms import LoginForm

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

@app.route('/login')
def login():
	form = LoginForm()
	return render_template('login.html', title='登录', form=form)

基础模板base.html 导航栏增加登录链接:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ vim base.html
<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			<a href="/login">登录</a> | <a href="#">注册</a>
		</div>
		<hr>
		{%  block content %}
		{% endblock %}
	</body>
</html>

运行程序,查看效果:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask run
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [15/Nov/2018 12:27:13] "GET /login HTTP/1.1" 200 -

在这里插入图片描述

处理用户提交的数据,接受、验证用户的数据,routes.py

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app
from flask import render_template, flash, redirect
from app.forms import LoginForm

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	form = LoginForm()
	if form.validate_on_submit():
		return redirect('index')
	return render_template('login.html', title='登录', form=form)

增强字段验证,login.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/login.html
{% extends "base.html" %}
{% block content %}
	<h1>登录</h1>
	<form action="" method="post" novalidate>
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}<br>
			{% for error in form.username.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}<br>
			{% for error in form.password.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.remember_me() }}
			{{ form.remember_me.label }}
		</p>
		<p>
			{{ form.submit() }}
		</p>
{% endblock %}

生成URL,使用url_for()函数:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/base.html
<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			<a href="{{ url_for('login') }}">登录</a> | <a href="#">注册</a>
		</div>
		<hr>
		{%  block content %}
		{% endblock %}
	</body>
</html>
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app
from flask import render_template, flash, redirect, url_for
from app.forms import LoginForm

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	form = LoginForm()
	if form.validate_on_submit():
		return redirect(url_for('index'))
	return render_template('login.html', title='登录', form=form)

项目结构:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree
.
├── app
│   ├── forms.py
│   ├── __init__.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       ├── index.html
│       └── login.html
├── config.py
├── Pipfile
├── Pipfile.lock
└── run.py

2 directories, 10 files

git操作:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v03
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git checkout -- <文件>..." 丢弃工作区的改动)

	修改:     Pipfile
	修改:     Pipfile.lock
	修改:     app/__init__.py
	修改:     app/routes.py
	修改:     app/templates/base.html

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	app/forms.py
	app/templates/login.html
	config.py

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/forms.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/templates/login.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add config.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/forms.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/templates/login.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add config.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile.lock
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/__init__.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/routes.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app/templates/base.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "完成web表单"
[v03 34f9e09] 完成web表单
 8 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 app/forms.py
 create mode 100644 app/templates/login.html
 create mode 100644 config.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v03
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git merge v03
更新 a3858ea..34f9e09
Fast-forward
 Pipfile                  |  1 +
 Pipfile.lock             | 17 ++++++++++++++++-
 app/__init__.py          |  2 ++
 app/forms.py             |  9 +++++++++
 app/routes.py            | 10 +++++++++-
 app/templates/base.html  |  2 +-
 app/templates/login.html | 27 +++++++++++++++++++++++++++
 config.py                |  3 +++
 8 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 app/forms.py
 create mode 100644 app/templates/login.html
 create mode 100644 config.py

4、数据库

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v04
切换到一个新分支 'v04'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v04
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git branch
  master
  v01
  v02
  v03
* v04

安装sqlite3:在开发过程中使用sqlite3,在生产服务器上部署时可使用MySQL,无需改变应用程序。

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ sudo apt-get install sqlite3
[sudo] chenchen 的密码: 
正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
...
...
正准备解包 .../sqlite3_3.11.0-1ubuntu1_amd64.deb  ...
正在解包 sqlite3 (3.11.0-1ubuntu1) ...
正在处理用于 man-db (2.7.5-1) 的触发器 ...
正在设置 sqlite3 (3.11.0-1ubuntu1) ...
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ sqlite3 -version
3.11.0 2016-02-15 17:29:24 3d862f207e3adc00f78066799ac5a8c282430a5f

安装Flask-SQLAlchemy:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv install flask-sqlalchemy
...
...
Successfully installed SQLAlchemy-1.2.14 flask-sqlalchemy-2.3.2

Adding flask-sqlalchemy to Pipfile's [packages]…
Pipfile.lock (3940c2) out of date, updating to (111144)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (3940c2)!
Installing dependencies from Pipfile.lock (3940c2)…
  ?   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 10/10 — 00:00:02

Flask-SQLAlchemy配置:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim config.py
import os

basedir = os.path.abspath(os.path.dirname(__file__))

class Config(object):
	SECRET_KEY = os.environ.get('SECRET_KEY') or 'you will never guess me'
	SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or 'sqlite:///' +os.path.join(basedir, 'app.db')
	SQLALCHEMY_TRACK_MODIFICATIONS = False
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/__init__.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)

from app import routes, models

为用户创建数据库模型

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/models.py
from app import db

class User(db.Model):
	id = db.Column(db.Integer, primary_key=True)
	username = db.Column(db.String(64), index=True, unique=True)
	email = db.Column(db.String(64), index=True, unique=True)
	password_hash = db.Column(db.String(128))
	
	def __repr__(self):
		return '<User {}>'.format(self.username)

测试一下用户数据库模型:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ python
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from app.models import User
>>> u = User(username='chenchen', email='chenchen@eaxmple.com')
>>> u
<User chenchen>
>>> exit()

创建shell上下文,方便在应用程序上下文中启动Python解释器:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim run.py
from app import app,db
from app.models import User

@app.shell_context_processor
def make_shell_context():
	return {'db':db, 'User':User}

添加了shell 上下文处理器功能后,我们可以方便地使用数据库实体,而无需导入它们:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ export FLASK_APP=run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask shell
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
App: app [production]
Instance: /usr/ccdocs/myproject/instance
>>> db
<SQLAlchemy engine=sqlite:usr/ccdocs/myproject/app.db>
>>> User
<class 'app.models.User'>
>>> exit()

创建一个sqlite3 数据库:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ sqlite3 app.db
SQLite version 3.11.0 2016-02-15 17:29:24
Enter ".help" for usage hints.
sqlite> CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(64), email VARCHAR(64), password_hash VARCHAR(128));
sqlite> .quit
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ flask shell
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
App: app [production]
Instance: /usr/ccdocs/myproject/instance
>>> u = User(username='lvlv', email='lvlv@example.com')
>>> db.session.add(u)
>>> db.session.commit()
>>> users = User.query.all()
>>> users
[<User lvlv>]
>>> exit()

项目结构:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree
.
├── app
│   ├── forms.py
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       ├── index.html
│       └── login.html
├── app.db
├── config.py
├── Pipfile
├── Pipfile.lock
└── run.py

2 directories, 12 files

git操作:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v04
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git checkout -- <文件>..." 丢弃工作区的改动)

	修改:     Pipfile
	修改:     Pipfile.lock
	修改:     app/__init__.py
	修改:     config.py
	修改:     run.py

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	app.db
	app/models.py

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add app.db app/models.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile Pipfile.lock app/__init__.py config.py run.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "添加User模型"
[v04 3e424f2] 添加User模型
 7 files changed, 40 insertions(+), 3 deletions(-)
 create mode 100644 app.db
 create mode 100644 app/models.py
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v04
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git merge v04
更新 34f9e09..3e424f2
Fast-forward
 Pipfile         |   1 +
 Pipfile.lock    |  16 +++++++++++++++-
 app.db          | Bin 0 -> 3072 bytes
 app/__init__.py |   4 +++-
 app/models.py   |  10 ++++++++++
 config.py       |   5 +++++
 run.py          |   7 ++++++-
 7 files changed, 40 insertions(+), 3 deletions(-)
 create mode 100644 app.db
 create mode 100644 app/models.py

5、用户登录
git 新建分支:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 master
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v05
切换到一个新分支 'v05'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v05
无文件要提交,干净的工作区

给用户模型的password_hash字段实现密码哈希:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/models.py
from app import db
from werkzeug.security import generate_password_hash, check_password_hash
class User(db.Model):
	id = db.Column(db.Integer, primary_key=True)
	username = db.Column(db.String(64), index=True, unique=True)
	email = db.Column(db.String(64), index=True, unique=True)
	password_hash = db.Column(db.String(128))
	
	def __repr__(self):
		return '<User {}>'.format(self.username)
	
	def set_password(self, password):
		self.password_hash = generate_password_hash(password)
	
	def check_password(self, password):
		return check_password_hash(self.password_hash, password)

安装Flask-Login:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ pipenv install flask-login
Installing flask-login…
...
...
Successfully installed flask-login-0.4.1

Adding flask-login to Pipfile's [packages]…
Pipfile.lock (8930f0) out of date, updating to (3940c2)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (8930f0)!
Installing dependencies from Pipfile.lock (8930f0)…

初始化Flask-Login:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/__init__.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)

from app import routes, models

为Flask-Login准备用户模型、用户加载器功能:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/models.py
from app import db,login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin

class User(UserMixin, db.Model):
	id = db.Column(db.Integer, primary_key=True)
	username = db.Column(db.String(64), index=True, unique=True)
	email = db.Column(db.String(64), index=True, unique=True)
	password_hash = db.Column(db.String(128))
	
	def __repr__(self):
		return '<User {}>'.format(self.username)
	
	def set_password(self, password):
		self.password_hash = generate_password_hash(password)
	
	def check_password(self, password):
		return check_password_hash(self.password_hash, password)

@login.user_loader
def load_user(id):
        return User.query.get(int(id))

修改用户登录视图函数:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app
from flask import render_template, flash, redirect, url_for
from app.forms import LoginForm
from flask_login import current_user, login_user
from app.models import User

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	if current_user.is_authenticated:
		return redirect(url_for('index')
	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(username=form.username.data).first()
		if user is None or not user.check_password(form.password.data):
			flash('无效的用户名或密码')
			return redirect(url_for('login'))
		login_user(user, remember=form.remember_me.data)
		return redirect(url_for('index'))
	return render_template('login.html', title='登录', form=form)

增加用户退出视图函数:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app
from flask import render_template, flash, redirect, url_for
from app.forms import LoginForm
from flask_login import current_user, login_user, logout_user
from app.models import User

@app.route('/')
@app.route('/index')
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	if current_user.is_authenticated:
		return redirect(url_for('index')
	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(username=form.username.data).first()
		if user is None or not user.check_password(form.password.data):
			flash('无效的用户名或密码')
			return redirect(url_for('login'))
		login_user(user, remember=form.remember_me.data)
		return redirect(url_for('index'))
	return render_template('login.html', title='登录', form=form)

@app.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('index'))

给基础模板base.html增加条件登录和退出链接:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/base.html
<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			{% if current_user.is_anonymous %}
				<a href="{{ url_for('login') }}">登录</a> | <a href="#">注册</a>
			{% else %}
				<a href="{{ url_for('logout') }}">退出</a>
			{% endif %}
		</div>
		<hr>
		{%  block content %}
		{% endblock %}
	</body>
</html>

要求用户登录:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/__init__.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)
login.login_view = 'login'

from app import routes, models

app/routes.py给index视图函数添加@login_required装饰器,并重定向到next页面:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app
from flask import render_template, flash, redirect, url_for, request
from werkzeug.urls import url_parse
from app.forms import LoginForm
from flask_login import current_user, login_user, logout_user, login_required
from app.models import User

@app.route('/')
@app.route('/index')
@login_required
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	if current_user.is_authenticated:
		return redirect(url_for('index'))
	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(username=form.username.data).first()
		if user is None or not user.check_password(form.password.data):
			flash('无效的用户名或密码')
			return redirect(url_for('login'))
		login_user(user, remember=form.remember_me.data)
		
		next_page = request.args.get('next')
		if not next_page or url_parse(next_page).netloc != '':
			next_page = url_for('index')
		return redirect(next_page)
	return render_template('login.html', title='登录', form=form)

@app.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('index'))

分别在基础模板导航栏、index模板中显示登录用户:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/base.html
<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			{% if current_user.is_anonymous %}
				<a href="{{ url_for('login') }}">登录</a> | <a href="#">注册</a>
			{% else %}
				[{{ current_user.username }}] | <a href="{{ url_for('logout') }}">退出</a>
			{% endif %}
		</div>
		<hr>
		{%  block content %}
		{% endblock %}
	</body>
</html>
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/index.html
{% extends "base.html" %}

{% block content %}
	<h1>这里是index页面,我在完成注册、登录功能</h1>
	<p>我是 {{ current_user.username}}</p>
{% endblock %}

改善体验,如果输入密码或用户名,弹出提示消息:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/base.html
<html>
	<head>
		<title>{{ title }}-云测平台</title>
	</head>
	<body>
		<div>
			{% if current_user.is_anonymous %}
				<a href="{{ url_for('login') }}">登录</a> | <a href="{{ url_for('register') }}">注册</a>
			{% else %}
				[{{ current_user.username }}] | <a href="{{ url_for('logout') }}">退出</a>
			{% endif %}
		</div>
		<hr>
		{% with messages=get_flashed_messages() %}
			{% if messages %}
				<ul>
					{% for message in messages %}
					<li>{{ message }}</li>
					{% endfor %}
				</ul>
			{% endif %}
		{% endwith %}
		{%  block content %}
		{% endblock %}
	</body>
</html>

用户注册:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,BooleanField,SubmitField
from wtforms.validators import DataRequired,ValidationError,Email,EqualTo
from app.models import User

class LoginForm(FlaskForm):
	username = StringField('用户名',validators=[DataRequired()])
	password = PasswordField('密码',validators=[DataRequired()])
	remember_me = BooleanField('记住我')
	submit = SubmitField('登录')

class RegistrationForm(FlaskFrom):
	username = StringField('用户名', validators=[DataRequired()])
	email = StringField('邮箱', validators=[DataRequired()])
	password = PasswordField('密码', validators=[DataRequired()])
	password2 = PasswordField('重输一次密码', validators=[DataRequired(), EqualTo('password')])
	submit = SubmitField('注册')
	
	def validate_username(self,username):
		user = User.query.filter_by(username=username.data).first()
		if user is not None:
			raise ValidationError('用户名被占用')
	def validate_email(self, email):
		user = User.query.filter_by(email=email.data).first()
		if user is not None:
			raise ValidationError('邮箱被占用')
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/register.html
{% extends "base.html" %}

{% block content %}
	<h1>用户注册</h1>
	<form action="" method="post">
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}<br>
			{% for error in form.username.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.email.label }}<br>
			{{ form.email(size=64) }}<br>
			{% for error in form.email.error %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}<br>
			{% for error in form.password.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password2.label }}<br>
			{{ form.password2(size=32) }}<br>
			{% for error in form.password2.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>{{ form.submit() }}</p>
	</form>
{% endblock %}
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/login.html
{% extends "base.html" %}
{% block content %}
	<h1>登录</h1>
	<form action="" method="post" novalidate>
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}<br>
			{% for error in form.username.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}<br>
			{% for error in form.password.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.remember_me() }}
			{{ form.remember_me.label }}
		</p>
		<p>
			{{ form.submit() }}
		</p>
	</form>
	<p>新用户?<a href="{{ url_for('register') }}">点击注册</a></p>
{% endblock %}

添加用户注册视图函数:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/routes.py
from app import app,db
from flask import render_template, flash, redirect, url_for, request
from werkzeug.urls import url_parse
from app.forms import LoginForm,RegistrationForm
from flask_login import current_user, login_user, logout_user, login_required
from app.models import User

@app.route('/')
@app.route('/index')
@login_required
def index():
	return render_template('index.html', title='首页')

@app.route('/login', methods=['GET', 'POST'])
def login():
	if current_user.is_authenticated:
		return redirect(url_for('index'))
	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(username=form.username.data).first()
		if user is None or not user.check_password(form.password.data):
			flash('无效的用户名或密码')
			return redirect(url_for('login'))
		login_user(user, remember=form.remember_me.data)
		
		next_page = request.args.get('next')
		if not next_page or url_parse(next_page).netloc != '':
			next_page = url_for('index')
		return redirect(next_page)
	return render_template('login.html', title='登录', form=form)

@app.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('index'))

@app.route('/register', methods=['GET','POST'])
def register():
	if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('恭喜,注册成功')
        return redirect(url_for('login'))
    return render_template('register.html', title='注册', form=form)

在这里插入图片描述
在这里插入图片描述
git操作:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v05
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git checkout -- <文件>..." 丢弃工作区的改动)

	修改:     Pipfile
	修改:     Pipfile.lock
	修改:     app.db
	修改:     app/__init__.py
	修改:     app/forms.py
	修改:     app/models.py
	修改:     app/routes.py
	修改:     app/templates/base.html
	修改:     app/templates/index.html
	修改:     app/templates/login.html

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	app/templates/register.html

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add Pipfile Pipfile.lock app.db app/__init__.py app/forms.py app/models.py app/routes.py app/templates/base.html app/templates/index.html app/templates/login.html app/templates/register.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v05
要提交的变更:
  (使用 "git reset HEAD <文件>..." 以取消暂存)

	修改:     Pipfile
	修改:     Pipfile.lock
	修改:     app.db
	修改:     app/__init__.py
	修改:     app/forms.py
	修改:     app/models.py
	修改:     app/routes.py
	修改:     app/templates/base.html
	修改:     app/templates/index.html
	修改:     app/templates/login.html
	新文件:   app/templates/register.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "完成用户登录"
[v05 71285d0] 完成用户登录
 11 files changed, 136 insertions(+), 9 deletions(-)
 create mode 100644 app/templates/register.html
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v05
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git merge v05
更新 3e424f2..7857ae5
Fast-forward
 Pipfile                     |   1 +
 Pipfile.lock                |   9 ++++++++-
 app.db                      | Bin 3072 -> 3072 bytes
 app/__init__.py             |   3 +++
 app/forms.py                |  19 ++++++++++++++++++-
 app/models.py               |  16 ++++++++++++++--
 app/routes.py               |  42 ++++++++++++++++++++++++++++++++++++++----
 app/templates/base.html     |  15 ++++++++++++++-
 app/templates/index.html    |   1 +
 app/templates/login.html    |   2 ++
 app/templates/register.html |  37 +++++++++++++++++++++++++++++++++++++
 11 files changed, 136 insertions(+), 9 deletions(-)
 create mode 100644 app/templates/register.html

项目结构:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree
.
├── app
│   ├── forms.py
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   └── templates
│       ├── base.html
│       ├── index.html
│       ├── login.html
│       └── register.html
├── app.db
├── config.py
├── Pipfile
├── Pipfile.lock
└── run.py

2 directories, 13 files

6、蓝图
git操作,新建分支:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 master
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v06
切换到一个新分支 'v06'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout -b v06
切换到一个新分支 'v06'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ cd app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo mkdir auth
[sudo] chenchen 的密码: 
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo chmod 777 auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo mv routes.py forms.py auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd templates
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ sudo mkdir auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ sudo chmod 777 auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ sudo mv  login.html register.html auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/templates$ cd ..
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ cd auth
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app/auth$ vim __init__.py
app/auth/__init__.py代码:
from flask import Blueprint

bp = Blueprint('auth', __name__)

from app.auth import routes

修改app/__init__.py:应用工厂模式

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/__init__.py
import os
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask,request,current_app
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

db = SQLAlchemy()
login = LoginManager()
login.login_view = 'auth.login'
login.login_message = '请先登录以进入该页面'
bootstrap = Bootstrap()

def create_app(config_class=Config):
	app = Flask(__name__)
	app.config.from_object(config_class)

	db.init_app(app)
	login.init_app(app)
	bootstrap.init_app(app)

	from app.auth import bp as auth_bp
	app.register_blueprint(auth_bp, url_prefix='/auth')
	
	from app.main import bp as main_bp
	app.register_blueprint(main_bp)
	
	if not app.debug and not app.testing:
		if not os.path.exists('logs'):
			os.mkdir('logs')
		file_handler = RotatingFileHandler('logs/app.log', maxBytes=10240, backupCount=10)
		file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s:%(message)s''[in %(pathname)s:%(lineno)d]'))
		file_handler.setLevel(logging.INFO)
		app.logger.addHandler(file_handler)
		
		app.logger.setLevel(logging.INFO)
		app.logger.info('程序启动')
	return app

from app import models

修改app/auth/routes.py文件:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/auth/routes.py
from app import db
from flask import render_template, flash, redirect, url_for, request
from werkzeug.urls import url_parse
from app.auth.forms import LoginForm,RegistrationForm
from flask_login import current_user, login_user, logout_user
from app.auth import bp
from app.models import User

@bp.route('/login', methods=['GET', 'POST'])
def login():
	if current_user.is_authenticated:
		return redirect(url_for('main.index'))
	form = LoginForm()
	if form.validate_on_submit():
		user = User.query.filter_by(username=form.username.data).first()
		if user is None or not user.check_password(form.password.data):
			flash('无效的用户名或密码')
			return redirect(url_for('auth.login'))
		login_user(user, remember=form.remember_me.data)
		
		next_page = request.args.get('next')
		if not next_page or url_parse(next_page).netloc != '':
			next_page = url_for('main.index')
		return redirect(next_page)
	return render_template('auth/login.html', title='登录', form=form)

@bp.route('/logout')
def logout():
	logout_user()
	return redirect(url_for('main.index'))

@bp.route('/register', methods=['GET','POST'])
def register():
	if current_user.is_authenticated:
        	return redirect(url_for('main.index'))
	form = RegistrationForm()
	if form.validate_on_submit():
		user = User(username=form.username.data, email=form.email.data)
		user.set_password(form.password.data)
		db.session.add(user)
		db.session.commit()
		flash('恭喜,注册成功')
		return redirect(url_for('auth.login'))
	return render_template('auth/register.html', title='注册', form=form)

修改app/templates/auth/login.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/auth/login.html
{% extends "base.html" %}
{% block content %}
	<h1>登录</h1>
	<form action="" method="post" novalidate>
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}<br>
			{% for error in form.username.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}<br>
			{% for error in form.password.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.remember_me() }}
			{{ form.remember_me.label }}
		</p>
		<p>
			{{ form.submit() }}
		</p>
	</form>
	<p>新用户?<a href="{{ url_for('auth.register') }}">点击注册</a></p>
{% endblock %}

修改app/templates/auth/register.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/auth/register.html
{% extends "base.html" %}

{% block content %}
	<h1>用户注册</h1>
	<form action="" method="post">
		{{ form.hidden_tag() }}
		<p>
			{{ form.username.label }}<br>
			{{ form.username(size=32) }}<br>
			{% for error in form.username.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.email.label }}<br>
			{{ form.email(size=64) }}<br>
			{% for error in form.email.error %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password.label }}<br>
			{{ form.password(size=32) }}<br>
			{% for error in form.password.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>
			{{ form.password2.label }}<br>
			{{ form.password2(size=32) }}<br>
			{% for error in form.password2.errors %}
				<span style="color:red;">[{{ error }}]</span>
			{% endfor %}
		</p>
		<p>{{ form.submit() }}</p>
	</form>
{% endblock %}

应用程序 main 蓝图

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ cd app
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo mkdir main
[sudo] chenchen 的密码: 
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ sudo chmod 777 main
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim main/__init__.py

代码:

from flask import Blueprint

bp = Blueprint('main', __name__)

from app.main import routes
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject/app$ vim main/routes.py
from flask import render_template
from flask_login import current_user,login_required
from app import db
from app.main import bp

@bp.route('/', methods=['GET', 'POST'])
@bp.route('/index', methods=['GET', 'POST'])
@login_required
def index():
	return render_template('index.html', title='首页')

修改run.py

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim run.py
from app import create_app, db
from app.models import User

app = create_app()

@app.shell_context_processor
def make_shell_context():
	return {'db':db, 'User':User}
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/models.py
from app import db,login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin

class User(UserMixin, db.Model):
	id = db.Column(db.Integer, primary_key=True)
	username = db.Column(db.String(64), index=True, unique=True)
	email = db.Column(db.String(64), index=True, unique=True)
	password_hash = db.Column(db.String(128))
	
	def __repr__(self):
		return '<User {}>'.format(self.username)
	
	def set_password(self, password):
		self.password_hash = generate_password_hash(password)
	
	def check_password(self, password):
		return check_password_hash(self.password_hash, password)

@login.user_loader
def load_user(id):
        return User.query.get(int(id))

修改base.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/base.html
<html>
    <head>
        <title>{{ title }}-云测平台</title>
    </head>
    <body>
        <div>
            {% if current_user.is_anonymous %}
                <a href="{{ url_for('auth.login') }}">登录</a> | <a href="{{ url_for('auth.register') }}">注册</a>
            {% else %}
                [{{ current_user.username }}] | <a href="{{ url_for('auth.logout') }}">退出</a>
            {% endif %}
        </div>
        <hr>
        {% with messages=get_flashed_messages() %}
            {% if messages %}
                <ul>
                    {% for message in messages %}
                    <li>{{ message }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
        {% endwith %}
        {%  block content %}
        {% endblock %}
    </body>
</html>

修改index.html

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim app/templates/index.html
{% extends "base.html" %}

{% block content %}
	<h1>这里是index页面,已完成注册、登录功能</h1><br>
	<h2>我是 {{ current_user.username}}</h2>
{% endblock %}

在这里插入图片描述
在这里插入图片描述

git操作:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ touch .gitignore
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ vim .gitignore
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v06
要提交的变更:
  (使用 "git reset HEAD <文件>..." 以取消暂存)

	新文件:   app/auth/__init__.py
	新文件:   app/auth/forms.py
	新文件:   app/auth/routes.py
	新文件:   app/main/__init__.py
	新文件:   app/main/routes.py
	新文件:   app/templates/auth/login.html
	新文件:   app/templates/auth/register.html
	新文件:   logs/app.log
	新文件:   logs/app.log.1
	新文件:   logs/app.log.2

尚未暂存以备提交的变更:
  (使用 "git add/rm <文件>..." 更新要提交的内容)
  (使用 "git checkout -- <文件>..." 丢弃工作区的改动)

	修改:     app.db
	修改:     app/__init__.py
	删除:     app/forms.py
	修改:     app/models.py
	删除:     app/routes.py
	修改:     app/templates/base.html
	修改:     app/templates/index.html
	删除:     app/templates/login.html
	删除:     app/templates/register.html
	修改:     run.py

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)

	.gitignore
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git add 各个文件
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git commit -m "用蓝图重构"
[v06 349d7a2] 用蓝图重构
 17 files changed, 436 insertions(+), 65 deletions(-)
 create mode 100644 .gitignore
 rewrite app/__init__.py (63%)
 create mode 100644 app/auth/__init__.py
 rename app/{ => auth}/forms.py (100%)
 rename app/{ => auth}/routes.py (55%)
 create mode 100644 app/main/__init__.py
 create mode 100644 app/main/routes.py
 rename app/templates/{ => auth}/login.html (87%)
 rename app/templates/{ => auth}/register.html (98%)
 rewrite app/templates/base.html (98%)
 create mode 100644 logs/app.log
 create mode 100644 logs/app.log.1
 create mode 100644 logs/app.log.2
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 v06
无文件要提交,干净的工作区
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git checkout master
切换到分支 'master'
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git branch
* master
  v01
  v02
  v03
  v04
  v05
  v06
(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git merge v06
更新 7857ae5..349d7a2
Fast-forward
 .gitignore                             |   8 +++++++
 app.db                                 | Bin 3072 -> 3072 bytes
 app/__init__.py                        |  41 +++++++++++++++++++++++++------
 app/auth/__init__.py                   |   5 ++++
 app/{ => auth}/forms.py                |   0
 app/{ => auth}/routes.py               |  35 ++++++++++++---------------
 app/main/__init__.py                   |   5 ++++
 app/main/routes.py                     |  11 +++++++++
 app/models.py                          |   2 +-
 app/templates/{ => auth}/login.html    |   4 ++--
 app/templates/{ => auth}/register.html |   2 +-
 app/templates/base.html                |  50 +++++++++++++++++++-------------------
 app/templates/index.html               |   4 ++--
 logs/app.log                           | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 logs/app.log.1                         | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 logs/app.log.2                         | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 run.py                                 |   4 +++-
 17 files changed, 430 insertions(+), 59 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 app/auth/__init__.py
 rename app/{ => auth}/forms.py (100%)
 rename app/{ => auth}/routes.py (55%)
 create mode 100644 app/main/__init__.py
 create mode 100644 app/main/routes.py
 rename app/templates/{ => auth}/login.html (87%)
 rename app/templates/{ => auth}/register.html (98%)
 create mode 100644 logs/app.log
 create mode 100644 logs/app.log.1
 create mode 100644 logs/app.log.2
 (myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ git status
位于分支 master
无文件要提交,干净的工作区

项目结构图:

(myproject) chenchen@chenchen-ubuntu:/usr/ccdocs/myproject$ tree
.
├── app
│   ├── auth
│   │   ├── forms.py
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── __init__.py
│   ├── main
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── models.py
│   └── templates
│       ├── auth
│       │   ├── login.html
│       │   └── register.html
│       ├── base.html
│       └── index.html
├── app.db
├── config.py
├── logs
│   ├── app.log
│   ├── app.log.1
│   └── app.log.2
├── Pipfile
├── Pipfile.lock
└── run.py

6 directories, 19 files
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值