(根据居然老师直播课内容整理)

一、准备工作

  • 经过分析,项目需要用f以下技术

    • lask框架前后端分离
    • mysql数据库
    • redis数据库
    • 工程日志
    • 前端静态文件

1.创建虚拟环境

pipenv shell

2、安装Flask框架及相关包

  • 需要用到以下安装包

    • Flask框架
    • flask-sqlalchemy 数据库连接
    • 2.3 redis 数据库连接
    • 2.4 flask-wtf :表单处理
    • 2.5 flask-session :session 和 cookies应用
pip install flask
pip install flask-sqlalchemy
pip install redis
pip install flask-wtf
pip install flask_session

3、创建Flask工程

二、配置环境

  • 根据项目分析,项目需要准备以下内容

    1. flask框架
  • 2、mysql

  • 3、redis

  • 4、session:参数SESSION_TYPE和SESSION_REDIS保存到redis数据库中,并对session签名

  • form验证表单需要加密

  • flask框架入口文件一般用manage.py,现在把所有可能用的到东西都写到一个入口文件,再进行拆分

1、入口文件准备

  • 入口文件需要准备以下内容:
    1、配置参数:定义成一个配置类,保存配置参数
  • mysql数据库配置参数
    • 安装并启动mysql数据库,并定义相关配置参数
  • redis数据库配置参数:注册时可能会用到图片和短信验证,保存到redis数据库中
    • 安装redis数据库
  • session保存redis数据库中时,需要配置
    2、加载配置文件
    3、创建mysql数据库
    4、创建redis数据库
    5、session绑定app
    6、form验证表单 wtf csrf
# manage.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
import redis
from flask_wtf import CSRFProtectapp=Flask(__name__)class Config():"""配置信息"""SECRET_KEY="ASDFLKASDKJF%AKLSDXO$IPPIUF"  # 字符串随便设,用于session签名使用# mysql数据库配置# 连接数据库MYSQL_HOSTNAME = '127.0.0.1'# 数据库MYSQL_DATABASE = 'testdb'# 端口MYSQL_PORT = 3306# 用户名和密码MYSQL_USERNAME = 'root'MYSQL_PASSWORD = 'root'# mysql+pymysql://用记名:密码@址址:端口/数据库DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_HOSTNAME, MYSQL_PORT, MYSQL_DATABASE)# redis 配置REDIS_HOSTNAME="127.0.0.1"REDIS_PORT=6379# flask-sessionSESSION_TYPE = 'redis'SESSION_REDIS = redis.Redis(host=REDIS_HOSTNAME, port=REDIS_PORT)SESSION_USE_SIGNER = True   # session 签名PERMANENT_SESSION_LIFETIME = 86400  # session生命周期,单位是秒,1天=60*60*24# 加载配置参数
app.config.from_object(Config)# 建立mysql数据库对象
db=SQLAlchemy(app)# 创建Redis
redis_store = redis.Redis(host=Config.REDIS_HOSTNAME, port=Config.REDIS_PORT)# session
Session(app)# post请求  wtf  csrf
CSRFProtect(app)app.route("/")
def index():return "hello world!"if __name__=="__main__":app.run()

2、入口文件拆分

2.1 拆分配置文件

  • 项目配置文件一般都是单独的文件,故把 配置类拆分到配置文件中
  • 项目一般都会分为开发环境和生产环境,所以再创建两个类,用于区分开发和生产环境,有些参数都是共用,所以两个类共用公共部分基类
  • 加载配置文件时,怎么区分哪个是生产环境哪个是开发环境,有两种方式,一般对app定义采用工厂模式,传递参数,在函数内进行区分
    • 方式一:用if判断进行区分
    • 方式二:用字典引用

2.1.1 拆分后的配置文件

