当前位置: 首页 > news >正文

Flask 项目结构

前面我们了解了 Flask 框架的特性和一些用法,比如创建一个简单应用、做些页面,以及增加鉴权模块等,如果要将 Flask 用于实际项目开发,还需要了解一下 Flask 项目结构。

Flask 是一个轻量级的 Web 框架,扩展性强,灵活性高,容易上手,不过 Flask 没有给出明确的项目结构,而是让开发者根据实际需求,创建适合自己的项目结构。对于初学者来说,面临的困难可能是不知道如何组织代码,特别是在看一些别人的代码时,弄不清结构,对理解和学习造成一定障碍。

需要说明的是今天所介绍的结构并不是最好的,不同的项目,不同的团队,不同的理念,会有不同的结构,今天介绍的只是一个参考。

我们就那之前的 Flask数据持久化 章节的练习作为实践。

按功能组织

按功能,指的是将 Web 项目的不同职能划分开,比如路由部分、模型部分、业务逻辑部分等

目录结构

project/  forms/    myform.py    ...  models/    __init__.py    profile.py    user.py    ...  routes/    __init__.py    home.py    profile.py    ...  static/    ...  services/    __init__.py    ...  templates/    createprofile.html    profile.html    ...  __init__.py  config.py

可以看到,项目根目录下,分为:

  • forms(表单):存放表单对象

  • models(模型):存放数据模型,即库表在程序中的映射对象,以及对象之间的关系

  • routes(路由):存放请求路由以及处理逻辑

  • static(静态文件):Flask 约定存放静态文件的目录

  • templates(模板):Flask 约定存放页面模板的目录

  • services(服务):存放业务逻辑或者其他服务类功能

  • __init__.py:Flask app 初始化方法

  • config.py:项目配置文件

这样的分类,相当于将之前写到一个代码文件(app.py)中的逻辑,按功能划分开,当项目逐渐变大变复杂后,这样的划分有助于开发和维护

初始化

按功能划分开,比较容易理解,不过将分开的部分有机结合起来是个问题, 推荐的方式是,在每个目录下创建一个 __init__.py 文件,有两个作用:

  1. 将目录变为包(package),方便其他地方引入

  2. 做些初始化工作,例如将目录下的内容统一起来,提供一站式装载

初始化模型

数据模型放在 models 目录下,一般数据模块需要和数据库交互,另外每个模型需要有个数据库实例,来创建模型以及字段定义

首先,创建目录的 __init__.py 代码文件:​​​​​​​

from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()def init_app(app):    db.init_app(app)    return db
  • 使用之前了解过的 Sqlalchemy 库,做数据映射(ORM)框架

  • 定义一个数据库对象 db,注意构造方法没有传递 app 参数,是因为此时还得到 app

  • 定义一个 init_app 函数,接收一个参数 app,就是 Flask app,用 db.init_app 方法初始化 Flask app

模型代码示例 project/models/profile.py :​​​​​​​

from . import dbclass Profile(db.Model):    id = db.Column(db.Integer, primary_key=True)    name = db.Column(db.String(20))    birthday = db.Column(db.Date())    createtime = db.Column(db.DateTime())    about = db.Column(db.Text())
  • 因为是在 models 目录下的代码文件,所以通过当前目录引入在 __init__.py 中定义的 db,用来定义数据模型及其字段

  • 字段在前面的数据持久化中有详细说明,这里省略解释

初始化路由

当路由处理代码被分开之后,在主程序代码中初始化会变得比较麻烦,幸好 Flask 有个 blueprint(蓝图)的概念,能很好的将分离出来的代码管理起来,确切的说 blueprint 的作用不止于此,这里只是需要用到它的部分功能

Web 项目被分成多个部分之后,每个部分可以单独成为一个子应用,blueprint 的作用就是可以让子应用的编写方式用在主应用中一样,比如注册路由,处理请求等,使用前,先创建一个 blueprint 实例,然后再将实例注册到 Flask app 实例中就好了。

