在学习过 Django 后,我们了解到 Django 中的 app 主要作用就是将 Django 项目划分成一个个单独的 app 模块,然后将所有 app 分配不同的处理功能,通过路由分配将它们连接成一个大的Django 项目,而在 Flask 中的蓝图与 Django 中的 app 有异曲同工之妙。
下面我们大致来了解一下 Flask 的蓝图,首先创建一个主的路由配置文件 app.py,该文件主要的作用就是启动整个的 Flask 框架;
from flask import Flask
# 创建Flask的主app
app = Flask(__name__)
app.debug = True
# app.py中的部分路由
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
print(app.url_map)
# 启动主app
app.run()
接着我们在 app.py 的同级目录下创建 user/views.py 和 cart/views.py ,内容大致如下;
# user/views.py
from flask import Blueprint
# 这里注意路径的不同
# 静态文件查找
# bp = Blueprint("user",__name__,url_prefix="/user/",static_folder='static')
# 模板文件查找
bp = Blueprint("user",__name__,url_prefix="/user/",static_folder='staticfiles',template_folder='templates')
@bp.route("/")
def index():
return render_template('user.html')
# cart/views.py
from flask import Blueprint
# 创建一个蓝图,Blueprint必须指定两个参数,cart表示蓝图的名称,__name__表示蓝图所在模块
bp = Blueprint("cart",__name__,url_prefix="/cart/")
# 用该蓝图来设置路由方法
@bp.route("/")
def index():
return "cart blueprint"
Flask 是通过蓝图注册方式将蓝图添加到主 app 中,而这两个 py 文件主要是创建蓝图,接着为创建的蓝图添加路由配置;
from flask import Flask
from user import views as UserViews
from cart import views as CartViews
# 创建Flask的主app
app = Flask(__name__)
app.debug = True
# 注册分路由 将蓝图注册到app
app.register_blueprint(UserViews.bp)
app.register_blueprint(CartViews.bp)
# app.py中的部分路由
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
print(app.url_map)
# 启动主app
app.run()
由于 user/views.py 处返回的是一个 user.html 页面,下面我们对其进行编写;
Title
user page
登录
这样配置好就可以实现路由分层管理,运行主程序进行访问,效果如下;
完成一个简单的登录验证的小案例来了解类视图,若已登录成功会跳转至商品搜索页面,否则回到登录页面。首先在主目录下创建 goods/views.py,编写一个类视图的简单使用;
from flask.views import MethodView
from flask import render_template,request
from user.views import login_required
class GoodsView(MethodView):
def get(self):
return render_template('goods.html')
def post(self):
q = request.form.get('q')
return q
接着把渲染模板 goods.html 的代码编写上;
Title
商品详情
在主 app 上注册路由;
from goods.views import GoodsView
app.add_url_rule('/goods/',view_func=GoodsView.as_view('goods'))
并在 user/views.py 中简单的编写登录注销的视图函数及定义装饰器;
import functools
from flask import Blueprint,render_template,session,url_for,redirect
# bp = Blueprint("user",__name__,url_prefix="/user/",static_folder='static')
bp = Blueprint("user",__name__,url_prefix="/user/",static_folder='staticfiles',template_folder='templates')
def login_required(func):
# 添加后路径名字不会变化,反转时不用修改
@functools.wraps(func)
def wrapper(*args,**kwargs):
if not session.get("is_login"):
return redirect(url_for('user.login'))
return func(*args,**kwargs)
return wrapper
@bp.route("/")
@login_required
def index():
# return "user blueprint"
return render_template('user.html')
@bp.route("/login/")
def login():
session['is_login'] = True
return render_template('login.html')
@bp.route("/logout/")
def logout():
session.clear()
return "session clear"
在 GoodsView() 视图函数中使用登录验证装饰器;
from flask.views import MethodView
from flask import render_template,request
from user.views import login_required
class GoodsView(MethodView):
@login_required
def get(self):
return render_template('goods.html')
def post(self):
q = request.form.get('q')
return q
其他视图使用直接在视图函数中添加@login_required即可;
@bp.route("/")
@login_required
def index():
# return "user blueprint"
return render_template('user.html')
效果如下(在还没登录前访问会跳转到登录页面):
上面是自己编写的登录验证,接下来使用 Flask 框架提供的 Flask_login 来登录验证。
安装
在使用前先进行安装:pip install Flask-Login==0.3.2;
配置
在安装完之后,在 app.py 主 app 中进行配置;
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
# 设置登录跳转及消息
login_manager.login_view = 'user.login'
login_manager.login_message = u""
重构用户模型
登录基于用户,需要定义 User 类,Flask-Login 规定 User 类必须实现三个属性和一个方法:
(1)is_authenticated 属性,一般而言,这个属性应该只返回 True,除非表示用户的对象因为某些原因不允许被认证;
(2)is_active 属性应该返回 True,除非是用户是无效的,比如因为他们的账号是被禁止;
(3)is_anonymous 属性应该返回 True,除非是伪造的用户不允许登录系统;
(4)get_id 方法应该返回一个用户唯一的标识符,以 unicode 格式。我们使用数据库生成的唯一的 id。需要注意地是在 Python 2 和 3 之间由于 unicode 处理的方式的不同我们提供了相应的方式。
这里最简单的方法就是从 UserMixin 类继承,该类提供了默认的实现。在 user/models.py 文件中编写代码如下;
from db.ext import db
from flask_login import UserMixin
# 用户模型
class UserModel(UserMixin,db.Model):
# 定义表名
__tablename__ = "user"
# 类型ID、类型名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(64), unique=True)
# 关联
password = db.Column(db.String(64), unique=True)
def __str__(self):
return self.username
class BookModel(db.Model):
__tablename__ = "book"
# 类型ID、类型名
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
bookname = db.Column(db.String(64), unique=True)
def __str__(self):
return self.bookname
再在 user/views.py 中引入上述编写的用户模型,并进行注册;
import json
from flask import render_template, session, redirect, url_for, request, flash
from flask.views import MethodView
from flask_login import login_user, logout_user
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField,PasswordField
from wtforms.validators import DataRequired
from .models import UserModel
# 登录功能实现
class LoginForm(FlaskForm):
username = StringField(u'用户名',validators=[DataRequired()])
password = PasswordField(u'密码',validators=[DataRequired()])
submit = SubmitField(u'提交')
# 统一用类视图
class LoginView(MethodView):
def get(self):
login_form = LoginForm()
return render_template('login.html',form=login_form)
def post(self):
login_form = LoginForm()
if login_form.validate_on_submit():
username = request.form.get('username')
password = request.form.get('password')
user = UserModel.query.filter_by(username=username,password=password).first()
# if username == "admin" and password == "112233":
if user:
# 登录成功
# session['is_login'] = True
# session['username'] = username
login_user(user,force=True)
next = request.args.get('next',None)
if not next:
return redirect(url_for('index'))
else:
return redirect(next)
return redirect(url_for('index'))
else:
flash("登录失败")
return render_template('login.html',form=login_form)
# 登出功能实现
class LogoutView(MethodView):
def get(self):
# session.clear()
logout_user()
return redirect(url_for('user.login'))
# 注册路由
app.add_url_rule('/user/login/',view_func=LoginView.as_view('user.login'))
app.add_url_rule('/user/logout/',view_func=LogoutView.as_view('user.logout'))
在 index/views.py 中设置登录限制;
from flask import render_template
from flask.views import MethodView
from flask_login import login_required, current_user
class IndexView(MethodView):
@login_required
def get(self):
return render_template("index.html",username=current_user.username)
接着,在模板 index.html 中访问当前变量;
Title
欢迎您,{% if current_user.is_authenticated %}
{{ username }}
{% endif %}
退出
user_loader 回调
这里我们必须编写一个函数用于从数据库加载用户,在 app.py 中使用;
# 设置 load_user 回调
@login_manager.user_loader
def load_user(userid):
return UserModel.query.get(userid)
效果如下:
当用户的用户名、密码核实正确后会跳转到欢迎登录界面,若失败则会提示登录失败。
flask-migrate 是基于 Alembic 进行的一个封装,并集成到 Flask 中, 而所有的迁移操作其实都是 Alembic 做的,他能跟踪模型的变化,并将变化映射到数据库中。
先进行安装:pip install flask-migrate,还需要再 app.py 中绑定 app 和数据库;
from flask_migrate import Migrate
# Migrate管理app里的数据库
migrate = Migrate(app,db)
生成数据库的操作:
# 初始化一个迁移文件夹
flask db init
# 把当前的模型添加到迁移文件中
flask db migrate
# 把迁移文件中对应的数据库操作,真正的映射到数据库中
flask db upgrade