Flask 第一课项目MVC拆分
tags:
- Flask
- 2019千锋教育
categories:
- flask
- MVC
- 项目拆分
文章目录
- Flask 第一课项目MVC拆分
- 第一节 flask的Hello world
- 1. flask基本知识
- 第二节 Flask的命令行工具
- 1. 命令行工具flask-script
- 2. flask-script使用
- 第三节 第一阶段_拆路由
- 1. 着手拆分
- 2. 尝试解决
- 3. 解决方案一:懒加载
- 4. 解决方案二:蓝图flask-blueprint
- 第四节 第二阶段_拆数据模型
- 1.数据模型构建
- 2. 官方方案之懒加载
- 第五节 第三阶段_分离配置和第三方库(包括上面的models)
- 1. 分离第三方库出__init__.py
- 正常练手项目使用此拆分已经可以足够完成
- 2. 分离配置出__init__.py
- 公司开发产品使用此拆分供多种人员使用
- 第六节 拓展添加Flask-migrate库
- 1. 增加数据库迁移功能
- 2. odoo框架介绍
第一节 flask的Hello world
1. flask基本知识
- Flask是一一个基于Python实现的Web开发‘微’框架
- 官方文档: http://flask.pocoo.org/docs/0.12/
- 中文文档: http://docs.jinkan.org/docs/flask/
- Flask和Django 样,也是一个基于MVC设计模式的Web框架
- Flask依赖三个库
- Jinja2模板引擎
- Werkzeug WSGI工具集
- ltsdangerous; 基于Django的签名模块
- MVC的设计模式目的是解耦:把用户逻辑、页面展示、数据库操作拆开来写。
from flask import Flask #导入flask
app = Flask(__name__)
#装饰器,用作url与视图函数的映射,一般写在函数上方
@app.route('/')
def index():
return 'Hello Flask'
#主函数,运行后在浏览器输入127.0.0.1:5000(或者进入控制台显示的地址即可)
#debug是否开启调试模式,开启后修改过python代码会自动重启
#threaded是否开启多线程
#port启动指定服务器的端口号
#host主机,默认是127.0.0.1, 指定为0.0.0.0代表所有ip可以连接本机
if __name__ == '__main__':
app.run()
- 开启debug. 会有一个PIN(密码)如下图:用于页面调试输入
return os.environ.get("FLASK_ENV") or "production"
- 这里有个Environment: production。 其实只要修改系统的环境变量FLASK_ENV
- 调试器有保护功能,页面调试如下
- 可以在网页中输出变量进行查看
第二节 Flask的命令行工具
1. 命令行工具flask-script
- debug是否开启调试模式,开启后修改过python代码会自动重启
- threaded是否开启多线程
- port启动指定服务器的端口号
- host主机,默认是127.0.0.1, 指定为0.0.0.0代表所有ip可以连接本机
- 下载flask-script: pip install flask-script -i https://pypi.douban.com/simple
- 初始化:使用app 构建Manage对象。manager = Manager(app)
- 运行:manager.run()
2. flask-script使用
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/')
def index():
return 'Hello Flask'
if __name__ == '__main__':
manager.run()
- 直接运行脚本,已经不能启动项目。(需要用命令行来启动命令)
- 使用命令: python manager.py runserver
- python manager.py runserver --help (查看可用命令)
- 如:(-h HOST, --host HOST) (-p PORT, --port PORT ) (–threaded) (-d, --debug)
第三节 第一阶段_拆路由
1. 着手拆分
- 项目目录创建如下。
- 把路由写到views 文件中
# views.py
from manage import app
@app.route('/')
def index():
return 'Hello Flask'
- 运行:python manager.py runserver 报错截图如下.(这是因为views根本没有注册到app中,app根本不知道views文件的存在)
2. 尝试解决
- 尝试解决方法一:
- 直接在manage.py 中导入路由函数。from App.views import index
- 结果报错:ImportError: cannot import name ‘index’
- 报错原因:循环导入(你导我,我导你)
- 尝试对代码做一些变换:
- 把manage.py的注册app的代码移动到项目的初始化文件__init__.py中
# App文件夹下的__init__.py
from flask import Flask
def create_app():
app = Flask(__name__)
return app
- manage.py 中引入create_app()
from App import create_app
app = create_app()
- 这时候views依然没有导入,如果直接在__init__.py中引入views。依然没有解决循环引用的问题。
3. 解决方案一:懒加载
- 直接在views.py中, 通过函数把app的值传过来
# views.py
def init_route(app):
@app.route('/')
def index():
return 'Hello Flask'
- 在__init__.py中引入初始化函数,把app的值传过去。这样的化views.py就没有导入app了。
# App文件夹下的__init__.py
from flask import Flask
from App.views import init_route
def create_app():
app = Flask(__name__)
init_route(app)
return app
- 结果:解决问题实现拆分。具体逻辑图如下:
- 这种方法并不是很好(不好看), 所有的路由都在一块(也可以拆)。
4. 解决方案二:蓝图flask-blueprint
- 下载flask-blueprint: pip install flask-blueprint -i https://pypi.douban.com/simple
- 蓝图是比较流行的一种方式。
- 修改views.py文件,注册蓝图。
# views.py
from flask import Blueprint, render_template
# 申明一个蓝图对象
blue = Blueprint('blue', __name__)
@blue.route('/')
def index():
return '我是蓝图的主页!'
#渲染模板和传参 {{ msg }}
#return render_template('index.html', msg="今天天气好")
- 在__init__.py中导入蓝图并注册蓝图。
from flask import Flask
from App.views import blue
def create_app():
app = Flask(__name__)
# 注册蓝图
app.register_blueprint(blue)
return app
- pycharm小技巧,把文件变成python包。用这种方法可以把蓝图划分成不同的蓝图路由。
第四节 第二阶段_拆数据模型
1.数据模型构建
- 安装flask-sqlalchemy:pip install flask-sqlalchemy -i https://pypi.douban.com/simple
- model.py也是由app实例构建的,实现一个数据库模型:
from manage import app
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
# 会员数据模型
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True) # 编号
username = db.Column(db.String(100), unique=True) # 昵称
password = db.Column(db.String(100)) # 密码
- 和上面views同样的问题, app这里需要引入。还需要把models注册到app中构成循环引用。
2. 官方方案之懒加载
- 假如不加修改采用我们之前的懒加载模式models.py代码如下。会出现db没有定义为全局变量的问题。
# models.py
from flask_sqlalchemy import SQLAlchemy
def init_model(app):
db = SQLAlchemy(app)
# 会员数据模型
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True) # 编号
username = db.Column(db.String(100), unique=True) # 昵称
password = db.Column(db.String(100)) # 密码
- 官方给出了解决方案如下:
# models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# 官方的解决方案
def init_model(app):
db.init_app(app=app)
# 会员数据模型
class User(db.Model):
id = db.Column(db.Integer, primary_key=True) # 编号
username = db.Column(db.String(100), unique=True) # 昵称
password = db.Column(db.String(100)) # 密码
- 在__init__.py中引入初始化函数和数据库的配置。把init_model导过去传值app。
# __init__.py
from flask import Flask
from App.views import blue
from App.models import init_model
def create_app():
app = Flask(__name__)
app.register_blueprint(blue)
# uri数据库+驱动://用户 名:密码@主机:端口/具体哪一个库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/flask_test'
# 保持兼容性
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
init_model(app)
return app
- 通过路由创建数据表。提前先构建一个数据库flask_test.运行后生产user表。
# views.py
from flask import Blueprint
from App.models import db
# 申明一个蓝图对象
blue = Blueprint('blue', __name__)
@blue.route('/createdb')
def createdb():
db.create_all()
return '创建数据表成功'
第五节 第三阶段_分离配置和第三方库(包括上面的models)
1. 分离第三方库出__init__.py
正常练手项目使用此拆分已经可以足够完成
- 创建配置文件settings.py
- 创建第三方库文件ext.py
- 分离models.py中的一些模型初始化,这里把views看成内置模块就放在__init__.py文件中。为了和django模型保持一致。这里也把上面的db变成models。
#models.py
from App.ext import models
# 会员数据模型
class User(models.Model):
id = models.Column(models.Integer, primary_key=True) # 编号
username = models.Column(models.String(100), unique=True) # 昵称
password = models.Column(models.String(100)) # 密码
- ext.py文件中放入需要导入的第三方库如:models初始化SQLAlchemy库
# ext.py
from flask_sqlalchemy import SQLAlchemy
models = SQLAlchemy()
def init_ext(app):
# 懒加载模型
models.init_app(app=app)
- 在__init__.py中懒加载ext.py中的init_ext。函数
# __init__.py
from flask import Flask
from App.views import blue
from App.ext import init_ext
def create_app():
app = Flask(__name__)
# uri数据库+驱动://用户 名:密码@主机:端口/具体哪一个库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/flask_test'
# 保持兼容性
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
init_ext(app=app)
app.register_blueprint(blue)
return app
# views.py
from flask import Blueprint, render_template
# 这里注意要导入models中的models,而不是刚刚注册的ext中的models
from App.models import models
# 申明一个蓝图对象
blue = Blueprint('blue', __name__)
@blue.route('/')
def index():
#渲染模板和传参 {{ msg }}
#return render_template('index.html', msg="今天天气好")
return 'Hello Flask'
@blue.route('/createdb')
def createdb():
models.create_all()
return '创建数据表成功'
- 模型可用的原因:views中导入了models
2. 分离配置出__init__.py
公司开发产品使用此拆分供多种人员使用
- 公司中常常需要配置多套环境。
- 开发环境(开发人员使用)
- 测试环境(测试人员使用)
- 演习环境(给产品看的)
- 生产环境 (又叫线上环境给用户使用)
- 把四套环境的配置写到配置文件的settings.py中。
def get_db_uri(dbinfo):
engine = dbinfo.get("ENGINE") or "mysql"
driver = dbinfo.get("DRIVER") or "pymysql"
user = dbinfo.get("USER") or "root"
password = dbinfo.get("PASSWORD") or "123456"
host = dbinfo.get("HOST") or "localhost"
port = dbinfo.get("PORT") or "3306"
dbname = dbinfo.get("DBNAME") or "flask_test"
# uri数据库+驱动://用户名:密码@主机:端口/具体哪一个库
return '{}+{}://{}:{}@{}:{}/{}'.format(engine, driver, user, password, host, port, dbname)
class Config:
DEBUG = False
TESTING = False
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 开发环境
class DevelopConfig(Config):
DEBUG = True
dbinfo = {
"ENGINE": "mysql",
"DRIVER": "pymysql",
"USER": "root",
"PASSWORD": "123456",
"HOST": "127.0.0.1",
"PORT": "3306",
"DBNAME": "flask_test"
}
SQLALCHEMY_DATABASE_URI = get_db_uri(dbinfo)
# 测试环境
class TestConfig(Config):
dbinfo = {
"ENGINE": "mysql",
"DRIVER": "pymysql",
"USER": "root",
"PASSWORD": "123456",
"HOST": "127.0.0.1",
"PORT": "3306",
"DBNAME": "flask_test"
}
SQLALCHEMY_DATABASE_URI = get_db_uri(dbinfo)
# 演示环境
class StageConfig(Config):
dbinfo = {
"ENGINE": "mysql",
"DRIVER": "pymysql",
"USER": "root",
"PASSWORD": "123456",
"HOST": "127.0.0.1",
"PORT": "3306",
"DBNAME": "flask_test"
}
SQLALCHEMY_DATABASE_URI = get_db_uri(dbinfo)
# 线上(生产)环境
class ProductConfig(Config):
dbinfo = {
"ENGINE": "mysql",
"DRIVER": "pymysql",
"USER": "root",
"PASSWORD": "123456",
"HOST": "127.0.0.1",
"PORT": "3306",
"DBNAME": "flask_test"
}
SQLALCHEMY_DATABASE_URI = get_db_uri(dbinfo)
envs = {
"develop": DevelopConfig,
"testing": TestConfig,
"staging": StageConfig,
"product": ProductConfig,
"default": DevelopConfig
}
- 把配置文件写到__init__.py文件中去。
from flask import Flask
from App.views import blue
from App.ext import init_ext
from App.settings import envs
def create_app():
app = Flask(__name__)
app.register_blueprint(blue)
# uri数据库+驱动://用户名:密码@主机:端口/具体哪一个库
#app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/flask_test'
# 保持兼容性
#app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config.from_object(envs.get("develop"))
init_ext(app=app)
return app
- 配置文件中的envs.get(“develop”),可以通过变量形式传入(比如获取当前电脑的环境变量,或者传入一个需要的环境)。
# __init__.py
from flask import Flask
from App.views import blue
from App.ext import init_ext
from App.settings import envs
def create_app(env):
app = Flask(__name__)
app.register_blueprint(blue)
# uri数据库+驱动://用户名:密码@主机:端口/具体哪一个库
#app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/flask_test'
# 保持兼容性
#app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config.from_object(envs.get(env))
init_ext(app=app)
return app
# manage.py
from flask_script import Manager
from App import create_app
import os
# 这样做的好处是,在开发的电脑上就是开发环境。在测试电脑上就是测试环境。
# 前提需要配置环境变量的值FLASK_ ENV。
env = os.environ.get("FLASK_ ENV", "develop")
app = create_app(env)
manager = Manager(app)
if __name__ == '__main__':
manager.run()
第六节 拓展添加Flask-migrate库
1. 增加数据库迁移功能
- Flask-migrate库用于拓展flask的数据库的类似django的迁移功能。
- pip install flask-migrate -i https://pypi.douban.com/simple
- 它和Flask-Script可以配合使用。from flask_migrate import MigrateCommand
- 操作命名db命令,manager.add_command(‘db’, MigrateCommand)
- 在ext.py中注册
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
models = SQLAlchemy()
migrate = Migrate()
def init_ext(app):
# 懒加载模型
models.init_app(app=app)
migrate.init_app(app, models)
- 在manage.py中绑定命令
from flask_script import Manager
from App import create_app
from flask_migrate import MigrateCommand
import os
# 这样做的好处是,在开发的电脑上就是开发环境。在测试电脑上就是测试环境。
# 前提需要配置环境变量的值FLASK_ ENV。
env = os.environ.get("FLASK_ ENV", "develop")
app = create_app(env)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
- 运行python manage.py runserver --help
- 初始化数据库:python manage.py db init
- 生成迁移文件:python manage.py db migrate
- 生成数据库:python manage.py db upgrade
2. odoo框架介绍
- 比django还重的框架。
- 可以一键生成网站