路由处理定义示例,project/routes/home.py:​​​​​​​

from flask import Blueprinthome_bp = Blueprint('home_bp', __name__)@home_bp.route('/', methods=['GET', 'POST'])def index():    return "Hello World!", 200
  • 引入 Flask 的 blueprint 模块

  • 初始化 blueprint 实例的实例 home_bp,第一个参数是 终端点(endpoint) 的名称,用在 url_for 方法中,第二个参数是作为模块被引入时候的名称

  • 使用和 blueprint 实例同名的装饰器定义路由,代替了之前 @app.route 的方式,相当于 blueprint 实例是一个 Flask app 实例

  • 视图函数的定义之前 Flask app 实例中的没有区别,这里只是简单的返回文字和状态

再看看路由模块的初始化,routes/__init__.py:​​​​​​​

from .home import home_bpfrom .profile import profile_bpdef init_app(app):    app.register_blueprint(home_bp)    app.register_blueprint(profile_bp)
  • 从当前目录下引入具体路由文件,从中引入 blueprint 实例

  • 定义初始化方法,参数就是 Flask app 实例,用 register_blueprint 方法将 blueprint 注册到 Flask app 实例中

Flask app 工厂方法

在之前的介绍中,在 app.py 中编写所有的东西,并且通过 app.run() 来启动应用,在实际项目中,推荐用 app 工厂方法的方式来启动,好处是:

  1. 便于测试,可以在不同的测试用例中创建特别的 app 实体

  2. 多实例运行,如果需要一个应用的多个版本,可以在一个应用进程中运行多个实例,而不必部署多个 Web 服务器(将在 Flask 部署中介绍)

创建 Flask app 写在 project/__init__.py 中:​​​​​​​

from flask import Flaskfrom .config import configfrom . import models, routesdef create_app(config_name='default'):    app = Flask(__name__)    app.config.from_object(config[config_name])    config[config_name].init_app(app)    models.init_app(app)    routes.init_app(app)    return app
  • 引入 flask 库

  • 从当前目录下引入配置文件

  • 引入上面定义的模型模块和路由模块

  • 定义工厂方法,默认方法名是 create_app,如果其他名称,需要在启动应用时指定(随后介绍),工厂方法有个参数,用来指定需要加载的配置内容,且设定了默认值(随后介绍)

  • 工厂方法中,先创建 Flask app 实例,然后加载配置,最后为模块初始化 模型和路由

  • 最后返回 Flask app 实例,方便测试和应用启动时的调用

工厂方法比单个文件写法更清爽,修改起来也更简单,另外这样定义还可以避免循环依赖问题,

循环依赖:如果在工厂方法中直接定义数据库模块 db,在模型中需要引用 db,而工厂方法又需要用模型来初始化 Flask app,就会引起循环依赖问题

启动项目

通过工厂方法创建的应用,因为没有明确的 app.run() 调用,不能直接像在前一样直接运行文件,而是要用 flask 命令行方式来启动

正常启动

启动之前,需要先设置 FLASK_APP 环境变量,指定需要运行的 Flask 项目, 值为项目文件夹名,即项目名:

  • Linux 或者 Mac

export FLASK_APP=project
  • Windows 命令行

set FLASK_APP=project
  • Powershell

$env:FLASK_APP="project"

然后在项目目录的上一层目录下执行命令,启动项目:

flask run

如果一切正常,就可以看到类似的结果:​​​​​​​

 * Serving Flask app "project" * Environment: production   WARNING: Do not use the development server in a production environment.   Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

设置启动参数

前面工厂方法可以定义一些参数,如何来指定呢?其中一种方法是设置环境变量 FLASK_APP,例如将 congfig_name 参数设置为 testing:

  • Linux 或者 Mac

export FLASK_APP=project:create_app('testing')
  • Windows 命令行

