大学期间选择的是web方向,主要学习的也是前后端,也是经典vue+spingboot,python基本没有怎么学,现在因为导师那边一个项目,然后叫我们跟着师兄师姐他们做一点,所以不得以得学一下python这边的后端框架flask了,话不多说,开始今天的学习了。
1、准备工作
工欲善其事必先利器,准备好环境以及开发工具不用多说。python环境肯定得有,而且建议python版本在3.9以上,如果python版本比较低,可以先去官网下载较新的版本。然后我选择的开发工具pycharm,vscode也是可以的,pycharm建议还是用专业版,社区版连创建flask项目都没有,都得手动配置,有点难受。有了python环境,大家就可以全局安装flask了,我是小白,所以选择全局,python里还有虚拟容器啥的,我嫌弃麻烦,就没有学了(偷个懒,哈哈)。
直接在windows控制台输入下列命令:
pip install Flask
然后就是打开pycharm,创建一个flask项目,这里建议选择第二个选项,Existing interpreter,就是已经存在的解释器,这样不用每次都要配。

如果大家安装了多个python版本,注意,在pycharm配置的解释器用你全局配置的版本所在的文件夹,我刚开始就因为这个pycharm选择配置的解释器和电脑全局使用的默认解释器不一样,导致我傻乎乎的全局安装了一些包,但是在pycharm里面却死活找不到包,一引用就报错,真被自己蠢哭了,我这里就再补充一下,先用命令看一下自己的使用python的路径:
py -0p

创建好项目后,就会得到一个默认的项目框架,如下:

之后我介绍我学习的项目架构与这个又不一样,但是我感觉大致是一样的,然后我们可以设置一下配置信息,点击那个小辣椒(hh)有一个配置选项,打开后可以手动设置debug模式,这个模式是什么呢,就是我们在修改了一部分代码后,不需要重启项目,直接保存文件后,刷新一下就可以看结果了,然后可以使用—host=xxxx设置主机号,–port=xxxx设置端口号,如下所示:

到这里基本准备工作就结束了,点击运行就可以看到简单结果了,我这里就不展示了,下面着重记录我自己学的项目结构体系,以及我的理解。
2、企业开发常用项目结构介绍
在AI的辅助下,我快速搭建起了一个企业开发中常用的项目结构,我学习的是前后端分离式的,就是后端单纯搞后端,不放前端代码。项目结构如下所示:
flask_projects/ # 项目根目录
├── app/ # 应用主目录
│ ├── init.py # 应用工厂文件
│ ├── extensions.py # Flask扩展实例文件
│ ├── api/ # API蓝图目录
│ │ ├── init.py # API蓝图初始化
│ │ └── routes.py # 路由定义文件
│ ├── models/ # 数据模型目录
│ │ ├── init.py
│ │ ├── user.py # 用户模型
│ │ └── book.py # 图书模型
│ ├── services/ # 业务逻辑目录
│ │ ├── init.py
│ │ ├── user_service.py # 用户相关业务逻辑
│ │ └── book_service.py # 图书相关业务逻辑
│ ├── static/ # 静态文件目录
│ └── templates/ # 模板文件目录
├── config/ # 配置文件目录
│ ├── init.py # 配置加载逻辑
│ ├── development.py # 开发环境配置
│ └── production.py # 生产环境配置
└── run.py # 应用启动文件
2.1 项目根目录
项目根目录总run.py是应用程序的入口文件,也就是我们用户启动flask应用,而requirements.txt是用于记录flask的项目依赖,那他具体有什么用呢——当别人丢给你一个flask项目,那你想要跑起来,是不是要有环境,requirements.txt这个文件就是记录你想要运行这个项目需要下载的依赖。咱们拿到项目后,第一步就是执行下列命令,安装项目依赖:
pip install -r requirements.txt
那又有问题了,我们要怎样将项目所需的依赖写入这个文件中呢,只需要执行下列命令:
pip freeze > requirements.txt

2.2 app目录
app目录是flask的核心应用目录,里面主要包括了api目录,models目录、services目录、static目录,还有初始化应用文件和扩展文件:

