1. 项目概述
这个停车位租赁平台项目是我最近完成的一个实战案例,采用Python Flask作为后端框架,搭配微信小程序前端。核心目标是解决城市停车难问题,让私家车位主可以出租闲置车位,同时为车主提供便捷的停车位查找和预约服务。
整个系统包含三个主要模块:微信小程序前端用户界面、Flask后端API服务、MySQL数据库存储。开发周期约8周,从需求分析到最终部署上线。下面我会详细拆解每个环节的实现细节和踩过的坑,希望能给想做类似项目的朋友一些参考。
提示:实际开发中微信支付接口和地图API的接入需要企业资质,个人开发者可以先使用模拟数据测试核心功能。
2. 技术选型与架构设计
2.1 为什么选择Flask+微信小程序
选择Flask作为后端主要基于以下考虑:
- 轻量灵活:相比Django,Flask更适合中小型API服务开发,没有太多预设约束
- 快速开发:用
flask-restful扩展可以快速构建RESTful API - Python生态:直接使用
SQLAlchemy做ORM,JWT做认证都很方便
微信小程序前端的选择理由:
- 免安装:用户无需下载APP,扫码即用
- 生态完善:自带用户体系、支付、地图等能力
- 开发友好:文档齐全,开发者工具成熟
2.2 系统架构图
code复制用户端微信小程序 → HTTP API → Flask后端服务
↓
MySQL数据库
↑
管理端网页(可选) ←───────┘
2.3 关键技术栈版本
- Python 3.8+
- Flask 2.0.3
- Flask-SQLAlchemy 3.0.1
- Flask-JWT-Extended 4.4.4
- MySQL 8.0
- 微信开发者工具 1.06.2209030
3. 数据库设计详解
3.1 核心表结构设计
用户表(users)
sql复制CREATE TABLE `users` (
`user_id` int NOT NULL AUTO_INCREMENT,
`openid` varchar(64) NOT NULL COMMENT '微信唯一标识',
`username` varchar(50) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`balance` decimal(10,2) DEFAULT '0.00',
`is_owner` tinyint(1) DEFAULT '0' COMMENT '是否是车位主',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
车位表(parkings)
sql复制CREATE TABLE `parkings` (
`parking_id` int NOT NULL AUTO_INCREMENT,
`location` varchar(255) NOT NULL,
`lat` decimal(10,7) NOT NULL COMMENT '纬度',
`lng` decimal(10,7) NOT NULL COMMENT '经度',
`price_per_hour` decimal(6,2) NOT NULL,
`owner_id` int NOT NULL,
`status` tinyint DEFAULT '1' COMMENT '1-可用 0-不可用',
`description` text,
`images` varchar(1000) DEFAULT NULL COMMENT '图片URL,多个用逗号分隔',
PRIMARY KEY (`parking_id`),
KEY `owner_id` (`owner_id`),
CONSTRAINT `parkings_ibfk_1` FOREIGN KEY (`owner_id`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
订单表(orders)
sql复制CREATE TABLE `orders` (
`order_id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`parking_id` int NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`total_price` decimal(10,2) NOT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-待支付 1-已支付 2-已完成 3-已取消',
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`transaction_id` varchar(64) DEFAULT NULL COMMENT '微信支付单号',
PRIMARY KEY (`order_id`),
KEY `user_id` (`user_id`),
KEY `parking_id` (`parking_id`),
CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`),
CONSTRAINT `orders_ibfk_2` FOREIGN KEY (`parking_id`) REFERENCES `parkings` (`parking_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 设计要点解析
- 微信用户标识:使用
openid作为用户唯一标识,避免自己维护账号体系 - 地理坐标存储:车位表增加
lat和lng字段用于地图定位 - 订单状态机:用
status字段的枚举值管理订单生命周期 - 图片存储:车位图片存储URL,实际文件可放在云存储服务
注意:MySQL 8.0默认使用
utf8mb4字符集,支持完整的Unicode包括emoji
4. Flask后端实现
4.1 项目结构
code复制parking-api/
├── app.py # 应用入口
├── config.py # 配置文件
├── requirements.txt # 依赖列表
├── models/ # 数据模型
│ ├── __init__.py
│ ├── user.py
│ ├── parking.py
│ └── order.py
├── resources/ # API资源
│ ├── auth.py
│ ├── parking.py
│ └── order.py
└── utils/ # 工具类
├── response.py
└── wx_login.py
4.2 核心API实现
用户认证(JWT)
python复制# resources/auth.py
from flask_restful import Resource
from flask_jwt_extended import create_access_token
from models.user import User
from utils.wx_login import WXLogin
class LoginAPI(Resource):
def post(self):
data = request.get_json()
code = data.get('code')
# 调用微信接口获取openid
wx_login = WXLogin(app.config['WX_APPID'], app.config['WX_SECRET'])
openid = wx_login.get_openid(code)
if not openid:
return {'message': '微信登录失败'}, 401
# 查找或创建用户
user = User.query.filter_by(openid=openid).first()
if not user:
user = User(openid=openid)
db.session.add(user)
db.session.commit()
# 生成JWT token
access_token = create_access_token(identity=user.user_id)
return {'token': access_token, 'user_id': user.user_id}
车位发布API
python复制# resources/parking.py
from flask_restful import Resource, reqparse
from flask_jwt_extended import jwt_required, get_jwt_identity
from models.parking import Parking
parking_parser = reqparse.RequestParser()
parking_parser.add_argument('location', type=str, required=True)
parking_parser.add_argument('lat', type=float, required=True)
parking_parser.add_argument('lng', type=float, required=True)
parking_parser.add_argument('price_per_hour', type=float, required=True)
parking_parser.add_argument('description', type=str)
parking_parser.add_argument('images', type=str)
class ParkingAPI(Resource):
@jwt_required()
def post(self):
args = parking_parser.parse_args()
current_user = get_jwt_identity()
parking = Parking(
location=args['location'],
lat=args['lat'],
lng=args['lng'],
price_per_hour=args['price_per_hour'],
owner_id=current_user,
description=args.get('description'),
images=args.get('images')
)
db.session.add(parking)
db.session.commit()
return {'message': '车位发布成功', 'parking_id': parking.parking_id}, 201
4.3 踩坑记录
-
JWT令牌过期:默认过期时间较短,生产环境需要调整
python复制app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=24) -
跨域问题:微信小程序需要处理CORS
python复制from flask_cors import CORS CORS(app, resources={r"/api/*": {"origins": "*"}}) -
数据库连接池:生产环境需要配置
python复制app.config['SQLALCHEMY_ENGINE_OPTIONS'] = { 'pool_size': 10, 'pool_recycle': 300, 'pool_pre_ping': True }
5. 微信小程序开发
5.1 页面结构
code复制pages/
├── index/ # 首页
├── publish/ # 发布车位
├── detail/ # 车位详情
├── order/ # 订单确认
├── my/ # 个人中心
└── orders/ # 订单列表
5.2 核心功能实现
微信登录
javascript复制// pages/index/index.js
Page({
handleLogin: function() {
wx.login({
success: res => {
if (res.code) {
wx.request({
url: 'https://your-api.com/api/login',
method: 'POST',
data: { code: res.code },
success: (resp) => {
wx.setStorageSync('token', resp.data.token)
wx.setStorageSync('user_id', resp.data.user_id)
}
})
}
}
})
}
})
地图选点
javascript复制// pages/publish/publish.js
Page({
chooseLocation: function() {
wx.chooseLocation({
success: (res) => {
this.setData({
location: res.address,
lat: res.latitude,
lng: res.longitude
})
}
})
}
})
5.3 样式优化技巧
-
rpx单位:适配不同屏幕尺寸
css复制.parking-item { width: 690rpx; margin: 20rpx 30rpx; padding: 20rpx; } -
flex布局:灵活排列元素
css复制.price-container { display: flex; justify-content: space-between; align-items: center; } -
小程序组件:复用UI元素
html复制<van-button type="primary" bindtap="handleSubmit">提交</van-button>
6. 部署与运维
6.1 生产环境部署
使用Gunicorn运行Flask
bash复制gunicorn -w 4 -b 0.0.0.0:5000 app:app
Nginx配置示例
nginx复制server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static {
alias /path/to/your/static/files;
}
}
6.2 小程序上线流程
- 开发版本测试
- 提交微信审核
- 审核通过后发布
- 配置业务域名(API域名需HTTPS)
6.3 监控与日志
- 错误监控:使用Sentry捕获异常
- 日志分割:配置logrotate
code复制/var/log/parking-api/*.log { daily rotate 7 compress missingok notifempty }
7. 项目优化方向
- 缓存优化:对热门车位数据使用Redis缓存
- 搜索优化:集成Elasticsearch实现复杂搜索
- 支付优化:增加优惠券和会员体系
- 安全优化:接口限流和防刷机制
这个项目从零开始实现大概用了两个月时间,最大的收获是对微信生态和Flask的深度理解。特别是微信支付接口的对接,需要仔细阅读文档和多次测试。如果时间允许,下一步我计划增加智能推荐和预约提醒功能。