set FLASK_APP=project:create_app('testing')
  • powershell

$env:FLASK_APP="project:create_app('testing')"
  • project 是 Flask app 所在的模块名,与上面直接写 project 一样

  • 冒号(:)后即为工厂方法的名,并且将参数带入

您可能已经想到,这种方式可以解决工厂方法名不是默认 create_app 的情况了,例如工厂方法名为 myapp_factory,以 Linux 环境为例:

export FLASK_APP=project:myapp_factory()

按业务组织

一个大型项目中,会包含很多子业务,比如人员管理、订单管理、统计报表等等,每一部分都可以是独立的项目,在 Flask 中,按照业务的方式将文件划分开,就是按业务方式来组织项目结构,这样的组织方式有助于并行开发和分而治之。

大体的结构是:​​​​​​​

project/  __init__.py  config.py  db.py  auth/    __init__.py    route.py    models.py    templates/  blog/    __init__.py    route.py    models.py    templates/  ...
  • 项目结构中,__init__.py 和 config.py 是整个应用的

  • auth、blog 目录是子业务,可以看到每个内部有自己的路由、模型和模板文件夹

  • db.py 是数据库连接模块,为各个子业务提供统一的数据库连接和模型支持,因为是单独的数据库模块,所以不会出现前面说的循环依赖问题,需要使用数据库模块的地方直接导入就行。

按业务组织方式中,每个子业务都是以 blueprint 的方式注册到 Flask app 上的,在按功能组织的方式中,我们只将路由用 blueprint 注册了,其实可以将 blueprint 看成一个独立的 Flask app,不过不用真的去部署,只需要注册到真正的 Flask app 上就行。

项目配置

之前的练习中都是将配置写到 app.py 中的,只是为了方便练习。实际项目中,配置是很重要的部分,系统研发过程中,需要经历不同的环境,比如开发环境,测试环境和生产环境,如果配置错了,开发环境连接上了生产环境的数据库,那可就糟糕了,相反开发环境为了方便查错,往往开启了 Debug 模式,如果放在生产环境中将会带来很大的性能损耗。

Python 中提供了丰富的配置处理方式,今天就 Flask 的配置利用实例简单介绍下,不过介绍的不见得就是最好的,只是一种解决思路,大家可以根据具体项目有所调整。

看一下代码:​​​​​​​

import osbasedir = os.path.abspath(os.path.dirname(__file__))class Config:    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'    SQLALCHEMY_COMMIT_ON_TEARDOWN = True    @staticmethod    def init_app(app):        passclass DevelopmentConfig(Config):    DEBUG = True    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-dev.db')class TestingConfig(Config):    TESTING = True    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data-test.db')class ProductionConfig(Config):    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'data.db')config = {    'development': DevelopmentConfig,    'testing': TestingConfig,    'production': ProductionConfig,    'default': DevelopmentConfig}
  • 实例项目中使用的数据库是 Sqlite,需要指定数据库文件目录,所以在定义了统一的目录 basedir,获取的是项目所在文件夹目录,因为 config.py 就在项目根目录中

  • 定义了 Config 基类,用类属性设置了 Flask app 的一些配置,其中 init_app 是为了在初始化 app 是附加一些额外配置用的

  • 定义了三个不同场景下的配置子类,分别是开发环境、测试环境和生产环境,大同小异,特别需要注意的是数据库文件名称,不同的场景有不同的名称

  • 将不同的配置放在一个词典(dict)中,在 Flask app 工厂方法中,通过参数来选择具体的配置类,为了严谨,还设置的默认配置,显然默认为开发环境是很好的选择

有必要说明的是,Flask app 有多种设置配置的方式,常用的如:

  • 属性指定,如 app.config["MYCONFIG"] = "xxxx"

  • 对象获取,如 app.config.from_object(configObj)

  • 配置文件,app.config.from_pyfile(pyfilepath)

  • JSON,app.config.from_json(jsonfilename)

