#app\__init__.py
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from config import config
# 由于尚未初始化所需的程序实例,所以没有初始化扩展,创建扩展类时没有向构造函数传入参数。
bootstrap = Bootstrap()
mail = Mail()
db = SQLAlchemy()
def create_app(config_name):
'''工厂函数'''
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)# 通过config.py统一接口
bootstrap.init_app(app)
mail.init_app(app)
db.init_app(app)
# 同上
# 附加路由和自定义错误页面,将蓝本注册到工厂函数
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
#app\main\views.py
from flask import render_template, session, redirect, url_for
from . import main
from .forms import NameForm
from .. import db
from ..models import User
@main.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first() # 查询数据库是否有该用户
if user is None: # 如果没有该用户,就保存到数据库中
user = User(username=form.name.data)
db.session.add(user)
db.session.commit()
session['known'] = False # 通过session保存 known为False,通过web渲染需要
else:
session['known'] = True
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('.index')) # 通过redirect避免用户刷新重复提交
return render_template('index.html', form=form, name=session.get('name'),
known=session.get('known', False))
#app\main\forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class NameForm(FlaskForm):
'''通过 flask-wtf 定义表单类'''
name = StringField('What is your name ?', validators=[DataRequired()]) # 文本框
submit = SubmitField('Submit') # 按钮
#app\main\errors.py
from flask import render_template
from . import main
@main.app_errorhandler(404) # 路由装饰器由蓝本提供,这里要调用 app_errorhandler 而不是 errorhandler
def page_not_found(e):
return render_template('404.html'), 404
#app\main\__init__.py
from flask import Blueprint
# 定义蓝本
main = Blueprint('main', __name__)
from . import views, errors
#app\email.py
from threading import Thread
from flask import render_template, current_app
from flask_mail import Message
from . import mail
def send_async_mail(app, msg):
'''创建邮件发送函数'''
with app.app_context():
mail.send(msg)
def send_mail(to, subject, template, **kwargs):
app = current_app._get_current_object()
if app.config['FLASKY_ADMIN']:
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject,
sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
msg.body = render_template(template + '.txt', **kwargs)
msg.html = render_template(template + '.html', **kwargs)
thr = Thread(target=send_async_mail, args=(app, msg))
thr.start() # 通过创建子线程实现异步发送邮件
return thr
#app\models.py
from . import db
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, index=True)
users = db.relationship('User', backref='role', lazy='dynamic')
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return '<User %r>' % self.username
#tests\test_basics.py
from app import create_app, db
class BasicsTestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_app_exists(self):
self.assertFalse(current_app is None)
def test_app_is_testing(self):
self.assertTrue(current_app.config['TESTING'])
#flasky.py
import os
from app import create_app, db
from app.models import User, Role
from flask_migrate import Migrate
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Role=Role)
@app.cli.command()
def test():
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
if __name__ == '__main__':
app.run()