程序架构
|-- application.py # flask中的全局变量,包括APP,数据库等
|-- common # 相当于utils,存放公共部分
| |-- __init__.py
| |-- libs # 公共方法或者类
| |-- models # MVC中的models层
|-- config # 配置文件
| |-- base_setting.py # 基础设置
| |-- __init__.py
| |-- local_setting.py # 本地开发环境
| `-- production_setting.py # 生产环境
|-- docs # 文档存放部分
| `-- mysql.md # 所有数据库变更记录
|-- jobs # 定时任务
| |-- bash_jobs # 脚本文件
| |-- __init__.py
| |-- launcher.py # 自定义命令行启动
| |-- readme.md
| `-- tasks # 定时任务
|-- manager.py # 启动入口
|-- readme.md
|-- requirements.txt # 后端所需包
|-- uwsgi.ini # 部署配置文件
|-- web # 交互
| |-- controllers # MVC中的C,控制器部分
| |-- __init__.py
| |-- interceptors # 拦截器部分
| |-- static # 静态文件
| `-- templates # 模板文件
`-- www.py # HTTP模块相关初始化
项目所需依赖
创建虚拟环境安装如下包:
flask
flask-sqlalchemy
flask-debugtoolbar
mysqlclient
flask_script
requests
uwsgi
模型层引入
这里因为课程都是用flask-sqlacodegen反迁移的方式分别插入到相应的models文件中,相应命令为:
flask-sqlacodegen 'mysql://root:123456@127.0.0.1/food_db' --outfile "common/models/model.py" --flask
flask-sqlacodegen 'mysql://root:123456@127.0.0.1/food_db' --tables user --outfile "common/models/user.py" --flask
虽然看起来是没什么问题的,后续也就每个models文件都执行一次上面的命令,我认为如果按作者的逻辑顺序,我们首先创建好food_db数据库,编码为utf8mb4,然后我们导入他在数据库文件中的food.sql,source一下创建好所有的表:
然后我们show tables就能看到所有的表:
Query OK, 0 rows affected, 7 warnings (0.10 sec)
mysql> show tables;
+-------------------------+
| Tables_in_food_db |
+-------------------------+
| app_access_log |
| app_error_log |
| food |
| food_cat |
| food_sale_change_log |
| food_stock_change_log |
| images |
| member |
| member_address |
| member_cart |
| member_comments |
| oauth_access_token |
| oauth_member_bind |
| pay_order |
| pay_order_callback_data |
| pay_order_item |
| queue_list |
| stat_daily_food |
| stat_daily_member |
| stat_daily_site |
| user |
| wx_share_history |
+-------------------------+
22 rows in set (0.03 sec)
我们再依次对上述命令针对于每个models下的模块进行反迁移,我感觉这样其实也可以,如果是将所有models写进一个文件中,但按本项目中的架构就显得有点矛盾,在没有models代码的情况下,我们需要运行flask-sqlacodegen近20次才能保证所有文件都要模型类。
那么,上面的操作都是反向迁移,数据库已经提前写好了。但若是我们希望能正向迁移,那应该怎么做呢?
第一种方式我觉得能写一个文件将所有models文件连接起来,然后利用flask-migrate,对migrations中的env指向我们做好的文件中,这种我感觉理论上是行得通的,因为类似django的机制。但工作量会比较大,其次就是不符合flask的初衷,所以能用第二种方式,就是使用 db.create_all()函数,让 SQLAlchemy 根据模型类创建数据库。
将local_settings中数据库配置复制一份在application中直接引用:
app = Application( __name__,template_folder=os.getcwd() + "/web/templates/",root_path=os.getcwd())
app.config["SQLALCHEMY_DATABASE_URI"] = 'mysql://root:password@IP:prot/food_db?charset=utf8mb4'
然后在该文件所在文件目录下,打开终端,然后进入到 Python 命令行,你也可以用 python manager.py shell 这个命令。
>> from application import db
>> db.create_all()
然后就可以看见如下的sql语句:
2019-12-09 16:02:28,286 INFO sqlalchemy.engine.base.Engine ()
2019-12-09 16:02:28,400 INFO sqlalchemy.engine.base.Engine COMMIT
2019-12-09 16:02:28,437 INFO sqlalchemy.engine.base.Engine
CREATE TABLE wx_share_history (
id INTEGER NOT NULL AUTO_INCREMENT,
member_id INTEGER NOT NULL,
share_url VARCHAR(200) NOT NULL,
created_time DATETIME NOT NULL,
PRIMARY KEY (id)
)
所有用户表总结:
项目构建方式
主要是一些配置文件以及前期准备工作。
application.py 项目配置文件
# _*_ coding:utf-8 _*_
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from common.libs.UrlManager import UrlManager
import os
class Applicaltion(Flask):
def __init__(self,import_name,template_folder=None,root_path=None):
# 在自定义结构项目中要改变template、static默认的设置路径
super(Applicaltion,self).__init__(import_name,template_folder=template_folder,root_path=root_path,static_folder=None)
if "ops_config" in os.environ:
print(os.environ["ops_config"]) # 获取环境变量的值
# 根据环境变量改变配置文件
self.config.from_pyfile('config/%s_setting.py'%os.environ["ops_config"],silent=True)
db.init_app(self)
db = SQLAlchemy()
# root_path=os.getcwd() 设置默认的根目录路径
app = Applicaltion(__name__,template_folder=os.getcwd()+'/web/templates',root_path=os.getcwd())
manager = Manager(app)
'''
函数模板:把python方法注入到模板引擎中
'''
app.add_template_global(UrlManager.buildStaticUrl,'buildStaticUrl')
app.add_template_global(UrlManager.buildUrl,'buildUrl')
这里会出现一个问题,因为我们改变了静态文件所在的地址,没有用template目录,前面我们已经通过os模块将模板的路径地址进行了调整,而static_folder我们设置的是None,所以我们可以在本地环境下新建一个static.py的文件来管理静态文件;默认的静态目录是项目目录下直接的static,跟模板目录一样,需要重新设置加载路径。
static.py静态路径文件和urlmanager.py链接管理文件
# _*_ coding:utf-8 _*_
from flask import Blueprint,send_from_directory
from application import app
route_static = Blueprint('static',__name__)
@route_static.route('/<path:filename>')
def static(filename):
print(filename)
return send_from_directory(app.root_path + '/web/statics/',filename)
1.1.2、www.py 路由文件
# _*_ coding:utf-8 _*_
from application import app
# 引用路由文件
from web.controllers.index import home
app.register_blueprint(home,url_prefix='/')
部署到生成环境不需要这个文件,只是解决本地静态文件无法加载问题。其中的url管理类为:
# -*- coding: utf-8 -*-
class UrlManager(object):
def __init__(self):
pass
@staticmethod
def buildUrl( path ):
return path
@staticmethod
def buildStaticUrl(path):
ver = "%s"%( 22222222 )
path = "/static" + path + "?ver=" + ver
return UrlManager.buildUrl( path )
manager.py启动配置文件
# -*- coding: utf-8 -*-
from application import app,manager,db
from flask_script import Server
import www
from jobs.launcher import runJob
from flask_migrate import Migrate,MigrateCommand
from flask_sqlalchemy import SQLAlchemy
##web server
manager.add_command( "runserver", Server( host='0.0.0.0',port=app.config['SERVER_PORT'],use_debugger = True ,use_reloader = True) )
#job entrance
manager.add_command('runjob', runJob() )
# migrate = Migrate(app,db)
# manager.add_command('db',MigrateCommand)
def main():
manager.run( )
if __name__ == '__main__':
try:
import sys
sys.exit( main() ) # 启动退出程序
except Exception as e:
import traceback
traceback.print_exc() # trackback模块可以捕获异常并打印全面的异常信息
小程序申请
到这里准备工作基本就做完了。