4. 项目初始化:用 Flask 搭骨架,配数据库,建 ORM 模型
好,咱们正式开始动手。上一章我们把需求理清了,这一章的目标很明确:让项目跑起来,能连上数据库,能操作数据表。
我个人习惯,做物联网项目时,先把基础设施夯实。你想想看,如果数据库连接配置错了,后面写再多业务代码也是白搭。所以这一章,咱们一步一个脚印来。
4.1 创建项目目录结构
先别急着写代码,把文件夹结构搭好。我见过不少新手,把所有文件都扔在根目录下,最后项目乱成一锅粥。
这是我推荐的结构,简洁且实用:
device_registry/
├── app.py # 应用入口
├── config.py # 配置文件
├── models.py # ORM 模型
├── requirements.txt # 依赖清单
└── venv/ # 虚拟环境(不提交到 Git)
嗯,这里要注意:venv 文件夹千万别提交到版本控制里。我吃过这个亏,有一次把虚拟环境整个推上去了,结果同事拉下来发现路径全不对,折腾了半天。
4.2 初始化 Flask 应用骨架
Flask 的初始化其实就几行代码。但我想强调一点:工厂模式。虽然小项目用简单模式也行,但为了后续扩展,我建议一开始就用工厂函数。
来看 app.py:
from flask import Flask
from config import Config
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
# 注册蓝图(后续章节会加)
# from routes import device_bp
# app.register_blueprint(device_bp)
return app
if __name__ == '__main__':
app = create_app()
app.run(debug=True, host='0.0.0.0', port=5000)
为什么用 create_app?说白了,就是为了测试方便。你写单元测试时,可以创建多个应用实例,互不干扰。我在做设备管理平台时,就因为一开始没用工厂模式,后来加测试时重构了一遍,那叫一个痛苦。
4.3 配置数据库连接
接下来是 config.py。这里我选 SQLite 做演示,因为零配置,上手快。生产环境你换成 MySQL 或 PostgreSQL 就行,改个连接字符串的事。
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///device_registry.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
这里有个坑:SQLALCHEMY_TRACK_MODIFICATIONS 一定要设为 False。为什么?因为 Flask-SQLAlchemy 的信号机制会消耗大量内存,而且你基本用不上。我曾经在一个项目中忘了关,结果内存占用飙到 2GB,查了半天才发现是这玩意儿在作祟。
config.py 里,然后提交到了公开仓库……嗯,后果你懂的。
4.4 初始化 ORM 模型
ORM 模型是咱们和设备身份打交道的桥梁。先安装依赖:
# requirements.txt
Flask==2.3.3
Flask-SQLAlchemy==3.1.1
然后初始化数据库对象。在 models.py 里:
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class DeviceIdentity(db.Model):
__tablename__ = 'device_identity'
id = db.Column(db.Integer, primary_key=True)
device_id = db.Column(db.String(64), unique=True, nullable=False, index=True)
device_secret = db.Column(db.String(128), nullable=False)
status = db.Column(db.String(16), default='active') # active / revoked
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self):
return {
'id': self.id,
'device_id': self.device_id,
'status': self.status,
'created_at': self.created_at.isoformat(),
'updated_at': self.updated_at.isoformat()
}
这个模型就是咱们设备身份注册系统的核心。每个字段都有它的用途:
| 字段名 | 类型 | 说明 |
|---|---|---|
id |
Integer (PK) | 自增主键,内部使用 |
device_id |
String(64) | 设备唯一标识,对外暴露,加索引 |
device_secret |
String(128) | 设备密钥,哈希存储,绝不存明文 |
status |
String(16) | 状态:active 正常,revoked 吊销 |
created_at |
DateTime | 创建时间,自动填充 |
updated_at |
DateTime | 更新时间,自动更新 |
device_secret 字段长度设 128 位,是因为后续我们会用 SHA-256 哈希,输出正好 64 字节,十六进制表示就是 128 个字符。别设短了,否则存不下。
4.5 整合:让 Flask 认识数据库
现在要把 db 对象注册到 Flask 应用里。修改 app.py:
from flask import Flask
from config import Config
from models import db
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
# 创建所有表(开发环境用,生产环境建议用迁移工具)
with app.app_context():
db.create_all()
return app
这里我用了 db.create_all(),它会在第一次运行时自动建表。但注意:这只是开发阶段的快捷方式。生产环境我强烈建议用 Flask-Migrate 做数据库迁移,否则改模型时你会哭的。
我曾经在项目上线后,需要给表加个字段,结果直接删表重建,把线上数据全丢了……嗯,从那以后我再也不敢在生产环境用 create_all 了。
4.6 验证:跑起来看看
启动应用:
python app.py
如果看到 Running on http://0.0.0.0:5000,说明骨架搭好了。再检查一下数据库文件:
ls -la instance/device_registry.db
有文件生成,说明数据库连接和建表都成功了。你可以用 SQLite 客户端看一眼:
sqlite3 instance/device_registry.db
.tables
.schema device_identity
应该能看到 device_identity 表,字段和咱们定义的一致。
4.7 本章知识体系总览
下面这张图,把咱们这一章做的事串起来了:
4.8 本章小结
这一章我们做了三件事:
- 用 Flask 搭好了项目骨架,采用工厂模式
- 配置了数据库连接,用环境变量管理敏感信息
- 定义了
DeviceIdentityORM 模型,并成功建表