import redisclass Config():"""配置信息"""SECRET_KEY = 'ASDAXCWE5ERTFG%%DAS34'   # 这个字符串自己随便写,用于session加密# mysql配置MYSQL_HOSTNAME = '127.0.0.1'MYSQL_DATABASE = 'testdb'MYSQL_PORT = 3306MYSQL_USERNAME = 'root'MYSQL_PASSWORD = 'root'# mysql+pymysql://用记名:密码@址址:端口/数据库DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_HOSTNAME, MYSQL_PORT,MYSQL_DATABASE)# redis 配置REDIS_HOSTNAME = "127.0.0.1"REDIS_PORT = 6379# flask-session  session保存到redis中SESSION_TYPE = 'redis'SESSION_REDIS = redis.Redis(host=REDIS_HOSTNAME, port=REDIS_PORT)SESSION_USE_SIGNER = True               # 对session签名,即加密PERMANENT_SESSION_LIFETIME = 86400  # session生命周期, 单位是秒, 60*60*24=86400class DevConfig(Config):"""开发环境"""DEBUG = Trueclass ProConfig(Config):"""生产环境"""config_map = {'dev': DevConfig,'pro': ProConfig
}

2.1.2 对manage的改造

# manage.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
from flask_wtf import CSRFProtect
from config import config_map# 工厂模式
def create_app(config_name):app = Flask(__name__)# if config_name == "dev":#     from config import DevConfig#     app.config.from_object(DevConfig)# else:#     from config import ProConfig#     app.config.from_object(ProConfig)config_class = config_map.get(config_name)    # 获取配置文件,用字典get方法可防止config_name不存时报错app.config.from_object(config_class)                # 加载配置文件return appapp=create_app("dev")# 建立mysql数据库对象
db=SQLAlchemy(app)# 创建Redis
redis_store = redis.Redis(host=Config.REDIS_HOSTNAME, port=Config.REDIS_PORT)# session
Session(app)# post请求  wtf  csrf
CSRFProtect(app)app.route("/")
def index():return "hello world!"if __name__=="__main__":app.run()

2.2 对应用进行分模块

  • 将业务逻辑蓝图放到相应的包中:建api_1_0包,即V1.0蓝图包
  • 建立静态文件目录: static
  • 建立自已定义的工具包:utils
  • 建立第三工具目录:libs
  • 建立日志目录:logs
  • 为进一步区分入口文件、公共文件及目录和业务逻辑目录,需要建立一个业务逻辑包lghome,将业务逻辑相关内容放到此包中,即将 api_1_0、static、utils、libs都移到此目录下

2.3 对入口文件进一步拆分

  • 建立了业务逻辑包以后,入口文件中,业务逻辑相关的功能,都将移到相应的包中
  • 1、工厂模式定义的create_app、数据库定义、session、csrf 都移到lghome包的__init__中
  • 2、app路由移到api_1_0包中的一个文件里,以后再完善
  • 3、简化manage入口文件

2.3.1 将业务逻辑相关的代码移到lghome包的__init__中

  • 将相关代码移到__init__.py后,暂不处理报错,以后再优化
# ./lghome/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
from flask_wtf import CSRFProtect
from config import config_map# 工厂模式
def create_app(config_name):app = Flask(__name__)# if config_name == "dev":#     from config import DevConfig#     app.config.from_object(DevConfig)# else:#     from config import ProConfig#     app.config.from_object(ProConfig)config_class = config_map.get(config_name)    # 获取配置文件,用字典get方法可防止config_name不存时报错app.config.from_object(config_class)                # 加载配置文件return app# 建立mysql数据库对象
db=SQLAlchemy(app)# 创建Redis
redis_store = redis.Redis(host=Config.REDIS_HOSTNAME, port=Config.REDIS_PORT)# session
Session(app)# post请求  wtf  csrf
CSRFProtect(app)

2.3.2 将路由代码暂时移到蓝图api_1_0包的demo.py中

# ./lghome/api_1_0/demo.py# app.route("/")
# def index():
#     return "hello world!"

2.3.3 优化入口文件manage.py

from lghome import create_appapp = create_app('dev')if __name__ == '__main__':app.run()

3、初步优化lghome包__init__.py

