Django如何从模板向视图传递ID以实现数据更新?
问题分析与解决方案
当前实现存在几个关键问题,导致点击更新链接后无法触发PostgreSQL函数执行:
- 点击
<a>标签发起的是GET请求,但视图仅在POST分支执行数据库操作,因此会直接进入else分支,不会触发函数调用。 - 视图中直接拼接SQL字符串存在SQL注入风险,同时
resolve_item是模型实例对象,直接拼入SQL会导致语法错误。 - 未处理数据库事务提交(如果PostgreSQL函数涉及数据修改,需要手动提交事务)。
可行方案
1. 修正视图函数(views.py)
- 使用参数化查询避免SQL注入
- 正确传递函数所需的参数(假设
resolve_clearance_item需要的是cl_itemid数值) - 处理事务提交(针对数据修改类函数)
- 重定向回列表页,避免刷新页面重复提交
from django.db import connection from django.shortcuts import get_object_or_404, render, redirect def update(request, cl_itemid): # 先验证ID对应的记录存在 resolve_item = get_object_or_404(Clearanceinsert, pk=cl_itemid) if request.method == "POST": with connection.cursor() as cursor: # 用参数化查询传递值,%s是PostgreSQL的占位符 cursor.execute("SELECT resolve_clearance_item(%s)", [cl_itemid]) # 若函数涉及数据变更,必须提交事务 connection.commit() # 重定向回列表页,替换为你的列表页URL名称 return redirect('clearance_index') else: # GET请求返回确认页面,避免误操作触发更新 return render(request, 'clearance/confirm_update.html', {'item': resolve_item})
2. 修改模板,使用POST提交请求
更新属于数据变更操作,建议用表单发起POST请求(<a>标签默认是GET,不适合修改类操作):
<table style="width:100%"> <tr> <th>cl_itemid</th> <th colspan="2">Actions:</th> </tr> {% for data in data %} <tr> <td>{{ data.cl_itemid }}</td> <td> <form method="POST" action="{% url 'update' data.cl_itemid %}"> {% csrf_token %} <!-- Django强制要求的CSRF防护 --> <button type="submit">Update</button> </form> </td> </tr> {% endfor %} </table>
如果想保留链接样式,可用CSS将按钮模拟成链接:
<style> .update-btn { background: none; border: none; color: blue; text-decoration: underline; cursor: pointer; padding: 0; } </style> <td> <form method="POST" action="{% url 'update' data.cl_itemid %}"> {% csrf_token %} <button type="submit" class="update-btn">Update</button> </form> </td>
3. 确认URL配置正确
在urls.py中确保update的路由映射正确:
from django.urls import path from . import views urlpatterns = [ # 其他路由... path('update/<int:cl_itemid>/', views.update, name='update'), path('', views.index, name='clearance_index'), # 列表页路由,对应视图中的redirect目标 ]
替代思路(Django模型封装函数)
如果resolve_clearance_item是自定义PostgreSQL函数,可以在模型中封装它,更符合Django开发规范:
from django.db import models class Clearanceinsert(models.Model): cl_itemid = models.IntegerField(primary_key=True) # 其他模型字段... def resolve_clearance(self): from django.db import connection with connection.cursor() as cursor: cursor.execute("SELECT resolve_clearance_item(%s)", [self.cl_itemid]) result = cursor.fetchone() connection.commit() return result[0] if result else None
视图中直接调用模型方法:
def update(request, cl_itemid): item = get_object_or_404(Clearanceinsert, pk=cl_itemid) if request.method == "POST": item.resolve_clearance() return redirect('clearance_index') else: return render(request, 'clearance/confirm_update.html', {'item': item})
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

