1. 项目概述
校园活动抽奖系统是高校各类活动中不可或缺的环节,传统线下抽奖方式存在组织效率低、参与门槛高、公平性难以保证等问题。基于微信小程序的校园活动抽奖系统(Django框架)正是为解决这些痛点而设计的一款轻量化应用。
作为一名长期从事校园信息化建设的开发者,我在实际工作中发现,很多高校活动组织者仍在使用Excel随机数生成、纸条抽奖等原始方式,不仅耗时耗力,还经常引发学生对公平性的质疑。这套系统正是基于这些实际需求痛点开发而来。
系统采用前后端分离架构,后端基于Django REST Framework构建API服务,前端使用微信小程序作为用户交互入口。这种架构选择主要基于以下考虑:
- 微信生态在高校的普及率接近100%,无需额外安装APP
- Django框架的ORM和Admin后台能快速搭建管理系统
- RESTful API设计便于后期扩展多端接入
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能设计
2.1 系统架构设计
系统采用典型的三层架构:
- 表现层:微信小程序 + 管理后台Web界面
- 业务逻辑层:Django REST Framework构建的API服务
- 数据访问层:MySQL + Redis缓存
这种分层设计使得系统各模块职责清晰,便于团队协作开发和后期维护。特别是在高并发场景下,可以通过横向扩展业务逻辑层节点来提升系统吞吐量。
2.2 主要功能模块
2.2.1 活动管理模块
管理员可以通过Web后台创建抽奖活动,设置以下关键参数:
- 活动基本信息(名称、时间、描述)
- 奖品配置(名称、数量、图片)
- 参与规则(开放/指定人群)
- 抽奖规则(普通随机/加权概率/分组抽选)
实际开发中发现,很多校园活动需要按院系或年级分组抽奖。我们在规则配置中特别加入了"分组抽选"功能,可以设置不同组别独立的中奖名额。
2.2.2 用户参与模块
参与者通过微信小程序完成:
- 微信授权登录获取openid
- 学号绑定验证身份(防止重复参与)
- 查看活动详情和奖品
- 参与抽奖并查看结果
2.2.3 抽奖引擎模块
这是系统的核心组件,实现了多种抽奖算法:
- 纯随机算法:简单随机选取
- 加权随机算法:根据奖品权重计算概率
- 分组抽选算法:按预设分组独立抽奖
我们采用Redis的原子操作保证抽奖过程的高并发安全性,实测可支持5000+用户同时抽奖。
3. 关键技术实现
3.1 后端技术栈
3.1.1 Django REST Framework
我们选择DRF而非原生Django主要基于以下考虑:
- 内置的序列化器简化了API开发
- 可浏览的API界面便于调试
- 丰富的权限控制机制
- 支持多种认证方式(JWT/Session等)
典型API视图示例:
python复制class LotteryViewSet(viewsets.ModelViewSet):
queryset = Lottery.objects.all()
serializer_class = LotterySerializer
permission_classes = [IsAdminOrReadOnly]
@action(detail=True, methods=['post'])
def draw(self, request, pk=None):
lottery = self.get_object()
if not lottery.is_active():
return Response({'error': '活动未开始或已结束'}, status=400)
user = request.user
if user.has_participated(lottery):
return Response({'error': '您已参与过本次抽奖'}, status=400)
prize = lottery.draw_prize(user)
return Response({'prize': prize.name})
3.1.2 数据库设计
主要数据表结构:
- 活动表(lottery):存储活动基本信息
- 奖品表(prize):与活动多对一关联
- 参与记录表(participation):记录用户参与情况
- 中奖记录表(winning):存储中奖结果
我们特别设计了奖品权重字段,支持灵活的概率配置:
python复制class Prize(models.Model):
lottery = models.ForeignKey(Lottery, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='prizes/')
quantity = models.PositiveIntegerField()
weight = models.FloatField(default=1.0) # 权重值,影响中奖概率
is_virtual = models.BooleanField(default=False) # 是否为虚拟奖品
3.2 前端技术实现
3.2.1 微信小程序开发
小程序端主要技术点:
- 使用wx.login获取用户openid
- 通过wx.request与后端API交互
- 本地缓存记录用户参与状态
- 使用canvas绘制中奖动画效果
关键登录逻辑:
javascript复制wx.login({
success: res => {
wx.request({
url: 'https://api.example.com/auth/',
method: 'POST',
data: { code: res.code },
success: res => {
wx.setStorageSync('token', res.data.token)
}
})
}
})
3.2.2 管理后台界面
基于Django Admin定制开发了活动管理后台,主要增强功能:
- 可视化奖品配置界面
- 参与数据统计图表
- 批量导入参与者功能
- 抽奖结果导出
4. 高并发优化实践
4.1 Redis缓存策略
为应对抽奖活动的高并发场景,我们采用Redis实现以下优化:
- 活动信息缓存:减少数据库查询
- 分布式锁:防止重复抽奖
- 计数器:实时统计参与人数
- 消息队列:异步处理中奖通知
关键Redis操作示例:
python复制import redis
from django.conf import settings
r = redis.Redis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
db=settings.REDIS_DB
)
def draw_prize(lottery_id, user_id):
lock_key = f"lottery:{lottery_id}:lock:{user_id}"
# 获取分布式锁,防止重复抽奖
with r.lock(lock_key, timeout=10):
# 检查是否已参与
if r.sismember(f"lottery:{lottery_id}:participants", user_id):
return None
# 执行抽奖逻辑
prize_id = select_prize(lottery_id)
# 记录参与和中奖信息
r.sadd(f"lottery:{lottery_id}:participants", user_id)
if prize_id:
r.sadd(f"lottery:{lottery_id}:winners", user_id)
r.hset(f"lottery:{lottery_id}:prize_mapping", user_id, prize_id)
return prize_id
4.2 数据库优化
针对MySQL的优化措施:
- 合理设计索引(活动ID、用户ID等查询字段)
- 读写分离(抽奖高峰期)
- 批量插入代替单条插入
- 定期归档历史数据
5. 安全与公平性保障
5.1 安全性措施
- HTTPS传输加密
- JWT身份验证
- 敏感数据脱敏存储
- 操作日志审计
- 防SQL注入/XSS攻击
5.2 公平性实现
为确保抽奖公平透明,我们采取以下措施:
- 使用系统时间作为随机种子
- 抽奖算法公开可验证
- 中奖结果区块链存证(可选)
- 完整的抽奖日志记录
抽奖核心算法实现:
python复制import random
import numpy as np
def weighted_random(prizes):
"""加权随机抽奖算法"""
prizes = [p for p in prizes if p['remaining'] > 0]
if not prizes:
return None
weights = [p['weight'] for p in prizes]
total = sum(weights)
prob = [w/total for w in weights]
# 使用numpy的choice函数保证概率准确性
index = np.random.choice(len(prizes), p=prob)
return prizes[index]['id']
6. 部署与运维
6.1 服务器环境
推荐生产环境配置:
- Ubuntu 20.04 LTS
- Nginx + uWSGI
- MySQL 8.0
- Redis 6.0
- Python 3.8+
6.2 部署步骤
- 安装依赖:
bash复制pip install -r requirements.txt
- 数据库迁移:
bash复制python manage.py migrate
- 收集静态文件:
bash复制python manage.py collectstatic
- 启动服务:
bash复制uwsgi --ini uwsgi.ini
6.3 监控与维护
建议配置:
- Prometheus + Grafana监控系统指标
- Sentry错误日志收集
- 定期数据库备份
- 日志轮转策略
7. 常见问题与解决方案
7.1 微信登录失败
问题现象:获取openid失败,返回40029错误
排查步骤:
- 检查AppID和AppSecret是否正确
- 确认服务器时间与北京时间同步
- 检查网络连接是否正常
- 查看微信接口状态是否正常
7.2 抽奖结果不一致
问题现象:不同用户看到的中奖结果不同
解决方案:
- 检查Redis缓存是否同步
- 验证分布式锁是否正常工作
- 确保抽奖算法使用相同随机种子
- 检查数据库事务隔离级别
7.3 高并发下性能下降
优化建议:
- 增加Redis集群节点
- 数据库查询添加缓存
- 使用CDN加速静态资源
- 开启Gzip压缩
8. 项目扩展方向
在实际使用过程中,我们发现系统还可以进一步扩展以下功能:
- 虚拟奖品自动发放:对接校园卡系统或电商平台,实现奖品自动发放
- 智能风控系统:基于用户行为分析识别刷奖行为
- 活动模板库:提供常见活动类型的预设模板
- 数据分析看板:更丰富的参与数据可视化分析
这个项目从最初的需求分析到最终上线,经历了多次迭代优化。最大的收获是认识到校园场景下的特殊需求,比如需要支持按院系分组抽奖、学号验证等功能。在技术选型上,Django REST Framework + 微信小程序的组合被证明是非常适合校园轻量级应用的方案。