上面将代码移到__init__.py时,数据库定义、session、csrf 未处理

3.1 完善数据库定义

  • 将 db和redis_store 定义放到 create_app函数前面,但不绑定,方便其它项目引用,当app初始化后,再进行绑定
# mysql数据库定义
db = SQLAlchemy()
# 创建Redis
redis_store = None
  • app在create_app函数中定义,故db 和 redis_store放在create_app中绑定

    • redis_store 定义为None ,所以绑定时重新赋值即可,即在函数内用global 重新赋值
    # 使用app初始化dbdb.init_app(app)# redis配置global redis_storeredis_store = redis.Redis(host=config_class.REDIS_HOST, port=config_class.REDIS_PORT)

3.2 完善session、csrf 定义

  • session 和 csrf 无需单独定义,直接在create_app中定义即可
   # sessionSession(app)# post请求  wtf  csrfCSRFProtect(app)

3.3 初步优化后的__ini__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
from flask_wtf import CSRFProtect
from config import config_map
import redisdb = SQLAlchemy()# 创建Redis
redis_store = None# 工厂模式
def create_app(config_name):app = Flask(__name__)config_class = config_map.get(config_name)app.config.from_object(config_class)# 使用app初始化dbdb.init_app(app)# redis配置global redis_storeredis_store = redis.Redis(host=config_class.REDIS_HOST, port=config_class.REDIS_PORT)# sessionSession(app)# post请求  wtf  csrfCSRFProtect(app)

4、优化数据库参数设置

  • 因数据库参数化时未定义 SQLALCHEMY_DATABASE_URI
  • 未设置 SQLALCHEMY_TRACK_MODIFICATIONS
  • 故修改配置文件即可
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_HOSTNAME, MYSQL_PORT,MYSQL_DATABASE)SQLALCHEMY_TRACK_MODIFICATIONS = False

完整代码如下:

import redisclass Config():"""配置信息"""SECRET_KEY = 'ASDAXCWE5ERTFG%%DAS34'   # 这个字符串自己随便写,用于session加密# mysql配置MYSQL_HOSTNAME = '127.0.0.1'MYSQL_DATABASE = 'testdb'MYSQL_PORT = 3306MYSQL_USERNAME = 'root'MYSQL_PASSWORD = 'root'# mysql+pymysql://用记名:密码@址址:端口/数据库SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_HOSTNAME, MYSQL_PORT,MYSQL_DATABASE)SQLALCHEMY_TRACK_MODIFICATIONS = False# redis 配置REDIS_HOSTNAME = "127.0.0.1"REDIS_PORT = 6379# flask-session  session保存到redis中SESSION_TYPE = 'redis'SESSION_REDIS = redis.Redis(host=REDIS_HOSTNAME, port=REDIS_PORT)SESSION_USE_SIGNER = True               # 对session签名,即加密PERMANENT_SESSION_LIFETIME = 86400  # 单位是秒,session生命周期,  60*60*24=86400class DevConfig(Config):"""开发环境"""DEBUG = Trueclass ProConfig(Config):"""生产环境"""config_map = {'dev': DevConfig,'pro': ProConfig
}

5、入口文件中进行数据库迁移

  • flask框架使用数据库,需要对数据进行迁移,并将app启动改为manage启动
    • 数据库迁移时,注意导入db
from lghome import db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand# 数据库迁移
manage = Manager(app)
Migrate(app, db)
manage.add_command('db', MigrateCommand)
  • manage.py完善后代码
from lghome import create_app, db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommandapp = create_app('dev')# 数据库迁移
manage = Manager(app)
Migrate(app, db)
manage.add_command('db', MigrateCommand)if __name__ == '__main__':manage.run()

6、初步完善视图文件

6.1 定义视图文件

  • 定义蓝图,并初步定义首页路由
    • @app.route("/")改为 @api.route("/")
./lghome/api_1_0/demo.py
from flask import Blueprintapi = Blueprint('api_1_0', __name__, url_prefix='/api/v1.0')@api.route("/")
def index():return "index page"

