flask快速入门笔记七_第三方模块
2 Flask-SQLAlchemy( 主要涉及password验证 )
3.1 登录用户 login_user
3.2 模板中的 current_user
3.3 保护路由 @login_required
3.4 登出用户 logout_user
4 Flask-Script 命令行控制
5 Flask-Migrate 命令行控制db
步骤一 : 创建表单
import os, sys from flask_wtf import Form from wtforms import StringField, PasswordField, BooleanField, SubmitField #这是wtform的支持的html标准字段 from wtforms.validators import DataRequired, Length, Regexp, EqualTo #wtform内建的验证函数 from wtforms import ValidationError #报错时使用 out = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(out) import model User = model.User class LoginForm(Form): username = StringField('Username', validators=[DataRequired(), Length(1, 64)]) password = PasswordField('Password', validators=[DataRequired()]) # remeber_me = BooleanField('Keep me Logged in') submit = SubmitField('Log In') class RegistrationForm(Form): username = StringField('Username', validators=[ DataRequired(), Length(1, 64), Regexp( regex='^[A-Za-z][A-Za-z0-9_]*$', message='username must have only letters, numbers,etc')]) password = PasswordField('Password', validators=[ DataRequired(), EqualTo('password2', message='Password must match')]) password2 = PasswordField('Confirm password', validators=[DataRequired()]) submit = SubmitField('Register') # 以validate_开头的函数且后面跟着字段名(比如username),这个方法会和常规验证函数一起调用 def validate_username(self, field): if User.query.filter_by(username=field.data).first(): raise ValidationError('Username already in use.')
其中 validate_username() 函数是验证表单
以validate_开头的函数且后面跟着字段名(比如username),这个方法会和常规验证函数一起调用
步骤二:把表单渲染成html
方式一,直接写html
<form method="POST" action="/"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(size=20) }} <input type="submit" value="Go"> </form>
其中form.hidden_tag()方法是一个隐藏的 DIV 标签中渲染任何隐藏的字段,包括 CSRF 字段
方式二, 利用flask_bootstrap的wtf.quick_form()方法
{% import "bootstrap/wtf.html" as wtf %}
....
{{ wtf.quick_form(form) }}
步骤三:在视图函数中处理表单
遵循POST/redirect/GET模式
@auth.route('/login', methods=['GET', 'POST']) def v_login(): form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(username=form.username.data).first() if user is not None and user.verify_password(form.password.data): login_user(user) # 相当于记住session return redirect(url_for('main.v_index')) flash('Invalid username or password.') return render_template('auth/login.html', form=form)
2 Flask-SQLAlchemy(主要涉及password验证)
from werkzeug.security import generate_password_hash, check_password_hash # 将密码加密和检查加密后的密码 from app2 import db from datetime import datetime class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(64), unique=True, index=True) password_hash = db.Column(db.String(128)) created = db.Column(db.DateTime, index=True, default=datetime.utcnow) comments = db.relationship('Comment', backref='users') # 该函数是password只有只写属性,如果被读则直接报错 @property def password(self): raise AttributeError('password is not a readable attribute') # 该函数用于当password被创建时,会被自动set成加密后的password @password.setter def password(self, password): self.password_hash = generate_password_hash(password) # 该函数用检测password与password_hash的值是否相同 def verify_password(self, password): return check_password_hash(self.password_hash, password)
为了安全,user的密码会用Werkzeug提供的密码散列
generate_password_hash 是生成散列
check_password_hash 是检查散列
@password.setter(def password()) 方法会将输入的password自动setter成password_hash
最后的 verify_password 方法用于验证password_hash是否相同
步骤一:配置应用
from flask_login import LoginManager login_manager = LoginManager() # 创建对象 login_manager.init_app(app) # 配置
login_manager.session_protection = 'strong' #设置session加密强度 login_manager.login_view = 'auth.v_login' # 设置默认的登录函数
步骤二:user_loader 回调
@login_manager.user_loader def load_user(user_id): return User.query.fiter_by(user_id).first()
步骤三:继承UserMixin
User的model一定要实现 is_authenticated; is_active; is_anonymous; get_id 四个方法
而User的model可以通过继承 UserMixin 来实现
from flask_login import UserMixin class User(db.Model, UserMixin): pass
login_user(user, form.remember_me.data) #记住session
这个方法可以让用户登录
@app.route('/login', methods=['GET', 'POST']) def login(): # Here we use a class of some kind to represent and validate our # client-side form data. For example, WTForms is a library that will # handle this for us, and we use a custom LoginForm to validate. form = LoginForm() if form.validate_on_submit(): # Login and validate the user. # user should be an instance of your `User` class login_user(user, form.remember_me.data) #记住session flask.flash('Logged in successfully.') next = flask.request.args.get('next') # next_is_valid should check if the user has valid # permission to access the `next` url if not next_is_valid(next): return flask.abort(400) return flask.redirect(next or flask.url_for('index')) return flask.render_template('login.html', form=form)
警告: 必须验证 next 参数的值。如果不验证的话,你的应用将会受到重定向的攻击。
每个模板都可以用 current_user 来代理访问登录的用户。
{% if current_user.is_authenticated %}
Hi {{ current_user.name }}!
{% endif %}
通过@login_required 来实现
@app.route("/logout") @login_required def logout(): logout_user() return redirect(somewhere)
命令行控制
# 调用runserver命令行 python manager.py runserver # 调用db的命令行 python manager.py db db_init
manager.py
from flask_script import Manager from myapp.mainapp import app from db_manger import db_manager manager = Manager(app) manager.add_command('db', db_manager) # 将db_manager添加到命令行 @manager.command def runserver(): print 'server run' if __name__ == '__main__': manager.run()
db_manager.py 中间db命令行 和 flask_migrate 思路一样
from flask_script import Manager db_manager = Manager() @db_manager.command def db_init(): print 'db init' @db_manager.command def db_drop(): print 'db drop'
1) 每次ORM更新时候,后期修改字段不会映射到数据库中,必要要 drop 再 create 这样很繁琐。
flask-migrate解决了这一问题
2) 使用 flask-migrate 需要借助 flask-script 然后使用命令行
3) flask_migrate 相关命令
python manager.py db init :初始化一个歉意脚本环境,只需执行一次
python manager.py db migrate : 将模型生成迁移文件,更改model就要执行这个文件
python manager.py db upgrade : 将迁移文件真正映射到数据库中,每次运行 migrate 后都要执行这行命令。
4) 注意 :和 create_all 同理,如果要将模型映射到数据库,必要将mode 导入到目标文件也就是 manager.py 中。
# coding=utf-8 from flask_script import Manager from flask_migrate import Migrate, MigrateCommand from myapp.mainapp import app from myapp.db_middle import db from db_manger import db_manager manager = Manager(app) # 1 先将app和db绑定 migrate = Migrate(app, db) # 把 MigrateCommand 命令添加到 manager 中 # db_manager 和 MigrateCommand 道理一样 manager.add_command('db', MigrateCommand)
步骤一: 配置应用
from flaskext.markdown import Markdown Markdown(app)
步骤二 编辑html:
<body> {% filter markdown %} #My Markdown *** * ##Some intersting things I just want to test hahaaaaaaa {% endfilter %} </body>