《Flask web开发》笔记5:大型程序的结构&用户认证Flask-Login

一.学习的内容:

  1.工厂函数的定义;

  2.蓝本的注册和蓝本文件结构;

  3.Werkzeug实现密码散列如何实现;

  4.Flask_login的用法;

       以上内容通过代码的形式展示;

 

二、工程的文件结构:

|-falsky/

  |-app/

    |-__init__.py  //初始化、工厂函数、注册蓝本等

    |-models.py  //定义数据库

    |-templates/  

      |-base.html  //基本的模板

      |-auth/   //蓝本的模板,这样不会跟其他蓝本弄混

        |-login.html   

        |-welcome.html

    |-auth/

      |-__init__.py   

      |-views.py  //蓝本的路由和视图函数的定义

      |-forms.py  //针对这个蓝本的表单

  |-config.py  //设置,可以给指定人不同的设置,例如数据库的不同

  |-manage.py  //运行

 

 

三、程序代码:

 

  1.app/__init__.py

  解释:这个py文件最为重要,database、flask_bootstrap、flask_login的实例化都在里面;另外,还有工厂函数(重点)

# coding: utf-8
from flask import Flask, render_template
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import config

bootstrap = Bootstrap()
mail = Mail()
db = SQLAlchemy()

login_manager = LoginManager()  
login_manager.session_protection = None
login_manager.login_view = 'auth.login'  #端点

def create_app(config_name):  #工厂函数

    app=Flask(__name__)

    app.config.from_object(config[config_name]) #调用config.py里定义配置名的配置
    config[config_name].init_app(app)


    bootstrap.init_app(app)
    mail.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)

    #注册蓝本,路由写在里面,注册才能使用
 
    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/auth') #url_prefix里的值代表路由的路径为/auth/**;

    return app
    

 

  2.app/auth/__init__.py

  解释:既然前面的工厂函数里注册了,那么这里就要创建蓝本对象了

from flask import Blueprint

auth = Blueprint('auth',__name__) #一般创建的蓝本对象和蓝本文件件重名

from . import views   #这里引入路由

 

  3.app/auth/views.py

  解释:这里定义路由;

# coding: utf-8
#import os
#import sys
#sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/' + '..'))

from flask import render_template
from flask import  redirect, request, url_for, flash
from flask_login import login_user
from . import auth
from ..models import User
from .forms import LoginForm
from flask_login import logout_user, login_required

@auth.route('/login/',methods=['GET', 'POST'])
def login():
    form = LoginForm()
    print 'views test'
    if form.validate_on_submit():
        user = User.query.filter_by(email = form.email.data).first()
        if user is not None and user.verify_password(form.password.data):
            
            login_user(user,form.remember_me.data)
            return redirect(request.args.get('next') or url_for('auth.welcome'))

            pass
        flash('Invalid username or password')
        pass
    return render_template('auth/login.html',form=form)
    pass


@auth.route('/logout')
@login_required
def logout():
    logout_user()
    flash('you have been logged out')
    pass

@auth.route('/test')
def test():
    form = LoginForm()  
    return render_template('welcome.html')
    pass

 

  4.app/auth/forms.py

  解释:在views视图函数要用到渲染模板的表单数据在这里定义;

# coding: utf-8
from flask_wtf import Form
from wtforms import StringField, PasswordField, BooleanField, SubmitField
#                    输入字段       密码字段        复选字段      提交
from wtforms.validators import Required, Length, Email

class LoginForm(Form):
    email = StringField('Email', validators=[Required(), Length(1, 64),Email()])
    password = PasswordField('Password', validators=[Required()])
    remember_me = BooleanField('Keep me logged in')
    submit = SubmitField('Log In')

  5.app/models.py

  解释:这里定义页面的数据库类:

# coding: utf-8
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from . import login_manager,db
from flask_sqlalchemy import SQLAlchemy

class User(UserMixin, db.Model):
    __tablename__ = 'users_three'
    id = db.Column(db.Integer, primary_key = True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))  #利用了Werkzeug实现密码哈希形式存入数据库;

    @property
    def password(self):
        raise AttributeError('password is not atterbute')
        pass

    @password.setter
    def password(self,password):
        self.password_hash=generate_password_hash(password)
        pass
    def verify_password(self,password):
        return check_password_hash(self.password_hash,password)
        pass

@login_manager.user_loader

def load_user(user_id):
    return User.query.get(int(user_id))#加载用户的回调函数接收以 Unicode 字符串形式表示的用户标识符。如果能找到用户,这个函数必须返回用户对象;否则应该返回 None

    pass

 

  6.config.py

  解释:这里你可以针对不同用户设置不同数据库路径、secret_key等、、、

import os
basedir = os.path.abspath(os.path.dirname(__file__))
class config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
    SQLALCHEMY_DATABASE_URI = 'mysql://root@localhost/yxctest'
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SQLALCHEMY_TRACK_MODIFICATIONS = True
    @staticmethod
    def init_app(app):
        pass

config = {
#'development': DevelopmentConfig,
#'testing': TestingConfig,
#'production': ProductionConfig,
'default': config
}

 

  7.manage.py

  解释:这里app.run运行

# coding: utf-8
import os 
from app import create_app,db
from app.models import User



app = create_app(os.getenv('FLASK_CONFIG') or 'default')



if __name__ == '__main__':
    app.run(debug=True)

 

到这里,一个完整的文件框架已经完成,下面添加一些模板

 

base.html

{% extends "bootstrap/base.html" %}
{% block content %}
<div class="container">
<div class="page-header">
<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated%}
<li><a href="{{ url_for('auth.logout') }}">Sign Out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}">Sign In</a></li>
{% endif %}
</ul>
</div>
</div>
{%endblock %}

 

login.html

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %}

{% block content %}
<div class="container">
<div class="page-header">
<h1>Login</h1>
</div>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}

 

wlecome.html

{% extends "bootstrap/base.html" %}

{% block title %}TTTTT{% endblock %}

{% block content %}

<div class="container">
<div class="page-header">
<h1>Hello!</h1>


</div>
</div>

{% endblock %}

 

效果图:

 

 

 

 

 

 

      

 

posted @ 2017-09-13 17:59  井冈大兵  阅读(333)  评论(0编辑  收藏  举报