如何在Django中通过AJAX调用Python脚本及校园IoT项目优化问询
在Django中用AJAX调用Python脚本(适配你的IoT考勤支付系统)
Hey there! 针对你的场景——给非Linux用户提供友好界面替代CLI工具,我来一步步拆解怎么用AJAX结合Django实现需求,同时适配你的树莓派、RFID/指纹模块硬件架构:
核心思路
AJAX没法直接调用Python脚本,得通过Django视图作为中间层:前端页面发送AJAX请求到Django的URL,视图处理请求(调用你的Python/CLI逻辑),再把结果返回给前端。用户在网页上点个按钮就能完成操作,完全不用碰Shell。
步骤1:把CLI逻辑封装到Django视图里
别直接用subprocess调用CLI(虽然能跑,但不够优雅安全),建议把CLI的核心代码改成可导入的函数,或者写成Django管理命令,这里给两种方案:
方案A:重构CLI逻辑为可调用函数
假设你的CLI工具process_rfid_data.py里有读取RFID并同步数据库的逻辑,把它封装成函数放到Django项目里:
# 在你的Django app下新建utils/rfid_utils.py import psycopg2 from django.conf import settings def process_rfid(tag_id): # 这里写原来CLI里的核心逻辑:验证标签、更新考勤记录等 conn = psycopg2.connect( dbname=settings.DATABASES['default']['NAME'], user=settings.DATABASES['default']['USER'], password=settings.DATABASES['default']['PASSWORD'], host=settings.DATABASES['default']['HOST'] ) # ... 执行数据库操作(比如插入考勤记录) ... conn.close() return {"status": "success", "message": f"RFID标签 {tag_id} 已同步"}
然后在Django视图里调用这个函数:
# views.py from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt # 临时用,后面会加CSRF保护 from .utils.rfid_utils import process_rfid @csrf_exempt def ajax_process_rfid(request): if request.method == 'POST': tag_id = request.POST.get('tag_id') if not tag_id: return JsonResponse({"status": "error", "message": "缺少RFID标签ID"}) # 调用封装好的业务逻辑 result = process_rfid(tag_id) return JsonResponse(result) return JsonResponse({"status": "error", "message": "仅支持POST请求"})
方案B:直接调用现有CLI脚本(不想改代码时用)
如果暂时不想重构CLI,用subprocess调用,但一定要过滤参数避免命令注入:
# views.py import subprocess from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def ajax_run_cli(request): if request.method == 'POST': cmd_args = request.POST.get('args', '') # 安全过滤:只允许字母数字的参数(比如RFID标签ID) if not cmd_args.isalnum(): return JsonResponse({"status": "error", "message": "无效参数"}) # 调用CLI脚本 result = subprocess.run( ['python', '/path/to/your/cli_tool.py', cmd_args], capture_output=True, text=True ) if result.returncode == 0: return JsonResponse({"status": "success", "output": result.stdout}) else: return JsonResponse({"status": "error", "output": result.stderr}) return JsonResponse({"status": "error", "message": "仅支持POST请求"})
步骤2:配置Django URL路由
把上面的视图映射到一个URL,让AJAX能访问到:
# urls.py from django.urls import path from . import views urlpatterns = [ # ... 其他已有URL ... path('ajax/process-rfid/', views.ajax_process_rfid, name='ajax_process_rfid'), # 如果是调用CLI的话,加这个: # path('ajax/run-cli/', views.ajax_run_cli, name='ajax_run_cli'), ]
步骤3:前端编写AJAX请求(带CSRF保护)
Django默认启用CSRF保护,所以AJAX请求必须带上CSRF令牌,下面给原生JS和jQuery两种写法:
原生JS版本
<!-- 在你的Django模板页面里 --> <button id="processRfidBtn">处理RFID数据</button> <div id="result"></div> <script> // 获取CSRF令牌的工具函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } const csrftoken = getCookie('csrftoken'); // 绑定按钮点击事件 document.getElementById('processRfidBtn').addEventListener('click', function() { const tagId = prompt('请输入RFID标签ID:'); // 也可以从输入框获取 if (!tagId) return; fetch('/ajax/process-rfid/', { method: 'POST', headers: { 'X-CSRFToken': csrftoken, 'Content-Type': 'application/x-www-form-urlencoded', }, body: `tag_id=${encodeURIComponent(tagId)}` }) .then(response => response.json()) .then(data => { const resultDiv = document.getElementById('result'); if (data.status === 'success') { resultDiv.innerHTML = `<p style="color: green;">${data.message}</p>`; } else { resultDiv.innerHTML = `<p style="color: red;">${data.message}</p>`; } }) .catch(error => { document.getElementById('result').innerHTML = `<p style="color: red;">请求失败:${error}</p>`; }); }); </script>
jQuery版本(项目用jQuery的话更简洁)
<button id="processRfidBtn">处理RFID数据</button> <div id="result"></div> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $('#processRfidBtn').click(function() { const tagId = prompt('请输入RFID标签ID:'); if (!tagId) return; $.ajax({ url: '{% url "ajax_process_rfid" %}', // 用Django URL反向解析,更灵活 type: 'POST', data: { tag_id: tagId }, headers: { 'X-CSRFToken': $('[name=csrfmiddlewaretoken]').val() // 从模板表单取CSRF令牌 }, success: function(data) { if (data.status === 'success') { $('#result').html(`<p style="color: green;">${data.message}</p>`); } else { $('#result').html(`<p style="color: red;">${data.message}</p>`); } }, error: function(xhr, status, error) { $('#result').html(`<p style="color: red;">请求失败:${error}</p>`); } }); }); </script>
针对你的IoT硬件场景的额外建议
因为你的系统用树莓派做客户端,搭配RFID/指纹模块,这里分两种常见场景给建议:
- 场景1:树莓派采集数据后自动同步到Django:树莓派上的采集脚本可以直接用
requests库发送POST请求到上面的AJAX接口,不用用户手动输入。比如树莓派上的代码:# 树莓派上的RFID采集脚本 import requests rfid_tag_id = "123456" # 从EM-18阅读器读取的标签ID response = requests.post( 'https://your-django-domain.com/ajax/process-rfid/', data={'tag_id': rfid_tag_id}, headers={'X-CSRFToken': 'your-csrf-token'} # 服务器间请求可临时关闭该接口CSRF,同时加IP白名单 ) print(response.json()) - 场景2:网页触发树莓派执行本地脚本:如果需要用户在网页上操作,让树莓派执行本地脚本(比如控制指纹模块),得在树莓派上跑个小型API服务(比如Flask),然后Django先接收AJAX请求,再转发到树莓派的API;或者用WebSocket实现实时通信,适合低延迟场景。
安全注意事项
- 永远不要把用户输入直接拼接到
subprocess命令里,一定要过滤验证参数,防止命令注入。 - 正式环境别用
@csrf_exempt,要么用上面的CSRF令牌方式,要么给特定IP(比如树莓派IP)加白名单。 - 给AJAX接口加权限控制,比如用Django的
@login_required装饰器,只允许授权用户访问。
内容的提问来源于stack exchange,提问作者Dhaval Savalia
相关产品推荐
相关产品推荐