总结

今天介绍了一个简单的 Flask 项目化结构,并利用之前做过的数据持久化的练习,做了项目化后的代码说明,并且说明了按功能和按业务两种项目组织方式,最后介绍了 Flask 项目中配置的方式。总之 Flask 是一个宽松的,简单的 Web 框架,每个人都可打造自己的一套项目构建方式,不过对于刚开始接触的同学,或者为了交流方便,还是有必要了解一下一般的组织方式,希望对您有所启发。

最后,示例代码中提供了较为完整的例子,其中还有如何自定义数据库初始化命令的例子,请您参考。

相关文章:

Flask 项目结构

前面我们了解了 Flask 框架的特性和一些用法,比如创建一个简单应用、做些页面,以及增加鉴权模块等,如果要将 Flask 用于实际项目开发,还需要了解一下 Flask 项目结构。 Flask 是一个轻量级的 Web 框架,扩展性强&#…...

云计算在IT领域的发展和应用

文章目录 云计算的发展历程云计算的核心概念云计算在IT领域的应用1. 基础设施即服务(IaaS):2. 平台即服务(PaaS):3. 软件即服务(SaaS): 云计算的拓展应用结论 &#x1f3…...

8年测试经验之谈 —— 接口自动化测试requests

1.什么是requests? requests是一个Python第三方库,处理URL资源特别方便 2.安装requests pip3 install requests 如果遇到Permission denied安装失败,请加上sudo重试 3.使用requests 3.1get请求方法 3.1.1基本的get请求 import reques…...

求助:vue从后端获取数据,如何对获得的数据进行拆分?

