zoukankan      html  css  js  c++  java
  • flask快速入门笔记七_第三方模块

      1 Flask-WTF

      2 Flask-SQLAlchemy( 主要涉及password验证 )

      3 Flask-Login

        3.1 登录用户 login_user

        3.2 模板中的 current_user

        3.3 保护路由 @login_required

        3.4 登出用户 logout_user

      4 Flask-Script 命令行控制

      5 Flask-Migrate 命令行控制db

      6 Flask-Markdown

    1 Flask-WTF 

    步骤一 : 创建表单

    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是否相同

    3 Flask-Login 

    步骤一:配置应用

    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

    3.1 登录用户 login_user  

    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 参数的值。如果不验证的话,你的应用将会受到重定向的攻击。

    3.2 模板中的 current_user  

    每个模板都可以用 current_user 来代理访问登录的用户。

    {% if current_user.is_authenticated %}
      Hi {{ current_user.name }}!
    {% endif %}

    3.3 保护路由 @login_required  

    通过@login_required 来实现

    3.4 登出用户 logout_user 

    @app.route("/logout")
    @login_required
    def logout():
        logout_user()
        return redirect(somewhere)

    4 Flask-Script 命令行控制  

     命令行控制

    # 调用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'

    5 Flask-Migrate 命令行控制db 

    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)

    6 Flask-Markdown  

    步骤一: 配置应用

    from flaskext.markdown import Markdown
    Markdown(app)

    步骤二 编辑html:

    <body>
    {% filter markdown %}
    #My Markdown
    ***
    * ##Some intersting things
    I just want to test hahaaaaaaa
    {% endfilter %}
    </body>
  • 相关阅读:
    分享PHP获取客户端IP的几种不同方式
    php魔术方法get和set举例
    PHP正确匹配图片路径
    PHP通用的防注入过滤用户字符串函数
    用PHP逐行读取TXT文件
    atitit.ajax 最佳实践跟框架选型 o99
    Atitit.研发管理提升效率软件开发方法DSM总结o99
    Atitit. js mvc 总结(2)angular 跟 Knockout o99 最佳实践
    atitit.hbnt orm db 新新增更新最佳实践o99
    Atitit.提升稳定性分析内存泄漏PermGen OOM跟解决之道...java
  • 原文地址:https://www.cnblogs.com/fuzzier/p/6297665.html
Copyright © 2011-2022 走看看