【简说Python WEB】Flask应用的文件结构
系统环境:Ubuntu 18.04.1 LTS
Python使用的是虚拟环境:virutalenv
Python的版本:Python 3.6.9
【简说Python WEB】Flask应用的文件结构
之前,我们应用了如下的组件:
- flask-wtf
- Flask-SQLAlchemy
- Flask-Moment
- Jinja2模板
- Bootstrap
- flask-mail
- flask_migrate
因为之前调试和应用组件,插件,导致app.py
有一定的体量。对于大多数web应用来说,如果把代码都堆在以前,难以维护。而有一个不错的文件目录组织。可以很好的维护整个项目。通过自我学习,提炼出自己一套容易维护的文件结构。把之前的可以剥离出来的公用模块进行一个分离操作。
1.文件结构的目录
Zflask/
├── app
│ ├── email.py
│ ├── __init__.py
│ ├── main
│ │ ├── errors.py
│ │ ├── forms.py
│ │ ├── __init__.py
│ │ └── views.py
│ ├── models.py
│ └── templates
│ ├── 404.html
│ ├── 500.html
│ ├── base.html
│ ├── index.html
│ └── mail
│ ├── new_user.html
│ └── new_user.txt
├── config.py
├── LICENSE
├── README.md
├── requirements.txt
└── zsdblog.py
app/email.py
从原来app.py
剥离出来的邮件功能app/models.py
把之前的users
模型和roles
模型,剥离出来.app/__init__.py 一些初始化的通用脚本放在这里面,工厂函数
config.py
配置文件zsdblog.py
主驱动应用,用于驱动整个项目requirements.txt
依赖包main/errors.py
剥离出来的自定义错误处理程序(剥离原来的程序)main/forms.py
表单处理程序(剥离原来的程序)main/views.py
自定义的应用路由程序(剥离原来的程序)main/__init__.py 蓝本程序
2.配置程序--config.py
import os
class Config:
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = 'wojiubugaosuni'
MAIL_SERVER = 'smtp.qq.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ZSD_MAIL_SUBJECT_PREFIX = '[ZSD博客]'
ZSD_MAIL_SENDER = 'ZSD博客 管理员 <543421410@qq.com>'
ZSD_ADMIN = os.environ.get('ZSD_ADMIN')
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG=True
HOSTNAME = '172.30.200.252'
DATABASE = 'zsd'
USERNAME = 'zsd'
PASSWORD = 'zsd'
DB_URI = 'mysql+pymysql://{}:{}@{}:3306/{}?charset=utf8mb4'.format(
USERNAME, PASSWORD, HOSTNAME, DATABASE)
SQLALCHEMY_DATABASE_URI = DB_URI
class TestingConfig(Config):
TESTING = True
class ProductionConfig(Config):
PROD = True
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
把之前的URI驱动,MAIL配置,封装起来。通过不同的应用环境,调用不同的配置。
3.app应用包
数据库模型app/email.py
和电子邮件函数程序app/models.py
都移动至app包内。
延迟构建应用实例,把创建过程移动到可以显示调用的工厂函数中
app/__init__.py 代码
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
from config import config
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
整个代码中,可以看到引入了许多Flask的扩展。因为还没有初始化所需要的应用实例,这些构建类也没有真正的初始化,只是放在了那里。
必须有一个应用,通过调用create_app
函数,才算初始化了。
4.剥离出来的email.py
修改的代码如下:
def send_email(to, subject, template, **kwargs):
app = current_app._get_current_object()
msg = Message(app.config['ZSD_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
sender=app.config['ZSD_MAIL_SENDER'], recipients=[to])
msg.body = render_template(template + '.txt', **kwargs)
msg.html = render_template(template + '.html', **kwargs)
thr = Thread(target=send_async_email, args=[app, msg])
thr.start()
return thr
其中添加了一句app = current_app._get_current_object()
调用的是current_app
而不是原来的app
5.蓝本(BLueprint)的应用
蓝本(BLueprint)实现应用的模块化,可以定义路由和错误处理程序,使得应用层次更清晰。
其中,蓝本中定义的路由和错误处理程序是处在sleep
状态。只有蓝本注册到应用上面了,它们才成为应用的一部分。这种插槽式的应用构建,非常灵活。
main/__init__.py 创建蓝本
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
然后在app/init.py程序中,把蓝本在工厂函数create_app()中注册到应用上。
app/__init__.py 蓝本注册
#..
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
6.main目录的error.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
其中errorhandler
被换成了app_errorhandler
, 相当于全局的错误处理程序。
7. main目录的view.py代码剥离:
from flask import render_template, session, redirect, url_for, current_app
from .. import db
from ..models import User
from ..email import send_email
from . import main
from .forms import NameForm
@main.route('/', methods=['GET', 'POST'])
def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username=form.name.data)
db.session.add(user)
db.session.commit()
session['known'] = False
if current_app.config['FLASKY_ADMIN']:
send_email(current_app.config['FLASKY_ADMIN'], 'New User',
'mail/new_user', user=user)
else:
session['known'] = True
session['name'] = form.name.data
return redirect(url_for('.index'))
return render_template('index.html',
form=form, name=session.get('name'),
known=session.get('known', False))
其中current_app
替换了原来的app
if current_app.config['FLASKY_ADMIN']:
send_email(current_app.config['FLASKY_ADMIN'], 'New User',
'mail/new_user', user=user)
url_for('index')
需要换成url_for('main.index')
main代表这个蓝本下的index路由跳转。
路由装饰器由蓝本提供,所以需要改成:@main.route
8.主脚本
zsdblog.py
代码如下:
import os
from flask_migrate import Migrate
from app import create_app, db
from app.models import User, Role
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Role=Role)
上述脚本,创建一个应用实例,环境变量FLASK_CONFIG
可以定义,如果不定义。做默认配置。
这次,可以开启DEBUG模式,如下:
设置环境变量:
(zsdpy1) $ export FLASK_APP=zsdblog.py
(zsdpy1) $ export FLASK_DEBUG=1
9.需要安装的依赖包
(zsdpy1) $ pip freeze >>requirements.txt
10.应用启动
(zsdpy1) $ flask run -h '0.0.0.0' -p 9000
当然如果有db模型更新的话,可以使用
flask db upgrade
更新到最新的模型DDL语。
应用效果如下:
附录
执行代码的时候,出现了如下错误 :
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'main.index' instead?
File "/home/zsd/Zflask/app/main/views.py", line 24, in index
return redirect(url_for('index'))
可以看到/home/zsd/Zflask/app/main/views.py
24行代码有问题,修改为如下 :
return redirect(url_for('main.index'))
【简说Python WEB】Flask应用的文件结构的更多相关文章
- 【简说Python WEB】数据库
目录 [简说Python WEB]数据库 数据库表 docker安装MySQL Flask-SQLAlchemy操纵MySQL数据库 初始化 定义模型 定义关系 数据库的CRUD操作 创建表 inse ...
- 【简说Python WEB】Flask-Moment
目录 [简说Python WEB]Flask-Moment 系统环境:Ubuntu 18.04.1 LTS Python使用的是虚拟环境:virutalenv Python的版本:Python 3.6 ...
- 【简说Python WEB】视图函数操作数据库
目录 [简说Python WEB]视图函数操作数据库 系统环境:Ubuntu 18.04.1 LTS Python使用的是虚拟环境:virutalenv Python的版本:Python 3.6.9 ...
- 【简说Python WEB】Web应用部署
目录 [简说Python WEB]Web应用部署 应用层 缓存层 数据层 Gunicorn 的应用 1.安装Gunicorn 2.Gunicorn的启动 Nginx 的应用 1.docker方式部署安 ...
- 【简说Python WEB】pyechart在flask中的应用
个人笔记总结,可读性不高.只为自己总结用.怕日后忘记. 这里用到了tushare,pandas等python组件. pyechart的案例 c = ( Bar() .add_xaxis([" ...
- python web -- flask
Flask是一个简洁的 Python_web 框架. 零. virtualenv 虚拟环境配置. $ easy_install pip $ pip install virtualenv $ virtu ...
- Python Web Flask源码解读(一)——启动流程
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- Python Web Flask源码解读(二)——路由原理
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- 【简说Python WEB】flask-mail电子邮件
目录 flask-mail flask shell发送邮件 系统环境:Ubuntu 18.04.1 LTS Python使用的是虚拟环境:virutalenv Python的版本:Python 3.6 ...
随机推荐
- Python 搭建webdriver环境遇到的问题总结
安装过程是参考<selenium2Python自动化测试实战>中Pythonwebdriver环境搭建章节 在安装过程中,遇到了一些问题,总结一下,为日后自己再遇到相同问题做个笔记以便查看 ...
- ActiveMQ学习总结(一)
自己写的网上商城项目中使用了ActiveMQ,虽然相比于RabbitMQ,kafka,RocketMQ等相比,ActiveMQ可能性能方面不是最好的选择,不过消息队列其实原理区别不大,这里对学过的关于 ...
- Swift 浅谈Struct与Class
讨论Struct与Class之前,我们先来看一个概念:Value Type(值类型),Reference Type(引用类型): 1. 值类型的变量直接包含他们的数据,对于值类型都有他们自己的数据副本 ...
- OpenCA搭建
前言: OpenCA是OpenCA开源组织使用Perl对OpenSSL进行二次开发而成的一套完善的PKI免费软件,主要由四部分组成:CA.RA.PUB和NODE.简而言之,PUB是对外提供服务的接口, ...
- 事务Transaction
目录 为什么写这系列的文章 事务概念 ACID 并发事务导致的问题 脏读(Dirty Read) 非重复读(Nonrepeatable Read) 幻读(Phantom Reads) 丢失修改(Los ...
- iMX287A基于嵌入式Qt的新冠肺炎疫情监控平台
目录 1.前言 2.数据接口的获取 3.Qt界面的实现 4.在开发板上运行Qt程序 5.最终效果 6.代码下载 @ 1.前言 之前我使用在桌面版本Qt实现了肺炎疫情监控平台:基于Qt的新冠肺炎疫情数据 ...
- Arthas 实战,助你解决同名类依赖冲突问题
上篇文章中,小黑哥分析 Maven 依赖冲突分为两类: 项目同一依赖应用,存在多版本,每个版本同一个类,可能存在差异. 项目不同依赖应用,存在包名,类名完全一样的类. 第二种情况,往往是这个场景,本地 ...
- 在eclipse的Java类文件中,右上角出现大写字母A代表什么
代表这个文件(类)是一个抽象类abstract的第一个字母:
- CSS 学习笔记——CSS Selector
CSS1 中定义的选择器 类型选择器 用于选择指定类型的元素(其实他就是 html 标签选择器),常见用法如下: body { /*对 body 元素定义样式*/ } body,div { /*同时选 ...
- css自定义 range radio select的样式滑轮,按钮,选择框
写在前面: 之前踩坑css的时候,遇到滑轮,按钮,选择框这类型的东西,为了页面效果,总是需要自定义他们的样式,而不使用他们的默认样式.当时写的时候,我也是蛮头疼的,弄了个demo,链接在下面.对此做个 ...