Django点击下载按钮时自动更新模型Choice字段值的实现问题
解决方案
以下两种方案均可实现点击下载按钮自动更新状态、无需跳转额外页面的需求,可根据实际场景选择:
方案1:纯后端实现(无需JS,兼容性最优)
无需引入前端脚本,逻辑最简单,点击后浏览器自动触发下载,当前页面无跳转。
步骤1:修改视图函数(views.py)
原有表单逻辑完全可以移除,直接更新状态后返回文件下载响应即可:
from django.http import FileResponse from django.shortcuts import get_object_or_404 def change_status(request, pk): oficio = get_object_or_404(Oficio, folio=pk) # 仅当状态为NUEVO时更新为LEIDO if oficio.estatus == Oficio.Estatus.NUEVO and request.method == "POST": oficio.estatus = Oficio.Estatus.LEIDO oficio.usuario = request.user # 仅更新指定字段,提升操作效率 oficio.save(update_fields=["estatus", "usuario"]) # 直接返回文件响应,触发浏览器下载 response = FileResponse(oficio.documento.open(), as_attachment=True) return response
步骤2:修改模板代码(template.html)
移除按钮内部嵌套的a标签(不符合HTML规范,容易触发行为冲突),改为纯提交按钮:
<form method="POST" action="{% url 'oficios:status' oficio.folio %}"> {% csrf_token %} <button type="submit" class="btn btn-primary btn-lg" title="Descargar"> <i class="fas fa-file-download"></i> </button> </form>
冗余代码清理
forms.py中的UpdateStatus表单已经完全没有使用场景,可以直接删除。
方案2:AJAX无感知更新(体验最优)
如果需要点击后页面上的状态标签自动同步更新、无需用户手动刷新页面,可采用该方案:
步骤1:修改视图函数(views.py)
返回JSON格式的响应供前端处理:
from django.http import JsonResponse from django.shortcuts import get_object_or_404 def change_status(request, pk): if request.method != "POST": return JsonResponse({"success": False, "msg": "请求方法错误"}) oficio = get_object_or_404(Oficio, folio=pk) new_status = oficio.get_estatus_display() if oficio.estatus == Oficio.Estatus.NUEVO: oficio.estatus = Oficio.Estatus.LEIDO oficio.usuario = request.user oficio.save(update_fields=["estatus", "usuario"]) new_status = oficio.get_estatus_display() return JsonResponse({ "success": True, "new_status": new_status })
步骤2:修改模板代码(template.html)
给状态标签添加唯一标识,绑定按钮点击事件发送AJAX请求:
<!-- 给原有状态标签添加id,方便后续更新内容 --> <span class="badge bg-primary" id="status_{{oficio.folio}}">{{ oficio.get_estatus_display }}</span> <!-- 下载按钮 --> <button type="button" class="btn btn-primary btn-lg download-btn" data-folio="{{oficio.folio}}" data-doc-url="{{oficio.documento.url}}" title="Descargar"> <i class="fas fa-file-download"></i> </button> <!-- 全局CSRF Token,AJAX请求用 --> {% csrf_token %} <script> // 批量绑定所有下载按钮的点击事件 document.querySelectorAll(".download-btn").forEach(btn => { btn.addEventListener("click", function() { const folio = this.dataset.folio; const docUrl = this.dataset.docUrl; const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; // 发送AJAX请求更新状态 fetch(`/oficios/status/${folio}/`, { method: "POST", headers: { "X-CSRFToken": csrfToken, }, }).then(res => res.json()) .then(data => { if (data.success) { // 自动更新页面上的状态标签 document.getElementById(`status_${folio}`).textContent = data.new_status; // 触发文件下载 window.open(docUrl, "_blank"); } }); }); }); </script>
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