6.2 将 蓝图定义移到api_1_0包的__init__.py中

  • 因为蓝图定义,在整个包中都会使用,故需要移到__init__.py 中,方便引用
  • 在视图文件中引用蓝图api
  • 在__init__.py中将蓝图定义与路由关联起来(注意:如果不执行此步骤,系统不会报错,但无法正确显示页面)

# ./lghome/api_1_0/__init__.py
from flask import Blueprintapi = Blueprint('api_1_0', __name__, url_prefix='/api/v1.0')from . import dmeo

6.3 将蓝图与app绑定

  • 蓝图定义后,与app绑定后,才能影响前端的请求,即在create_app函数中将蓝图与app绑定

    • app.register_blueprint(蓝图的实例名)
# ./lghome/__init__.py
...
def create_app(config_name)... ...# 注册蓝图from lghome import api_1_0app.register_blueprint(api_1_0.api)

7.到此为止,项目入口文件已拆分完成

  • 运行系统即可访问: http://127.0.0.1/api/v1.0/index

    运行结果如下:

8.可能遇到的坑

  • 可能会出现循环导入,例:对db引用:

    • manage.py中需要导入db

    • lghome/init.py 中定义了db ,且引用了 lghome/api_1_0/init.py 中的api ,此时db 未创建

    • lghome/api_1_0/init.py中,引用了lghome/api_1_0/demo.py

    • lghome/api_1_0/demo.py 定义了路由,需要访问数据库,引了 db ,但db未创建,至此形成了循环引用。

    • 解决办法:

  • 在 lghome/init.py 中 工厂模式create_app函数内,注册蓝图时再引用api,如下图:
  • 即:
    • manage.py中需要导入db
    • lghome/init.py 中定义了db ,必入时未执行create_app函数,就未引用了 lghome/api_1_0/init.py 中的api ,可顺利完成引用, 随后db 已创建,完成引用
    • 当manage.py中调用create_app函数时,引用了 lghome/api_1_0/init.py 中的api
    • lghome/api_1_0/init.py中,引用了lghome/api_1_0/demo.py
    • lghome/api_1_0/demo.py 定义了路由,需要访问数据库,引了 db ,但db已创建,完美的避开了循环引用。

三、项目日志配置

  • 项目框架搭建时,需要搭建日志记录功能模块,支持系统各模块记录日志使用

1、创建日志模块方法

# 日志
def setup_log():# 设置日志的的登记  DEBUG调试级别logging.basicConfig(level=logging.DEBUG)# 创建日志记录器,设置日志的保存路径和每个日志的大小和日志的总大小# log 100M  log1  logfile_log_handler = RotatingFileHandler("logs/log.log", maxBytes=1024*1024*100,backupCount=100)# 创建日志记录格式,日志等级,输出日志的文件名 行数 日志信息formatter = logging.Formatter("%(levelname)s %(filename)s: %(lineno)d %(message)s")# 为日志记录器设置记录格式file_log_handler.setFormatter(formatter)# 为全局的日志工具对象(flaks app使用的)加载日志记录器logging.getLogger().addHandler(file_log_handler)

2、启动日志

  • 在create_app()时,启动日志

3、记录日志

  • 在需要记录日志的地方,调用logger即可
# 创建日志记录器
logger = logging.getLogger('django')
# 输出日志
logger.debug('测试logging模块debug')
logger.info('测试logging模块info')
logger.error('测试logging模块error')

4、日志更多操作详见《Flask中日志logging的使用》

四、通过蓝图方式调用静态html提供前端界面

  • 本项目是前后端分离的开发模式,为开发调试方便,通过蓝图方式提供调用静页面实现前端界面

  • 这里创建的蓝图与api_1_0的蓝图没有关系。

  • 例本项目将:静态文件保存到lghome/static/目录下

  • 可以这样访问:

    • http://127.0.0.1:5000/static/html/index.html

    • 但直接将服务器的路径都暴露了

  • 建议访问方式:

    • 127.0.0.1:5000/ 访问首页
    • 127.0.0.1:5000/index.html 访问首页
    • 127.0.0.1:5000/register.html 访问注册
  • 为发达到这个效果,需要进行路由转换,自定义一个路由转换器

