Django资产管理系统中“Confirm Changes”按钮触发404错误排查
问题描述
我正在开发一个基于Django的简易资产管理程序,在assman.html中有处理资产详情修改的代码,同时有唤起该表单的"change"按钮代码,两个场景都调用views.py中的assman_handler()函数。点击"change"和"delete"按钮时函数可正常执行,但点击"Confirm Changes"按钮时直接返回404错误:
Page not found (404)
No Asset matches the given query.
Request Method: POST
Request URL: http://localhost:8000/assman_handler
Raised by: assman.views.assman_handler
相关代码如下:
修改资产表单代码(assman.html)
{%if change_form%} <h2>Change Asset Details</h2> <form method="POST" name='change_asset' action="{% url 'assman_handler' %}"> {% csrf_token %} {% if NoSuchUser %} <script>window.alert('No such user!')</script> {% endif %} <table> <tr> <td><label for="qrcode">QR Code:</label></td> <td><input type="text" name="qrcode" class="form-control" id="qrcode" maxlength='13' value = "{{ asset.qrcode }}" required></td> </tr> <tr> <td><label for ="name" required>Asset Name: </label></td> <td><input type="text" name="name" class='form-control' value = "{{ asset.name }}" required ></input></td> </tr> <tr> <td><label for="user_id">User:</label></td> <td> <select name="user_id"> {%for user in users%} <option value="{{ user.id }}" {% if user.id == asset.user.id %}selected{% endif %}>{{ user.username }}</option> </option> {%endfor%} </select> </td> </tr> <tr> <td><label for="checkout_date">Checkout Date:</label></td> <td><input type="date" name="checkout_date" class="form-control" id="checkout_date" value = "{{asset.checkout_date}}" required></td> </tr> <tr> <td><label for="location">Location:</label></td> <td><input name="location" class="form-control" id="location" value = "{{asset.location}}" required></td> </tr> </table> <button type="submit" class="btn btn-primary" value='confirm' name='value'>Confirm Changes</button> </form> {%endif%}
唤起修改表单的按钮代码(assman.html)
<h2>Matched Items</h2> {%for asset in matches%} <li> {{asset.name}} at {{asset.location}} owned by {{asset.user}} expiring on {{asset.checkout_date}}</li> <form method="POST" action="{% url 'assman_handler' %}" style="display: inline-block;"> {% csrf_token %} <input type="submit" name="value" value="change" id="change-btn"> <input type="hidden" value={{asset.id}} name='asset_id'> </form> <form method='POST' action="{% url 'assman_handler' %}" style="display: inline-block;"> {% csrf_token %} <input type="submit" value="delete" name='value' > <input type="hidden" name = "asset_id" value={{asset.id}} name='asset'> </form> </li> {%endfor%}
视图函数代码(views.py)
def assman_handler(request): print(request.POST.get('value')) #Setting variable values assid = request.POST.get('asset_id') asset = Asset.objects.get(id=assid) if request.POST.get('value') == 'change': return render(request, 'assman.html', {'users': User.objects.all(),'change_form': True, 'asset': asset, 'allass': Asset.objects.all()}) elif request.POST.get('value') == 'confirm': # Behaviour for changing assets redirect('assman') elif request.POST.get('value') == 'delete': asset.delete() redirect('assman')
Asset模型代码(models.py)
class Asset(models.Model): name = models.CharField(max_length=255) location = models.CharField(max_length=255) user = models.ForeignKey(User, on_delete=models.CASCADE) checkout_date = models.DateField() qrcode = models.CharField(max_length=13) objects = models.Manager()
问题原因
- 缺少资产ID传递:点击"Confirm Changes"提交修改表单时,表单未携带
asset_id隐藏字段,导致assid = request.POST.get('asset_id')获取到的值为None。 - 无异常处理逻辑:调用
Asset.objects.get(id=assid)时,assid为None会触发Asset.DoesNotExist异常,Django默认将该异常转换为404错误。 - 视图逻辑顺序错误:在判断操作类型之前就执行了资产查询代码,导致确认修改的请求还没进入分支判断就触发了异常。
修复方案
步骤1:给修改表单添加asset_id隐藏字段
修改assman.html中的修改资产表单,在{% csrf_token %}下方添加隐藏字段传递当前资产ID:
{%if change_form%} <h2>Change Asset Details</h2> <form method="POST" name='change_asset' action="{% url 'assman_handler' %}"> {% csrf_token %} <!-- 添加资产ID隐藏字段 --> <input type="hidden" name="asset_id" value="{{ asset.id }}"> {% if NoSuchUser %} <script>window.alert('No such user!')</script> {% endif %} <!-- 剩余表单内容保持不变 -->
步骤2:调整视图函数逻辑并添加异常处理
修改views.py中的assman_handler函数,先判断操作类型,再按需查询资产,同时处理资产不存在的情况:
from django.shortcuts import redirect, render from django.http import Http404 def assman_handler(request): action = request.POST.get('value') print(action) if action == 'change': assid = request.POST.get('asset_id') try: asset = Asset.objects.get(id=assid) except Asset.DoesNotExist: raise Http404("资产不存在") return render(request, 'assman.html', { 'users': User.objects.all(), 'change_form': True, 'asset': asset, 'allass': Asset.objects.all() }) elif action == 'confirm': assid = request.POST.get('asset_id') try: asset = Asset.objects.get(id=assid) # 执行资产修改逻辑 asset.qrcode = request.POST.get('qrcode') asset.name = request.POST.get('name') asset.user_id = request.POST.get('user_id') asset.checkout_date = request.POST.get('checkout_date') asset.location = request.POST.get('location') asset.save() except Asset.DoesNotExist: raise Http404("资产不存在") return redirect('assman') elif action == 'delete': assid = request.POST.get('asset_id') try: asset = Asset.objects.get(id=assid) asset.delete() except Asset.DoesNotExist: raise Http404("资产不存在") return redirect('assman') # 处理未知操作 return redirect('assman')
步骤3:修正删除表单的重复name属性
删除按钮的表单中,隐藏字段存在重复name属性,修改为唯一的name="asset_id":
<form method='POST' action="{% url 'assman_handler' %}" style="display: inline-block;"> {% csrf_token %} <input type="submit" value="delete" name='value' > <input type="hidden" name="asset_id" value="{{asset.id}}"> </form>
内容的提问来源于stack exchange,提问作者Hannah K
相关产品推荐
相关产品推荐