从后端获取数据格式如下: { "count": 3, "lists": [ { "id": 2, "name_id": 4, "name": "4: 2201030019: 张四", }, { …...

html5拖拽文件上传需阻止默认事件

至少阻止下列3个事件的默认行为才能实现文件拖拽上传 var bdocument.getElementById(box) b.ondragenter(e)>{e.preventDefault()console.log(aaa,e.dataTransfer.files); } b.ondragover(e)>{e.preventDefault()console.log(bb,e.dataTransfer.files); }b.ondrop(e)>…...

深入剖析Kubernetes之Pod基本概念(一)

文章目录 Pod 中重要字段Pod 的生命周期 Pod,而不是容器,才是 Kubernetes 项目中的最小编排单位。将这个设计落实到 API 对象上,容器(Container)就成了 Pod 属性里的一个普通的字段。那么,到底哪些属性属于…...

idea 对JavaScript进行debug调试

文章目录 1.新增 JavaScript Debug 配置2.配置访问地址3.访问url. 打断点测试 前言 : 工作中接手别人的前端代码没有注释,看浏览器的network或者console切来切去,很麻烦,可以试试idea自带的javscript debug功能。 1.新增 JavaScript Debug 配…...

npm init

1、什么是npm init npm是开源 JavaScript 包管理器,允许 JavaScript 开发人员分享和重用代码。npm init是一种在创建新的npm包时使用的命令,它将提示你填写一些信息以便在package.json文件中创建初始配置。 2、为什么要使用npm init初始化项目 在node…...

微信小程序开发教学系列(6)- 数据缓存与本地存储

第六章 数据缓存与本地存储 在开发微信小程序时,我们通常会面临一个问题:如何在不重复请求接口的情况下,将数据保存在本地,提高用户体验并减少网络请求的次数。这就需要我们学会使用数据缓存和本地存储的技巧。本章将介绍在微信小…...

跟我学c++中级篇——模板的基础术语说明

一、类模板术语 1、模板的特化 模板的特化也叫具体化&#xff0c;非常容易理解&#xff0c;就是把模板中的模板参数给定具体的类型。看下面的例子&#xff1a; //模板 template <typename T,typname N> class Data {}; //特化 template<> class Data<int,int&…...

最新Win10离线安装.NET Framework 3.5的方法(附离线包2022/3/22)

win10系统安装软件时&#xff0c;可能需要.net framework3.5的运行环境&#xff0c;当我们安装某些软件的时候会提示“你的电脑上的应用需要使用以下Windows功能:.NET Framework 3.5(包括.NET 2.0和3.0)。如果系统默认的是4.0以上的版本&#xff0c;当软件需要.net framework3.…...

最新docker多系统安装技术

在Ubuntu操作系统中安装Docker 在Ubuntu操作系统中安装Docker的步骤如下。 1&#xff0e;卸载旧版本Docker 卸载旧版本Docker的命令如下&#xff1a; $ sudo apt-get remove docker docker-engine docker.io 2&#xff0e;使用脚本自动安装 在测试或开发环境中&#xff0…...

系统架构设计高级技能 · 云原生架构设计理论与实践

系列文章目录 系统架构设计高级技能 软件架构概念、架构风格、ABSD、架构复用、DSSA&#xff08;一&#xff09;【系统架构设计师】 系统架构设计高级技能 系统质量属性与架构评估&#xff08;二&#xff09;【系统架构设计师】 系统架构设计高级技能 软件可靠性分析与设计…...

Springboot集成RocketMQ——简单使用

目录 1.MQ选型 2.RocketMQ基本架构 3.Springboot集成RocketMQ 4.顺序消息 5.延时消息 6.事务消息 1.MQ选型 目前市面上的MQ选型&#xff1a;主要分为3个类型 Kafka&#xff1a;吞吐量大&#xff0c;且性能好&#xff0c;集群高可用&#xff1b;会丢失数据&#xff0c;功…...

第一百二十四回 Flexible组件

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了扩展内容相关的知识&#xff0c;本章回中将介绍 Flexible组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在前面章回中介绍了扩展列表相关的内容&#xff0c;当页面中其它组件和扩展列表一起使…...

关于stm32推挽带有上下拉电阻的思考、IO口驱动能力是什么

1、发现推挽带有上下拉电阻 1.1、stm32手册 记忆中推挽是不需要上下拉的&#xff0c;没关注过&#xff0c;但是我真的理解上下拉吗&#xff0c;下图来自stm32f4的中文版和英文版的数据手册&#xff0c;没有翻译错&#xff0c;就是“推挽带有上下拉的能力”。 1.2、查找相关信…...

考研408 | 【操作系统】 内存管理

内存的基础 内存和内存的作用&#xff1a; 几个常用的数量单位&#xff1a; 指令的工作原理&#xff1a; 问题&#xff1a;如何将指令中的逻辑地址转换为物理地址&#xff1f; 解决办法&#xff1a;装入的三种方式 1.绝对装入 2.可重定位装入 3.动态重定位 从写程序到程…...

C# 工厂模式

一、概述 工厂模式&#xff08;Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。在C#中&#xff0c;工厂模式通过定义一个公共接口或抽象类来创建对象&#xff0c;而具体的对象创建则由工厂类来实现。 工厂模式主要包含三个角色…...

在云服务器上安装Jenkins

说明&#xff1a;Jenkins是一个部署项目的平台&#xff0c;通过Jenkins可以省去从项目开发–>部署项目之间的所有流程&#xff0c;做到代码提交即上线。本文介绍在云服务CentOS上安装Jenkins。 前提 安装Jenkins之前&#xff0c;先要在云服务上安装JDK、Maven、Git&#x…...

一文了解SpringBoot中的IOC

目录 1.什么是IOC 2.IOC容器 3.创建IOC容器 4.装配Bean到IOC容器 5.依赖注入 1.什么是IOC IOC&#xff1a;Inversion of Control 控制反转 Sping中我们把一个个对象称为Bean&#xff0c;以前我们实例一个对象的时候&#xff0c;都会直接New一个 而在Spring中&#xff0…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

tomcat入门

1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效&#xff0c;稳定&#xff0c;易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...