本文是記錄本人創建一個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()