1、自定义一个路由转换器

  • 在lghome/utils下创建 路由转换器
from werkzeug.routing import BaseConverterclass ReConverter(BaseConverter):def __init__(self,map,regex):super().__init__(map)self.regex=regex

2、将自定义的路由转换器添加到

  • 路由转换器定义后,需要添加到flask框加中
  • 在注册app 时,将自定义路由转换器添加到 app.url_map.converters字典中
app.url_map.converters["re"]=ReConverter

3、定义静态html蓝图及路由

  • 在lghome下创建蓝图文件commons.py

    • 定义蓝图
    • 定义通用路由:根据自定路由转换器
    • 静态html文件在static/home下面,少了一级目录,所以把home加上即可
    • 如果没有输入页面(没有传递参数),应该访问主页,判断一下改成index.html
# /lghome/commons.pyfrom flask import Blueprint,current_apphtml=Blueprint("web_html",__name__)@html.route("/<re('.*'):html_file_name>")
def get_html(html_file_name):# 访问首页if not html_file_name:html_file_name="index.html"html_file_name = 'html/' + html_file_namereturn current_app.send_static_file(html_file_name)

4、注册静态蓝图

  • 在create_app函数中注册静态蓝图
    # 注册静态蓝图from lghome import web_htmlapp.register_blueprint(web_html.html)

五、数据库模型准备

  • 数据库设计需要根据实际需求来设计

1、用户表user

  • 通地注册界面分析,user表应该有:id、mobile、password
  • 通过个人信息分析,user表应该还有:name、real_name、id_card、avater_url

2、房屋表house

  • house_id 、user_id、title、price、area_id
  • 房屋所在区域独立建表
  • 房屋轮播图信息也独立建表
  • 房屋标签信息也独立建表

3、区域表 area

  • area_id、name

4、房屋轮播图 house_image

  • url 、house_id

5、房屋标签信息 faciliy

  • faciliy_id、name

6 定单表 order

  • id 、user_id、house_id、create_time、start_time、end_time、price、status、days、amount、comment

六、数据库迁移

1、 db init

2、 db migrate

3、 db upgrade

4、检查

5、可能遇到的问题

5.1 执行db migrate报错,提示: ModuleNotFoundError:No module named ‘pymysql’

  • 解决办法:pip install pymysql

5.2 执行db upgrade报错,提示:

  • 解决办法:在蓝图进行引用(代码编写后,未在系统中进行引用)

七、注意事项:

1、 系统运行前,需要启动以下数据库,并保证参数正确:

  • mysql
  • redis

2、安装必要的包

3、如果出现下面错误

