Django会话无法保存表单数据问题求助
问题描述
开发了一个分阶段Django视图,要求不使用AJAX且保持URL不变,流程为表单获取数据→处理→存入数据库。部分数据无法通过POST传递,尝试存入session但失效:表单POST数据正常,但session存/读要么返回空值要么触发KeyError。手动设置request.session['newvar'] = "test works"可正常读取,说明session功能本身无问题。
视图代码
def processpayment(request, *args, **kwargs): if request.method == 'POST': form = paymentDetailsForm(request.POST) amount = request.POST.get('amount', False); stage = request.POST.get('stage', False); if (stage == "checkout"): return render(request, "payment.html", {'form': form, 'amount': amount, 'stage': stage}) if (stage == "complete"): return render(request, "payment.html", {'amount': request.session['amount'], 'stage': stage, 'name': request.session['name']}) if (amount == "custom"): if form.is_valid(): amount = form_data.get('amount') name = form_data.get('name') request.session['amount'] = amount request.session['name'] = name request.session.modified = True return render(request, "payment.html", {'form': form, 'stage': stage, 'amount': amount}) return render(request, "payment.html", {'amount': amount, 'stage': stage}) else: return render(request, "payment.html") return render(request, "payment.html")
模板代码
{% load static %} {% load widget_tweaks %} <html> <head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/css/bootstrap.min.css" integrity="sha512-rt/SrQ4UNIaGfDyEXZtNcyWvQeOq0QLygHluFQcSjaGB04IxWhal71tKuzP6K8eYXYB6vJV4pHkXcmFGGQ1/0w==" crossorigin="anonymous" referrerpolicy="no-referrer" /> </head> <body> <div class="m-3"> {% if stage == "complete" %} <<h2 class="mx-auto text-center mb-3">Name:<b> {{ name }}</h2> {% elif stage == "checkout" %} <div style="margin-left: 20%; margin-right: 20%;"> <h2 class="mx-auto text-center mb-3">Amount to be charged: ${{ amount }}</h2> <div class="col-md-12 mx-auto d-flex justify-content-center mt-2"> <div class="container"> <div class="row "> <div class="col-md-6 p-3"> <form id='formName' name='formName' action="{% url 'processpayment' %}" method="POST"> <input type="hidden" id="amount" name="amount" value="{{ amount }}"> <input type="hidden" id="stage" name="stage" value="complete"> <button type="submit" name="submit" class="btn btn-primary mt-3">Next</button> </form> </div> </div> </div> </div> </div> {% elif amount == "custom" %} <form action="{% url 'processpayment' %}" method="POST"> <div class="container pt-3 pb-3"> <input type="hidden" id="stage" name="stage" value="checkout"> <div class="row"> <div class="col-md-6 mb-2"> {% render_field form.amount class+="form-control" placeholder="AMOUNT" %} </div> <div class="col-md-6 mb-2"> {% render_field form.name class+="form-control" placeholder="NAME" %} </div> </div> <div class="row justify-content-center"> <span class="input-group-btn"> <button class="btn btn-primary mt-3" type="submit">Next</button> </span> </div> </div> </form> {% else %} <div class="col-md-12 mx-auto d-flex justify-content-center mt-2"> <div class="container"> <div class="row "> <div class="col-md-12 text-center p-3"> <form id='formName' name='formName' action="{% url 'processpayment' %}" method="POST"> <input type="hidden" id="amount" name="amount" value="custom"> <button type="submit" name="submit" class="btn btn-primary">Make a payment</button> </form> </div> </div> </div> </div> {% endif %} </div> </body> </html>
forms.py代码
from django import forms from django.forms import widgets from .models import PaymentMade class paymentDetailsForm(forms.ModelForm): name = forms.CharField(max_length=50) amount = forms.IntegerField() def __init__(self, *args, **kwargs): super(paymentDetailsForm, self).__init__(*args, **kwargs) self.fields['name'].required = False self.fields['amount'].required = False class Meta: model = PaymentMade fields = ('name', 'amount')
Session配置(settings.py)
SESSION_EXPIRE_AT_BROWSER_CLOSE = True SESSION_COOKIE_AGE = 1200 SESSION_SAVE_EVERY_REQUEST = True
问题原因及修复方案
核心问题:未定义form_data变量
在视图的amount == "custom"分支中,代码使用了form_data.get('amount'),但form_data从未被定义,正确的做法是使用form.cleaned_data获取验证后的表单数据。
修复后的视图代码
def processpayment(request, *args, **kwargs): if request.method == 'POST': form = paymentDetailsForm(request.POST) amount = request.POST.get('amount', False) stage = request.POST.get('stage', False) if stage == "checkout": return render(request, "payment.html", {'form': form, 'amount': amount, 'stage': stage}) if stage == "complete": # 用get方法避免KeyError,提供默认值 session_amount = request.session.get('amount', 0) session_name = request.session.get('name', 'Unknown') return render(request, "payment.html", {'amount': session_amount, 'stage': stage, 'name': session_name}) if amount == "custom": if form.is_valid(): # 替换form_data为form.cleaned_data amount = form.cleaned_data.get('amount') name = form.cleaned_data.get('name') request.session['amount'] = amount request.session['name'] = name # Django修改session字典后会自动标记为modified,此行可省略 # request.session.modified = True return render(request, "payment.html", {'form': form, 'stage': stage, 'amount': amount}) return render(request, "payment.html", {'amount': amount, 'stage': stage}) else: return render(request, "payment.html") return render(request, "payment.html")
额外优化建议
- 读取session时使用
get方法并设置默认值,避免KeyError导致页面崩溃 - 模板中
stage == "complete"分支存在多余的<符号:<<h2,需修正为<h2 - 所有POST表单缺少
{% csrf_token %}标签,Django默认要求该令牌验证,否则会返回403错误,需在每个表单内添加
内容的提问来源于stack exchange,提问作者Jake Rankin
相关产品推荐
相关产品推荐

