此章和教程出入不大,可直接看原教程
- 之前寫的代碼耦合太重,python也可以像js模塊化一樣模塊化程序結(jié)構
模塊化
- 使用 藍圖(藍本),我們之前的程序都有一個Flask的實例
app = Flask(__name__)
- 這個app變量可以定義路由,藍圖就是可以將路由分門別類,然后在組合在一起
- 需要重新設置一下目錄結(jié)構:
.
├── app
│ ├── admin
│ │ ├── errors.py
│ │ ├── forms.py
│ │ ├── __init__.py
│ │ └── views.py
│ ├── __init__.py
│ ├── main
│ │ ├── forms.py
│ │ ├── __init__.py
│ │ └── views.py
│ ├── models.py
│ ├── static
│ └── templates
│ ├── 404.html
│ ├── 500.html
│ ├── admin
│ │ ├── login.html
│ │ └── register.html
│ ├── base.html
│ ├── index.html
│ └── user.html
├── config.py
├── manage.py
- Flask 程序一般都保存在名為app的包中.
- config.py 保存著配置
- manage.py 用于啟動項目
說明一下python 的包(package),從目錄結(jié)構上看,python的package有兩部分組成: 文件夾和init.py 文件. 正是因為init.py 的存在 python編譯器才會把那個文件夾當作是一個python的包來看待. 而那個 init.py 的效果就是, 能夠有一個與包名字相同的文件. 什么意思呢?
比如 我們有一個名字為 main 的包, 那么
from main import *
這行代碼中,從main包中import所有的東西,你想啊,main是個包,import進來是啥??? 其實阿,import進來的是init.py中的內(nèi)容.
- 把原先那個blog.py中的東西復制一下就好了:
- config.py:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = 'a string'
# 數(shù)據(jù)庫配置
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
SQLALCHEMY_COMMIT_TEARDOWN = True
SQLALCHEMY_TRACK_MODIFICATIONS = False
@staticmethod
def init_app(app):
pass
仿照狗書,創(chuàng)建一個程序工廠函數(shù). 設計模式中有一個模式叫做:工廠模式,比如你需要一個東西,但這個東西你需要配置很多,這樣你就可以用到工廠模式,在把配置(比如汽車廠,把各個零件組裝起來)的活交給工廠,那么工廠出來的產(chǎn)品就是好的產(chǎn)品.這樣可以降低程序的耦合度,怎么理解呢,如果這個產(chǎn)品是壞的,那么你也不需要到處去程序的代碼,只需要去那個工廠的程序中去尋找bug就好了
程序工廠函數(shù):
說一下工廠函數(shù),我們之前單個文件開發(fā)程序很方便,但卻有個很大的缺點,因為程序在全局作用中創(chuàng)建,所以無法動態(tài)修改配置.運行腳本時,實例已經(jīng)創(chuàng)建,再修改配置為時已晚,解決問題的方法就是延遲創(chuàng)建程序?qū)嵗?把創(chuàng)建過程移到可顯式調(diào)用的工廠函數(shù)中.
- app/init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
Config.init_app(app)
db.init_app(app)
return app
這段代碼,我們的db實例,先于app創(chuàng)建,app的創(chuàng)建只能調(diào)用了create_app()函數(shù)之后才創(chuàng)建.
藍圖:
Flask 中的藍圖為這些情況設計:
- 把一個應用分解為一個藍圖的集合。這對大型應用是理想的。一個項目可以實例化一個應用對象,初始化幾個擴展,并注冊一集合的藍圖。
- 以 URL 前綴和/或子域名,在應用上注冊一個藍圖。 URL 前綴/子域名中的參數(shù)即成為這個藍圖下的所有視圖函數(shù)的共同的視圖參數(shù)(默認情況下)。
- 在一個應用中用不同的 URL 規(guī)則多次注冊一個藍圖。
- 通過藍圖提供模板過濾器、靜態(tài)文件、模板和其它功能。一個藍圖不一定要實現(xiàn)應用或者視圖函數(shù)。
- 初始化一個 Flask 擴展時,在這些情況中注冊一個藍圖。
藍圖問題,最后總結(jié):
- 在藍本中定義的路由處于休眠狀態(tài),直到藍本注冊到程序上后,路由才真正成為程序的一部分
創(chuàng)建藍本:
- app/main/init
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
藍圖是通過實例化Blueprint類對象來創(chuàng)建的。這個類的構造函數(shù)接收兩個參數(shù):藍圖名和藍圖所在的模塊或包的位置。與應用程序一樣,在大多數(shù)情況下,對于第二個參數(shù)值使用Python的name變量即可。
應用程序的路由都保存在app/main/views.py模塊內(nèi)部,而錯誤處理程序則保存在app/main/errors.py中。導入這些模塊可以使路由、錯誤處理與藍圖相關聯(lián)。重要的是要注意,在app/init.py腳本的底部導入模塊要避免循環(huán)依賴,因為view.py和errors.py都需要導入main藍圖
注冊藍圖:
- app/init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
Config.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
#通過register_blueprint方法將藍圖注冊進來
return app
- app/main/errors.py:
from flask import render_template
from . import main
@main.app_errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@main.app_errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500
- app/main/views.py:
from flask import render_template
from flask import session
from flask import redirect
from flask import url_for
from flask import request
from . import main
from ..models import User
from .. import db
@main.route('/', methods=['GET', 'POST'])
def index():
if 'name' in request.args:
name = request.args['name']
return render_template('user.html', username=name)
else:
return render_template('index.html')
@main.route('/register', methods=['POST'])
def register():
username = request.form['username']
password = request.form['password']
if username:
user = User.query.filter_by(name=username)
if user is None:
##添加進數(shù)據(jù)庫
user = User(name=username)
##如果沒有app.config['SQLALCHEMY_COMMIT_TEARDOWN'] = True
##這句后面還要加上db.session.commit()才會提交到數(shù)據(jù)庫
db.session.add(user)
session['known'] = False
else:
session['known'] = True
session['name'] = username
name=session.get('name')
return '你的用戶名是 %s' % name
- manage.py:
from flask_script import Manager
from app import create_app, db
app = create_app()
manager = Manager(app)
if __name__ == '__main__':
manager.run()
- app/models.py:
from . import db
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# 如果你學過數(shù)據(jù)庫的話就知道我們一般通過id來作為主鍵,來找到對應的信息的,通過id來實現(xiàn)唯一性
name = db.Column(db.String(64), unique=True)
def __repr__(self):
return 'users表: id為:{}, name為:{}'.format(self.id, self.name)
- 在終端輸入:
python manage.py shell
>>> from manage import *
>>> db
<SQLAlchemy engine=sqlite:////home/me/PycharmProjects/blog/data.sqlite>
>>> db.drop_all()
>>> db.create_all()
>>> exit()
- 這里把表重新創(chuàng)建了一下,因為表已經(jīng)移動位置了.
然后:
python manage.py runserver
然后就可以正常運行了