flask项目1实战:1、项目准备(二)工程开发环境准备(待进一步细化完善)相关推荐

  1. 【以项目实战讲解CAD的二次开发】

    以项目实战讲解CAD的二次开发 说明 背景目的 环境搭建 c++ .net 启动程序 后续的框架构想 总结 说明 这是我的第一个博客,之前也一直不敢写,本人能力有限,怕写错,误导一批新手.也很久没有较 ...

  2. java服务器要二次编译,ecology项目二次开发环境搭建

    ecology项目二次开发环境搭建 Submitted By Weaver 文档版本控制 文档简要信息: 文档主题(Title) ecology项目二次开发环境搭建 作者(Author) 审批者 (T ...

  3. 项目总结25:海康威视SDK-Java二次开发-客流量分析

    项目总结25:海康威视SDK-Java二次开发-客流量分析 前言 本来一个很简单的SDK接口对接,折腾了好久:总结下原因有: 海康的SDK底层使用C++写的,我不熟悉C++: 海康Java源码示例写的 ...

  4. ArcGIS Pro二次开发环境配置及项目创建示例

    一.软件版本 ArcGIS Pro 2.8 Visual Studio 2019 二.组件 ArcGIS Pro 2.8 SDK for .NET: proapp-sdk-templates.vsix ...

  5. php 数据采集模板,基于PHP实战帝国CMS系统二次开发(标签、模板、快速仿站、数据采集)...

    基于帝国CMS的网站开发是一套从入门至精通的帝国视频教程,该教程细腻入微的由服务器配置.帝国CMS安装.DIV+CSS模版制做,通过帝国CMS去实现模版的功... 基于帝国CMS的网站开发是一套从入门 ...

  6. qgis二次开发环境搭建(超级详细)

    最近有一个项目要求基于qgis+QT进行二次开发开发,要使用到qgis平台.陆陆 续续花了差不多两个多星期,在把开发环境搭建起来. 首先就面临2种选择,一种 到qgis官网下载源码,进行编译,此 情况 ...

  7. SpringBoot-从入门到放弃(二) 开发环境的搭建

    SpringBoot-从入门到放弃(二) 开发环境的搭建 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/z23546498/article/deta ...

  8. creo2.0+VS2010采用protoolkit二次开发环境配置(64位win7)

    在网上找了很多资料,也遇到过很多问题.本文的配置过程主要参考了网上的两篇文章,地址如下: http://www.doc88.com/p-3085972896759.html http://wenku. ...

  9. SQL审核 | SQLE 二次开发环境搭建

    作者:Jason 就职于捷信消费金融有限公司,担任 DBA 工作.先后从事过 oracle .mongo .mysql 的 DBA ,以及大数据 ETL 的开发工作.对 NEWSQL 以及云原生分布式 ...

  10. Revit二次开发环境搭建(Revit 2019+Visual Studio 2017)

    Revit二次开发环境搭建(Revit 2019+Visual Studio 2017) 安装 Revit 2019 Visual Studio 2017 Revit SDK 2019 配置Addin ...

最新文章

  1. 参考答案:03 向量空间
  2. PyTorch的计算图和自动求导机制
  3. 数学之美 系列三 -- 隐含马尔可夫模型在语言处理中的应用
  4. 网易创新企业大会倒计时2天 《企业数字化升级之路》白皮书将发布
  5. RavenDb学习(十)附件,存储大对象
  6. 合并两个有序数组Python解法
  7. jquery响应式内容滑动插件bxSlider
  8. ICCV2021 |上交、北理、百度联合研究视频缩放任务中的自条件概率学习
  9. gdal数据类型_科学网-gdal数据类型的代码的核心定义文件-林清莹的博文
  10. db h2 数据类型_H2数据库函数及数据类型概述-阿里云开发者社区
  11. html和vue的区别,2018-09-16第四课 (v-html和v-text的区别,v-once和v-pre的区别,vue的生命周期,选项卡)...
  12. 如何在EDI系统中查询文件?
  13. 【数字信号处理】划重点
  14. Excel vba编程实现ftp下载并打开自动运行
  15. 优酷.kux文件折腾记
  16. MFC控件自适应调整大小
  17. html anki编辑器,打造你的专属单词本——Anki 初探(无痛入门)
  18. 传感器实验——火焰传感器
  19. Qt5.12.6 + VS2019添加图片资源文件
  20. 软件测试流程及规范(参考大华为的规范)

热门文章

  1. k均值算法 动图制作代码
  2. 详解拦截导弹问题(动态规划)
  3. 【Unity-学习-003】导弹,跟踪弹怎么玩?
  4. 不懂copy与deepcopy的区别?这一篇就够了
  5. 【全网最细PAT题解】【PAT乙】1044 火星数字(测试点2,测试点4详细解释)
  6. 写一个有app控制的自动开锁系统
  7. 【计量经济学】【高教版】第一次作业(7、8、10)
  8. 笔记本安装ubuntu18.04之后提示网络连接激活失败无法上网
  9. easyui 重置多条件查询
  10. 申请AI方向研究型博士、硕士指南