假设我们的项目根目录是:my-flask-web
README.md文件(项目目录结构)
shell
my-flask-web/
├── app/
│ ├── __init__.py # Flask 应用工厂
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py # 用户模型
│ └── routes/
│ ├── __init__.py
│ ├── main.py # 主路由蓝图
│ └── api.py # API 蓝图
├── config.py # 配置文件
├── run.py # 启动文件
├── requirements.txt # Python 依赖
├── Dockerfile # Docker 镜像构建
├── docker-compose.yml # Docker 编排
├── .env.example # 环境变量示例
├── .gitignore # Git 忽略规则
├── .dockerignore # Docker 忽略规则
├── README.md # 项目说明
└── venv/ # 虚拟环境(已安装依赖)
一、创建flask必备文件
1.1 程序入口文件:./run.py
python
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
1.2 Flask 应用工厂:.app/__init__.py
python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name='default'):
"""应用工厂模式"""
app = Flask(__name__)
app.config.from_object(config[config_name])
# 初始化扩展
db.init_app(app)
# 注册蓝图
from app.routes.main import main_bp
from app.routes.api import api_bp
app.register_blueprint(main_bp)
app.register_blueprint(api_bp, url_prefix='/api')
# 创建数据库表
with app.app_context():
db.create_all()
return app
1.3 Flask配置文件:./config.py
python
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
"""基础配置"""
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key')
# MySQL 数据库配置
MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')
MYSQL_PORT = os.environ.get('MYSQL_PORT', 3306)
MYSQL_USER = os.environ.get('MYSQL_USER', 'root')
MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', 'your_password_data')
MYSQL_DATABASE = os.environ.get('MYSQL_DATABASE', 'flask_app')
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USER}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}"
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
"""开发环境配置"""
DEBUG = True
class ProductionConfig(Config):
"""生产环境配置"""
DEBUG = False
class TestingConfig(Config):
"""测试环境配置"""
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'testing': TestingConfig,
'default': DevelopmentConfig
}
1.4 用户模型./app/models/user.py
python
from app import db
from datetime import datetime
class User(db.Model):
"""用户模型"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
'id': self.id,
'username': self.username,
'email': self.email,
'created_at': self.created_at.isoformat() if self.created_at else None
}
def __repr__(self):
return f'<User {self.username}>'
1.5 模型聚合文件:./app/models/__init__.py
python
from app.models.user import User
__all__ = ['User']
1.6 主路由蓝图:./app/routes/main.py
python
from flask import Blueprint, jsonify
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def index():
"""首页"""
return jsonify({
'message': '欢迎使用 Flask 应用',
'status': 'success'
})
@main_bp.route('/health')
def health():
"""健康检查端点"""
return jsonify({
'status': 'healthy'
})
1.7 API 蓝图:./app/routes/api.py
python
from flask import Blueprint, jsonify, request
from app import db
from app.models import User
api_bp = Blueprint('api', __name__)
@api_bp.route('/users', methods=['GET'])
def get_users():
"""获取所有用户"""
users = User.query.all()
return jsonify({
'users': [user.to_dict() for user in users],
'count': len(users)
})
@api_bp.route('/users', methods=['POST'])
def create_user():
"""创建新用户"""
data = request.get_json()
if not data or not data.get('username') or not data.get('email'):
return jsonify({'error': '用户名和邮箱是必填项'}), 400
user = User(
username=data['username'],
email=data['email']
)
db.session.add(user)
db.session.commit()
return jsonify({
'message': '用户创建成功',
'user': user.to_dict()
}), 201
@api_bp.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
"""获取指定用户"""
user = User.query.get_or_404(user_id)
return jsonify({'user': user.to_dict()})
1.8 蓝图聚合文件:./app/routes/__init__.py
python
from app.routes.main import main_bp
from app.routes.api import api_bp
__all__ = ['main_bp', 'api_bp']
1.9 包管理文件:·./requirements.txt
txt
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
PyMySQL==1.1.0
cryptography==41.0.7
python-dotenv==1.0.0
二、创建docker必要文件
我们项目使用flask+mysql+vue多个容器,使用docker-compose.yml文件进行编排各容器的关系
2.1 编排多个容器文件:./docker-compose.yml
yml
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
environment:
- MYSQL_HOST=db
- MYSQL_PORT=3306
- MYSQL_USER=root
- MYSQL_PASSWORD=rootpassword
- MYSQL_DATABASE=flask_app
- SECRET_KEY=your_production_secret_key
depends_on:
db:
condition: service_healthy
networks:
- flask-network
volumes:
- .:/app
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=flask_app
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- flask-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 5s
retries: 10
networks:
flask-network:
driver: bridge
volumes:
mysql_data:
2.2 Docker 镜像构建文件:./Dockerfile
用来构建 Docker 镜像的配置文件。它定义了如何把你的应用打包成一个可移植的容器。
bash
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Expose port
EXPOSE 5000
# Run the application
CMD ["python", "run.py"]
2.3 docker过滤文件:./.dockerignore
作用是在构建 docker 镜像时排除不需要的文件,避免把垃圾文件打包进镜像。
bash
__pycache__/
*.py[cod]
*$py.class
venv/
env/
.venv/
.env
.git/
.gitignore
.idea/
.vscode/
*.log
.DS_Store
*.md
2.4 环境变量模板文件:./.env.example
ini
# 数据库配置
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=你的密码
MYSQL_DATABASE=flask_app
# Flask 配置
FLASK_APP=run.py
FLASK_ENV=development
SECRET_KEY=你的密钥