尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Django在线编程竞赛平台部署与判题系统实战指南

Django在线编程竞赛平台部署与判题系统实战指南 简介本资源是一套基于Django框架开发的在线编程竞赛平台完整源码面向Python后端开发者、Web全栈学习者及高校计算机专业学生用于理解并复现典型OJOnline Judge系统的核心架构与工程实践。项目覆盖用户管理、题库维护、竞赛组织、代码提交判题、API接口设计、缓存优化及UV统计等全流程功能具备生产级模块划分与可扩展性设计。压缩包共193个文件以163个Python源码文件为主体支撑业务逻辑与Django应用结构辅以7个配置文件如supervisord.conf、nginx.conf、Dockerfile等体现服务部署与容器化能力另有HTML模板、Shell脚本、SSL证书及Markdown文档构成开箱即用的开发-部署闭环。包体仅282KB轻量但结构完整目录清晰、模块解耦度高适合深入学习Django中REST API、权限控制、异步任务与系统集成等进阶实践。目前已有31人学习下载。1. 这不是另一个“Django博客模板”而是一个可上线的在线编程竞赛平台原型你解压(源码)基于Django框架的在线编程竞赛平台.zip后看到的不是manage.py polls/的教学示例而是一套完整覆盖「题目管理→代码提交→实时判题→排行榜→用户权限分级」闭环的生产级骨架。它不依赖 Vue 或 React 前端框架纯 Django 模板渲染 jQuery AJAX 实现交互对中小团队快速部署 OJOnline Judge类系统极具实操价值。尤其适合高校算法课实训平台、企业内部编程考核系统或开源技术社区的轻量级竞赛服务——不需要 Docker 编排、不强求 Kubernetes一台 2 核 4G 的云服务器 Nginx PostgreSQL 就能跑通核心链路。注意该 ZIP 包不含预编译二进制判题沙箱如 seccomp 隔离的 C 编译器判题逻辑走 Python subprocess 调用本地 gcc/g/python3 解释器因此安全边界依赖操作系统级用户隔离与超时控制不可直接用于面向公网的高并发竞赛场景但作为教学演示、内网测评或二次开发基线完全可靠。2. 从 ZIP 解包到 Django 项目结构还原识别关键模块与依赖约束2.1 解压后必须验证的 4 类文件完整性该 ZIP 包并非简单压缩其目录结构隐含运行约束。解压后需立即检查以下四类文件是否存在且路径正确以典型解压路径/opt/oj-platform/为例文件类型必须存在路径作用说明Django 核心配置/opt/oj-platform/oj_platform/settings/production.py生产环境专用配置含 SECRET_KEY、DEBUGFalse、ALLOWED_HOSTS 等硬性参数不可用settings/base.py替代判题引擎脚本/opt/oj-platform/judge/judge_worker.py独立于 Django 的长进程通过 Redis 队列接收待判题任务调用gcc -o /tmp/xxx /tmp/xxx.c /tmp/xxx input.txt output.txt执行超时由signal.alarm()控制Nginx 反向代理配置片段/opt/oj-platform/deploy/nginx.conf非完整 nginx.conf而是include /opt/oj-platform/deploy/nginx.conf;引用的 location 块专用于/api/judge//static//media/路由分发Supervisor 进程管理配置/opt/oj-platform/deploy/supervisord.conf定义oj-webgunicorn、oj-judgejudge_worker.py、celery-worker异步任务三个进程组含autostarttrue和stopwaitsecs30等关键重启策略提示若解压后缺失deploy/目录说明 ZIP 包被截断或下载不完整。使用unzip -t (源码)基于Django框架的在线编程竞赛平台.zip校验 CRC32 值失败则重新下载。不要尝试用zip -F修复该包无冗余校验段。2.2 依赖安装必须锁定 Python 版本与关键包版本项目requirements.txt中明确要求Django4.2.11非最新 5.x因判题模块judge/utils.py使用了django.db.models.signals.post_save的旧版信号注册语法。执行以下命令前确认系统 Python 版本为 3.9–3.11# 创建隔离环境推荐 pyenv 或 system python -m venv python3.10 -m venv /opt/oj-platform/venv source /opt/oj-platform/venv/bin/activate # 安装时强制忽略兼容性警告但保留 psycopg2-binaryPostgreSQL 驱动 pip install --no-deps -r requirements.txt pip install Django4.2.11 psycopg2-binary2.9.7 redis4.6.0 gunicorn21.2.0注意mysqlclient不在依赖列表中——该项目默认使用 PostgreSQL。若需切换 MySQL必须修改settings/production.py中DATABASES[default][ENGINE]为django.db.backends.mysql并额外安装mysqlclient2.2.4否则python manage.py migrate会报django.core.exceptions.ImproperlyConfigured: mysql isnt an available database backend.2.3 数据库迁移与初始超级用户创建迁移前必须确保 PostgreSQL 服务已启动且oj_platform数据库已创建非仅用户# 登录 psql 创建数据库假设 PostgreSQL 用户为 postgres sudo -u postgres psql -c CREATE DATABASE oj_platform; sudo -u postgres psql -c CREATE USER oj_user WITH PASSWORD StrongPass123!; sudo -u postgres psql -c GRANT ALL PRIVILEGES ON DATABASE oj_platform TO oj_user; # 执行 Django 迁移指定 settings 模块路径 cd /opt/oj-platform python manage.py migrate --settingsoj_platform.settings.production python manage.py createsuperuser --settingsoj_platform.settings.production迁移成功后auth_user、problem_problem、submission_submission等 12 张表将生成。特别注意problem_problem表的test_case_zip字段为models.FileField实际存储路径由settings.production.MEDIA_ROOT /opt/oj-platform/media/决定需确保该目录存在且 Web 服务用户如www-data有写权限。3. Nginx Gunicorn Supervisor 三件套部署让平台真正可访问3.1 配置 Nginx 反向代理与静态资源服务将deploy/nginx.conf内容合并至主配置如/etc/nginx/sites-enabled/oj.conf关键部分如下upstream oj_web { server 127.0.0.1:8000; } server { listen 80; server_name oj.example.com; # 静态资源直接由 Nginx 服务不经过 Django location /static/ { alias /opt/oj-platform/staticfiles/; expires 1y; add_header Cache-Control public, immutable; } # 媒体文件题目测试用例 ZIP、用户上传代码也由 Nginx 服务 location /media/ { alias /opt/oj-platform/media/; expires 1h; } # API 请求转发给 Gunicorn location /api/ { proxy_pass http://oj_web; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 根路径交由 Django 处理 location / { proxy_pass http://oj_web; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }提示/static/路径必须与python manage.py collectstatic --settingsoj_platform.settings.production输出目录一致。若collectstatic报错OSError: [Errno 13] Permission denied: /opt/oj-platform/staticfiles执行sudo chown -R www-data:www-data /opt/oj-platform/staticfiles。3.2 Gunicorn 启动参数详解与性能调优supervisord.conf中oj-web进程组定义如下[program:oj-web] command/opt/oj-platform/venv/bin/gunicorn --bind 127.0.0.1:8000 --workers 3 --worker-class sync --timeout 120 --max-requests 1000 --graceful-timeout 30 --log-level info oj_platform.wsgi:application directory/opt/oj-platform userwww-data autostarttrue autorestarttrue redirect_stderrtrue stdout_logfile/var/log/oj/web.log--workers 3按 2 核 CPU 计算2 × 2 1 5理论值但判题模块占用大量 CPU故降为 3 避免争抢--timeout 120必须 ≥ 判题脚本JUDGE_TIMEOUT 60秒否则 Gunicorn 在判题完成前就 kill worker--max-requests 1000防止内存泄漏每处理 1000 个请求后重启 worker--graceful-timeout 30确保正在执行的判题请求有 30 秒优雅退出时间。3.3 Supervisor 管理判题进程与故障自愈supervisord.conf中oj-judge组是平台核心其配置决定判题稳定性[program:oj-judge] command/opt/oj-platform/venv/bin/python /opt/oj-platform/judge/judge_worker.py directory/opt/oj-platform useroj-judge # 必须创建独立用户禁止用 root 或 www-data autostarttrue autorestarttrue startretries3 stopwaitsecs60 redirect_stderrtrue stdout_logfile/var/log/oj/judge.log environmentPYTHONPATH/opt/oj-platform注意useroj-judge要求提前创建该系统用户并赋予/opt/oj-platform/media/读写权限及/tmp/执行权限sudo useradd -r -s /bin/false oj-judge sudo chown -R oj-judge:oj-judge /opt/oj-platform/media/ sudo setfacl -R -m u:oj-judge:rwx /tmp/启动全部服务后执行sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start all再用curl http://localhost/api/health/验证接口返回{status:ok,judge_status:ready}。4. 判题模块深度配置控制超时、内存限制与语言支持4.1 修改judge/config.py中的 5 个关键安全参数该文件定义判题沙箱行为直接关系到服务器安全。必须根据硬件调整参数名默认值推荐值2核4G说明JUDGE_TIMEOUT3060单次判题最大运行时间秒Python 题目常需 40 秒JUDGE_MEMORY_LIMIT134217728 (128MB)268435456 (256MB)进程虚拟内存上限C STL 容器易突破 128MBJUDGE_PROCESS_LIMIT50100子进程数限制避免 fork 炸裂JUDGE_MAX_FILE_SIZE1048576 (1MB)5242880 (5MB)用户提交代码最大体积支持大算法题SUPPORTED_LANGUAGES[c, cpp, python][c, cpp, python, java]添加 Java 需确保系统已安装 OpenJDK 17修改后需重启oj-judge进程sudo supervisorctl restart oj-judge。4.2 Java 支持的三步落地非默认启用添加 Java 支持需手动补全安装 JDK 并设环境变量sudo apt install openjdk-17-jdk echo export JAVA_HOME/usr/lib/jvm/java-17-openjdk-amd64 | sudo tee -a /etc/environment source /etc/environment在judge/language_handlers.py中注册 Java 处理器# 新增 JavaCompiler 类位于 judge/language_handlers.py class JavaCompiler(BaseCompiler): def compile(self, src_path, exe_path): # 编译命令javac -d /tmp/xxx/ /tmp/xxx/Main.java cmd [javac, -d, os.path.dirname(exe_path), src_path] return self._run_command(cmd, timeout30) def run(self, exe_path, stdin_path, stdout_path, stderr_path): # 运行命令java -cp /tmp/xxx/ Main input.txt output.txt class_dir os.path.dirname(exe_path) main_class Main cmd [java, -cp, class_dir, main_class] return self._run_command(cmd, stdin_path, stdout_path, stderr_path, timeoutself.timeout)更新SUPPORTED_LANGUAGES并重启判题进程在judge/config.py中将java加入列表执行sudo supervisorctl restart oj-judge。4.3 测试判题链路用 curl 模拟一次提交验证判题是否生效执行以下命令替换YOUR_JWT_TOKEN为管理员登录后获取的 tokencurl -X POST http://oj.example.com/api/submissions/ \ -H Authorization: Bearer YOUR_JWT_TOKEN \ -H Content-Type: application/json \ -d { problem_id: 1, language: python, code: print(\Hello OJ!\) }成功响应包含status: pending10 秒后查GET /api/submissions/1/应返回status: accepted且time_used_ms: 123。若返回status: system_error检查/var/log/oj/judge.log中是否出现OSError: [Errno 13] Permission denied—— 这表示oj-judge用户无权执行/tmp/下的二进制文件需执行sudo setfacl -m u:oj-judge:x /tmp/。5. 生产环境必须启用的 3 项加固措施与监控技巧5.1 强制 HTTPS 与 HSTS 头注入在 Nginx 配置的server块中添加listen 443 ssl http2; ssl_certificate /etc/letsencrypt/live/oj.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/oj.example.com/privkey.pem; add_header Strict-Transport-Security max-age31536000; includeSubDomains always;同时在settings/production.py中追加SECURE_SSL_REDIRECT True SECURE_HSTS_SECONDS 31536000 SECURE_HSTS_INCLUDE_SUBDOMAINS True SECURE_CONTENT_TYPE_NOSNIFF True SESSION_COOKIE_SECURE True CSRF_COOKIE_SECURE True提示SECURE_SSL_REDIRECT True会使所有 HTTP 请求 301 跳转 HTTPS但需确保 Lets Encrypt 证书已签发成功否则网站完全不可访问。首次部署建议先关闭此开关确认功能正常后再启用。5.2 PostgreSQL 连接池与慢查询日志在settings/production.py的DATABASES配置中加入连接池参数OPTIONS: { MAX_CONNS: 20, # 最大连接数匹配 PostgreSQL max_connections * 0.5 CONN_MAX_AGE: 60, # 连接复用 60 秒 },并在 PostgreSQL 配置/etc/postgresql/*/main/postgresql.conf中启用慢查询log_min_duration_statement 1000 # 记录 1s 的查询 log_directory pg_log log_filename postgresql-%Y-%m-%d_%H%M%S.log重启 PostgreSQL 后慢查询日志将输出至/var/lib/postgresql/data/pg_log/重点关注SELECT * FROM submission_submission WHERE status pending ORDER BY created_at LIMIT 100类语句——这是判题队列轮询 SQL若未在status和created_at上建复合索引会导致全表扫描。5.3 判题成功率监控用 Redis 键值统计异常率平台未内置监控看板但可通过 Redis 实时提取关键指标。判题模块在judge_worker.py中写入以下键judge:stats:total累计判题次数INCRjudge:stats:success成功次数INCRjudge:stats:timeout超时次数INCRjudge:stats:ce编译错误次数INCR执行以下命令计算当前成功率redis-cli EOF GET judge:stats:total GET judge:stats:success EOF若success/total 0.95需检查judge.log中是否高频出现subprocess.TimeoutExpired—— 此时应调低JUDGE_TIMEOUT或升级服务器 CPU。注意Redis 键名前缀judge:可在judge/config.py中修改但所有统计脚本需同步更新。不要删除judge:stats:*键否则统计数据归零。本文还有配套的精品资源点击获取
返回列表