本文是记录本人创建一个flask项目的完整过程。css
涉及FLASK的诸多实用技术。html
pycharm创建FLASK项目便可运行。前端
代码以下:python
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'hello' if __name__ == '__main__': app.run()
直接运行便可。pycharm的默认访问地址是http://127.0.0.1:5000/mysql
修改默认的app.py为main.py,即主入口文件redis
前端想少写东西,就要有前端框架,bootstrap是一个流行的框架,原有的flask-bootstrap中止更新了,改用一个继承者Bootstrap-Flasksql
pip install Bootstrap-Flask
在templates目录下建立目录base,在base目录下建立base.html数据库
<!doctype html> <html lang="en"> <head> {% block head %} <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> {% block styles %} <!-- Bootstrap CSS --> {{ bootstrap.load_css() }} {% endblock %} <title>Your page title</title> {% endblock %} </head> <body> <!-- Your page content --> {% block content %}{% endblock %} {% block scripts %} <!-- Optional JavaScript --> {{ bootstrap.load_js() }} {% endblock %} </body> </html>
这个代码是bootstrap-flask推荐的。npm
from flask_bootstrap import Bootstrap from flask import Flask, render_template #添加渲染模板的库 app = Flask(__name__) bootstrap = Bootstrap(app) @app.route('/') def hello_world(): return render_template('base/base.html') #修改返回为渲染模板 if __name__ == '__main__': app.run()
运行访问,虽然是个空页面,可是查看源码,会看到多了加载CSS和JSflask
from flask_bootstrap import Bootstrap from flask import Flask, render_template app = Flask(__name__) bootstrap = Bootstrap(app) app.config['BOOTSTRAP_SERVE_LOCAL'] = True #配置flask-bootstrap加载本地数据 @app.route('/') def hello_world(): return render_template('base/base.html') if __name__ == '__main__': app.run()
由原来的cdn加速地址改成本地了。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="/bootstrap/static/css/bootstrap.min.css" type="text/css">
1.为了项目复制以及部署,须要对第三方库进行管理。
在项目根目录建立文件make_requirement.py
import os, sys, platform # 找到当前目录 project_root = os.path.dirname(os.path.realpath(__file__)) print(project_root) #不一样的系统,使用不一样的命令语句 if platform.system() == 'Linux': command = sys.executable + ' -m pip freeze > ' + project_root + '/requirements.txt' if platform.system() == 'Windows': command = '"' + sys.exec_prefix + '\Scripts\pip" freeze > ' + project_root + '\\requirements.txt' # # 拼接生成requirements命令 print(command) # # # 执行命令。 os.system(command)
运行后便可在项目根目录生成requirements.txt
以下:
D:. │ main.py │ make_requirement.py │ requirements.txt │ ├─app │ └─users │ view.py #新建视图文件 │ ├─static ├─templates │ └─base │ base.html │ └─__pycache__ main.cpython-37.pyc
编辑/app/users/view.py
from flask import Blueprint user = Blueprint('user', __name__) @user.route('/') def show(): return 'user.default' @user.route('/register') def register(): return 'user.register' @user.route('/login') def login(): return 'user.login' @user.route('/logout') def logout(): return 'user.logout'
编辑main.py
from flask_bootstrap import Bootstrap from flask import Flask, render_template from app.users.view import user #引入视图 app = Flask(__name__) bootstrap = Bootstrap(app) app.config['BOOTSTRAP_SERVE_LOCAL'] = True app.register_blueprint(user, url_prefix='/user') #注册视图 if __name__ == '__main__': app.run()
http://127.0.0.1:5000/user/
http://127.0.0.1:5000/user/register
http://127.0.0.1:5000/user/login
http://127.0.0.1:5000/user/logout
均可以访问
pip install sqlalchemy alembic MySQL-connector-python
建立config.py
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base engine = create_engine('mysql+mysqlconnector://zzcld:zzcld@mariadb/zzcld', convert_unicode=True) db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = db_session.query_property()
把main.py中定义的配置,放进config.py
修改config.py
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base class Config(object): #配置这项 DEBUG = False TESTING = False DATABASE_URI = 'mysql+mysqlconnector://zzcld:zzcld@mariadb/zzcld' BOOTSTRAP_SERVE_LOCAL = True engine = create_engine(Config.DATABASE_URI, convert_unicode=True) #修改数据库路径 db_session = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) Base = declarative_base() Base.query = db_session.query_property()
http://www.javashuo.com/article/p-kprqthiu-da.html
建立/app/users/model.py
from config import Base from sqlalchemy import Column, Integer, String, Boolean class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) username = Column(String(50)) #用户名 password = Column(String(120)) #密码 activity = Column(Boolean) #是否活动/禁用
须要修改配置的有两个文件。
alembic.ini,其中配置数据库链接参数。
修改这行:
sqlalchemy.url = driver://user:pass@localhost/dbname
改成咱们的数据链接参数:
sqlalchemy.url = mysql+mysqlconnector://zzcld:zzcld@mariadb/zzcld
env.py,其中配置models。
修改这行:
target_metadata = None
修改成:
import os import sys sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/../") from app.users import model target_metadata = model.Base.metadata
alembic revision --autogenerate 生成alembic升级脚本
alembic upgrade head 升级数据库结构到最新版
执行这两个命令,或用扩展工具的图形菜单。
使用第三方工具,链接你的数据库查看数据库创建状况。
这个是一个表单库,基于wtform。处理各类表单,先处理注册和登陆。
pip install flask-wtf
修改user/register,既/app/users/view.py
class register_form(FlaskForm): #注册表单 username = StringField('用户名', validators=[DataRequired()]) password = StringField('密码', validators=[DataRequired()]) class login_form(FlaskForm): #登陆表单 username = StringField('用户名', validators=[DataRequired()]) password = StringField('密码', validators=[DataRequired()])
建立/templates/users/register.html
建立/templates/users/login.html
内容同样
{% extends 'base/base.html' %} {% block content %} <form method="POST" action="#"> {{ form.csrf_token }} {{ form.username.label }} {{ form.username(size=20) }} <br> {{ form.password.label }} {{ form.password(size=20) }} <br> <input type="submit" value="提交"> </form> {% endblock %}
修改/app/users/view.py
@user.route('/register', methods=('GET', 'POST')) def register(): form = register_form() # 初始化表单 return render_template('users/register.html', form=form) @user.route('/login', methods=('GET', 'POST')) def login(): form = login_form() # 初始化表单 return render_template('users/login.html', form=form)
http://127.0.0.1:5000/user/register
http://127.0.0.1:5000/user/login
已经有了一个表单,有用户名和密码两个框,一个提交按钮。
修改/app/users/view.py
@user.route('/register', methods=('GET', 'POST')) def register(): form = register_form() # 初始化表单 if form.validate_on_submit(): # 若是页面有提交数据,在此建立数据库条目 new_user = Users(username=form.username.data, password=form.password.data, activity=True) db_session.add(new_user) db_session.commit() db_session.close() return redirect(url_for('user.login')) # 跳转到登陆页面 return render_template('users/register.html', form=form) @user.route('/login', methods=('GET', 'POST')) def login(): form = login_form() # 初始化表单 if form.validate_on_submit(): # 若是页面有提交数据,在此建立数据库条目 login_user = db_session.query(Users).filter_by(username=form.username.data).first() # 查找name=jack的 print(login_user.username) print(form.password.data) if login_user.password==form.password.data: return redirect(url_for('user.show')) # else: return '登陆失败' return render_template('users/login.html', form=form)
我测试正常
为防止cookie伪造,我使用session来保存用户信息。
pip install flask-session
修改main.py
from flask_bootstrap import Bootstrap from flask import Flask, render_template from app.users.view import user # 引入视图 from config import Config from flask_session import Session app = Flask(__name__) app.config.from_object(Config) #不知道为何,注入Session以前要先加载配置 Session(app) #新加 bootstrap = Bootstrap(app) app.register_blueprint(user, url_prefix='/user') @app.route('/') def default(): return render_template('base/base.html') if __name__ == '__main__': app.run()
修改config.py
class Config(object): # 配置这项 DEBUG = False TESTING = False DATABASE_URI = 'mysql+mysqlconnector://zzcld:zzcld@mariadb/zzcld' BOOTSTRAP_SERVE_LOCAL = True SECRET_KEY = os.urandom(24) # 加密的密码,部署时修改,测试时使用随机字符串 SESSION_TYPE = 'filesystem' # session存储类型,暂时使用文件存储,部署时会改用redis SESSION_PERMANENT = False # 是否永久生效,false就是关闭浏览器失效 SESSION_USE_SIGNER = True #是否签名会话cookie sid 避免伪造,签名 SESSION_FILE_THRESHOLD = 2 #保存session条数,既最大同时登陆人数,默认500,部署时修改
登陆时,设置session,登出时,清空session,用户默认页,读取session。
修改/app/users/view.py
@user.route('/') def show(): return (session.get('key', 'not set')+'设置'+session.get('user', 'not set')) @user.route('/login', methods=('GET', 'POST')) def login(): form = login_form() # 初始化表单 if form.validate_on_submit(): # 若是页面有提交数据,在此建立数据库条目 login_user = db_session.query(Users).filter_by(username=form.username.data).first() # 查找name=jack的 print(login_user.username) print(form.password.data) if login_user.password==form.password.data: session['key'] = 'value' session['user'] = 'user' return redirect(url_for('user.show')) # else: return '登陆失败' return render_template('users/login.html', form=form) @user.route('/logout') def logout(): session.clear() return 'user.logout'
http://127.0.0.1:5000/user/ 登陆前和登陆后,显示的不同。
http://127.0.0.1:5000/user/login
http://127.0.0.1:5000/user/logout
我是常常网机释放数据库链接,这不是一个好习惯,好在flask有内置的装饰器能够在在请求结束时或在应用程序关闭时自动删除数据库会话:
from flask_bootstrap import Bootstrap from flask import Flask, render_template from app.users.view import user from config import Config from config import db_session #引入session from flask_session import Session app = Flask(__name__) app.config.from_object(Config) Session(app) bootstrap = Bootstrap(app) app.register_blueprint(user, url_prefix='/user') @app.teardown_appcontext #新加 def shutdown_session(exception=None): db_session.remove() @app.route('/') def default(): return render_template('base/base.html') if __name__ == '__main__': app.run()