1. 项目概述
这个Django电影购票系统是一个典型的Web应用开发项目,它模拟了现代影院在线售票的核心业务流程。作为一个全栈开发项目,它涵盖了用户认证、座位选择、支付流程、订单管理等完整功能链。我曾在多个商业项目中实现过类似系统,这次将分享从架构设计到具体实现的完整经验。
系统采用Django作为后端框架,这是Python生态中最成熟的Web框架之一。它内置的ORM、Admin后台和模板系统,特别适合快速开发此类数据密集型的业务系统。前端部分使用Bootstrap保证响应式布局,配合jQuery处理动态交互。数据库选用MySQL,考虑到票务系统对事务完整性的要求。
2. 核心功能模块设计
2.1 用户认证系统
Django自带的auth模块已经提供了完善的用户体系,但我们仍需进行深度定制:
python复制class CustomUser(AbstractUser):
phone = models.CharField(max_length=15)
avatar = models.ImageField(upload_to='avatars/')
def get_booking_history(self):
return self.orders.filter(status__in=['paid', 'used'])
关键点在于:
- 扩展AbstractUser而不是从头开发
- 使用ImageField需要配置MEDIA_ROOT
- 添加业务相关的方法而非仅存储数据
重要提示:用户密码务必使用make_password()处理,绝对不要明文存储。我曾见过因密码泄露导致的法律纠纷,这点要格外谨慎。
2.2 影院与放映厅建模
这部分是系统的核心数据模型,需要精确反映物理世界的业务规则:
python复制class Theater(models.Model):
name = models.CharField(max_length=100)
location = models.PointField() # 需要安装django.contrib.gis
facilities = models.ManyToManyField('Facility')
class Screen(models.Model):
theater = models.ForeignKey(Theater, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
seating_map = models.JSONField() # 存储座位矩阵
def get_available_seats(self, showtime):
# 实现座位状态查询逻辑
pass
特别说明:
- PointField需要PostGIS支持,如使用MySQL可替换为lat/lng字段
- JSONField存储动态座位图,比关联表更灵活
- 座位状态需要实时计算,不能简单缓存
2.3 订单与支付系统
这是最复杂的业务模块,需要处理高并发和事务:
python复制class Order(models.Model):
STATUS_CHOICES = [
('unpaid', '待支付'),
('paid', '已支付'),
('cancelled', '已取消')
]
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
showtime = models.ForeignKey('Showtime', on_delete=models.PROTECT)
seats = models.JSONField() # 格式: [["A",1],["A",2]]
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
@transaction.atomic
def make_payment(self, payment_method):
# 实现支付事务
pass
支付环节的注意事项:
- 必须使用@transaction.atomic装饰器
- 先锁票再发起支付请求
- 设置合理的支付超时时间(建议15分钟)
3. 关键技术实现细节
3.1 座位锁定机制
解决并发选座的核心问题,我们采用数据库悲观锁:
python复制def reserve_seats(showtime_id, seat_list):
with transaction.atomic():
showtime = Showtime.objects.select_for_update().get(pk=showtime_id)
if check_availability(showtime, seat_list):
# 创建临时订单记录
return create_temp_order(showtime, seat_list)
raise SeatNotAvailableError()
实测中需要注意:
- MySQL默认隔离级别下,select_for_update可能引发死锁
- 锁定时长不宜超过500ms
- 前端需要配合轮询订单状态
3.2 定时任务设计
使用Celery处理以下异步任务:
- 释放超时未支付订单
- 生成每日销售报表
- 发送电子票邮件
配置示例:
python复制@app.task(bind=True)
def release_unpaid_orders(self):
expired_orders = Order.objects.filter(
status='unpaid',
created_at__lt=timezone.now()-timedelta(minutes=15)
)
for order in expired_orders:
order.release_seats()
部署建议:
- 使用Redis作为Broker
- 监控任务队列积压情况
- 重要任务要配置重试机制
3.3 性能优化方案
针对票务系统特点,我们采用多级缓存:
- 热点数据缓存:
python复制def get_popular_movies():
return cache.get_or_set('popular_movies',
lambda: Movie.objects.filter(is_hot=True)[:10],
timeout=3600
)
- 查询优化:
python复制Showtime.objects.select_related('movie', 'screen').prefetch_related('screen__theater')
- 静态资源CDN加速:
html复制<img src="{% static 'posters/movie.jpg' %}" cdn-enabled>
4. 部署与监控
4.1 生产环境配置
推荐使用Docker Compose部署:
yaml复制version: '3'
services:
web:
build: .
command: gunicorn cinema.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/app/static
depends_on:
- redis
- db
redis:
image: redis:alpine
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
关键配置项:
- Gunicorn worker数 = CPU核心数 * 2 + 1
- PostgreSQL连接池大小建议20-50
- Redis最大内存限制1GB
4.2 监控指标
必须监控的核心指标:
| 指标类别 | 具体指标 | 报警阈值 |
|---|---|---|
| 应用性能 | 请求响应时间 | >500ms |
| 数据库 | 活跃连接数 | >最大连接数80% |
| 业务 | 每分钟下单量 | 同比下跌50% |
| 系统 | CPU使用率 | >70%持续5分钟 |
推荐使用Prometheus+Grafana搭建监控看板。
5. 常见问题排查
5.1 座位冲突问题
现象:用户A和B同时选中相同座位
排查步骤:
- 检查数据库隔离级别
sql复制SHOW VARIABLES LIKE 'transaction_isolation'; - 验证select_for_update是否生效
- 检查前端是否重复提交
5.2 支付回调丢失
现象:支付成功但订单状态未更新
解决方案:
- 实现补偿查询接口
- 添加对账任务
- 日志记录原始回调数据
5.3 性能下降分析
使用Django Debug Toolbar定位:
- 检查N+1查询问题
- 分析模板渲染耗时
- 查看缓存命中率
6. 项目扩展方向
基于这个基础系统,可以考虑:
- 会员积分系统
python复制class LoyaltyProgram:
def calculate_points(self, order):
return int(order.total_amount)
- 智能推荐引擎
python复制def recommend_movies(user):
from sklearn.neighbors import NearestNeighbors
# 实现协同过滤算法
- 移动端APP开发
- 使用DRF构建API
- 采用JWT认证
- 支持WebSocket实时推送
这个项目源码我已托管在GitHub,包含完整的测试用例和API文档。在实际开发过程中,最大的教训是要提前设计好事务边界,特别是在处理票务库存时。建议新手从小的业务场景开始,逐步扩展功能模块。