2.2.1 app下的初始化文件__init__.py
先讲讲__init__.py文件,可能就有同学问为啥这个文件这样取名字呢,额,我只能说可能就是一种规定,就是说如果你文件命名为这个文件,flask就会自动扫描到这个文件作为初始化文件,这也是为什么在run.py中,可以直接引入然后创建实例:
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
然后我们具体来看一下初始化文件__init__.py中干了什么事
from flask import Flask
from config import config_by_name
from app.extensions import db, cors
def create_app(config_name='development'):
app = Flask(__name__)
# 加载配置
app.config.from_object(config_by_name[config_name])
# 初始化扩展
db.init_app(app)
cors.init_app(app, supports_credentials=True)
# 注册蓝图
from app.api import api_bp
app.register_blueprint(api_bp, url_prefix='/api')
return app
加载配置就是将数据库的配置项加载进来,实际开发中会有开发环境和部署环境
class DevelopmentConfig:
DEBUG = True
TESTING = False
# 数据库配置
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://prod_user:prod_password@prod_host/flask_prod"
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 密钥配置
SECRET_KEY = 'dev_secret_key'
# 其他开发环境特定配置
CORS_HEADERS = 'Content-Type'
class ProductionConfig:
DEBUG = False
TESTING = False
# 数据库配置
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://prod_user:prod_password@prod_host/flask_prod'
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 密钥配置
SECRET_KEY = 'your_production_secret_key' # 在实际部署时应该使用环境变量
# 其他生产环境特定配置
CORS_HEADERS = 'Content-Type'
初始化扩展,这里就是将数据库实例对象导入,然后配置跨域问题,什么是跨域呢跨域是指在浏览器中,一个域下的文档或脚本试图请求另一个域下的资源时,域名、协议或端口不同,浏览器会出于安全考虑,限制跨源HTTP请求,这种安全策略被称为同源策略。实际一点来讲,就是如果你前后端若没有配置,前后端就无法正常对接。要么前端配置,要么后端配置。
注册蓝图又是什么呢?我第一次接触也是不知道啥意思,直白来说,蓝图就像是一个小型的应用程序,它允许你将相关的视图、模板和静态文件组织在一起。想象成一个大型商场:
- 商场就是你的 Flask 应用
- 不同的楼层(服装区、美食区、电器区)就是不同的蓝图
- 每个区域都有自己的管理方式,但都属于同一个商场
例如在我们的代码中:
Apply to production.p…
# app/api/__init__.py
from flask import Blueprint
api_bp = Blueprint(‘api’, __name__) # 创建一个名为’api’的蓝图
python
Apply to production.p…
# app/__init__.py
app.register_blueprint(api_bp, url_prefix=’/api’) # 注册蓝图,并设置URL前缀
这样做的好处是:
可以轻松添加新的功能模块(比如后面添加 admin 蓝图:/admin/…)
所有 API 相关的路由都以 /api 开头
代码更容易维护,因为相关功能都组织在一起
2.2.2 扩展文件extensions.py
扩展,我个人感觉就和vscode中的扩展一样,可以很方便的使用别人封装好的功能,这里同样也是,实现跨域啊,数据库操作啊,都可以使用扩展文件,我们只要下载好了python包,在扩展里导入,调用创建好实例就好,之后就可以在其他文件中导入这些实例实现相对应的扩展功能。
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
# 创建扩展实例
db = SQLAlchemy()
cors = CORS()
2.2.3 app下的api文件夹
这里显然是用于写实际路由api接口的,我觉得后端其实都很像,我学过Express.js,Spring Boot,现在的flask,我觉得他们都是很相似的,我觉得如果你有一个后端框架的基础,上手会很快的。api文件夹核心也就两个文件,一个是暴露出去的init文件,一个就是路由配置文件了,刚才我们在app下总的__init__.py中看到导入了api的api_bp,这个实例就是来自api文件夹下的__int__.py了
from flask import Blueprint
api_bp = Blueprint('api', __name__)
from app.api import routes
然后我们重点来看一下rotues.py里的代码:
from flask import request, jsonify
from app.api import api_bp
from app.services.user_service import UserService
from app.services.book_service import BookService
@api_bp.route('/')
def hello_world():
return 'Hello!'
@api_bp.route("/home")
def get_home():
return '这是home主页'
@api_bp.route("/blog/<int:blog_id>")
def blog_detail(blog_id):
return "当前页面是 %d" % blog_id
@api_bp.route("/book/list")
def book_list():
page = request.args.get("page", default=1, type=int)
return f"您获取的是第{page}页"
@api_bp.route('/user/selectAll', methods=['GET'])
def get_all_users():
result = UserService.get_all_users()
return jsonify(result), result['code']
@api_bp.route('/user/<int:user_id>', methods=['GET'])
def get_user(user_id):
result = UserService.get_user_by_id(user_id)
return jsonify(result), result['code']
@api_bp.route('/user/adduser', methods=['POST'])
def create_user():
user_data = request.get_json()
result = UserService.create_user(user_data)
return jsonify(result), result['code']
@api_bp.route('/user/<int:user_id>', methods=['PUT'])
def update_user(user_id):
user_data = request.get_json()
result = UserService.update_user(user_id, user_data)
return jsonify(result), result['code']
@api_bp.route('/user/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
result = UserService.delete_user(user_id)
return jsonify(result), result['code']
# 图书相关路由
@api_bp.route('/book/list', methods=['GET'])
def get_all_books():
result = BookService.get_all_books()
return jsonify(result), result['code']
@api_bp.route('/book/<int:book_id>', methods=['GET'])
def get_book(book_id):
result = BookService.get_book_by_id(book_id)
return jsonify(result), result['code']
@api_bp.route('/book/add', methods=['POST'])
def create_book():
book_data = request.get_json()
result = BookService.create_book(book_data)
return jsonify(result), result['code']
@api_bp.route('/book/<int:book_id>', methods=['PUT'])
def update_book(book_id):
book_data = request.get_json()
result = BookService.update_book(book_id, book_data)
return jsonify(result), result['code']
@api_bp.route('/book/<int:book_id>', methods=['DELETE'])
def delete_book(book_id):
result = BookService.delete_book(book_id)
return jsonify(result), result['code']
这一眼看过去,就基本同其他后端框架一样,这里写路由,然后我们还需要一个实现类去实现实际的增删改查,这里只负责调用实现方法,然后以正确的结果返回,这里可以配置路由的请求类型,是get啊,还是post,还是put,还是delete,需要什么参数等等。
2.2.4 models文件夹
app下的models文件夹是数据模型目录,这些数据模型是和数据库中的表一一对应的,比如在我这个项目中,目前有用户表和图书表,那么在models中就有两个对应的数据模型:
用户模型:
from app.extensions import db
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
def to_dict(self):
return {
'id': self.id,
'username': self.username,
# 出于安全考虑,不返回密码
}
图书模型:
from app.extensions import db
class Book(db.Model):
__tablename__ = 'book'
id = db.Column(db.Integer, primary_key=True)
book_name = db.Column(db.String(100), nullable=False)
price = db.Column(db.Float, nullable=False)
count = db.Column(db.Integer, nullable=False)
def to_dict(self):
return {
'id': self.id,
'book_name': self.book_name,
'price': self.price,
'count': self.count
}
2.2.5 services文件夹
app下的services文件夹是用于业务逻辑处理,我觉得和springboot中的service层一样,以及和Express中的router_handler一样,都是路由接口的实际处理逻辑,操作数据库这些操作都是在这实现的,话不多说,大家可以看一下下面的代码就知道了,我这里同样有两个py文件,一个是用户的业务处理逻辑,另一个是图书的业务处理逻辑,我这里就以用户的为例:

from app.models.user import User, db
class UserService:
@staticmethod
def get_all_users():
try:
users = User.query.all()
return {'code': 200, 'data': [user.to_dict() for user in users], 'message': '获取用户列表成功'}
except Exception as e:
return {'code': 500, 'message': f'获取用户列表失败: {str(e)}'}
@staticmethod
def get_user_by_id(user_id):
try:
user = User.query.get(user_id)
if user:
return {'code': 200, 'data': user.to_dict(), 'message': '获取用户信息成功'}
return {'code': 404, 'message': '用户不存在'}
except Exception as e:
return {'code': 500, 'message': f'获取用户信息失败: {str(e)}'}
@staticmethod
def create_user(user_data):
try:
# 检查用户名是否已存在
if User.query.filter_by(username=user_data['username']).first():
return {'code': 400, 'message': '用户名已存在'}
new_user = User(
username=user_data['username'],
password=user_data['password'] # 实际项目中应该对密码进行加密
)
db.session.add(new_user)
db.session.commit()
return {'code': 200, 'data': new_user.to_dict(), 'message': '创建用户成功'}
except Exception as e:
db.session.rollback()
return {'code': 500, 'message': f'创建用户失败: {str(e)}'}
@staticmethod
def update_user(user_id, user_data):
try:
user = User.query.get(user_id)
if not user:
return {'code': 404, 'message': '用户不存在'}
# 如果要更新用户名,检查新用户名是否与其他用户冲突
if 'username' in user_data and user_data['username'] != user.username:
if User.query.filter_by(username=user_data['username']).first():
return {'code': 400, 'message': '用户名已存在'}
user.username = user_data['username']
if 'password' in user_data:
user.password = user_data['password'] # 实际项目中应该对密码进行加密
db.session.commit()
return {'code': 200, 'data': user.to_dict(), 'message': '更新用户信息成功'}
except Exception as e:
db.session.rollback()
return {'code': 500, 'message': f'更新用户信息失败: {str(e)}'}
@staticmethod
def delete_user(user_id):
try:
user = User.query.get(user_id)
if not user:
return {'code': 404, 'message': '用户不存在'}
db.session.delete(user)
db.session.commit()
return {'code': 200, 'message': '删除用户成功'}
except Exception as e:
db.session.rollback()
return {'code': 500, 'message': f'删除用户失败: {str(e)}'}
2.2.5 static文件夹
这个文件夹一看名字就知道是用于存放用户上传的一些静态文件,图片,视频这些,不用多说了。
2.3 config文件夹

config文件夹其实上面已经涉及到了,数据库连接的代码这些的基本配置都在这里,然后跨域的配置啊以及一些其他的,我这个项目也是比较简单的结构,也就没有很多配置,代码这里就不贴了,上面已经贴了。
3、总结
到此为之,一个简单的flask项目的结构就介绍的差不多了,我觉得对于有后端开发基础的同学,上手还是不是很难的,我这里也是简单记录一下我的学习过程。每天进步一点点!
欢迎参观我的个人博客https://blog.heartwarming.online/








