Django表单初始值设置异常:提交时user字段丢失致表单验证失败
问题根源
HTML中标记为disabled的表单元素不会被浏览器提交到服务器,所以你提交表单时request.POST里根本没有user字段的值,而你的表单又把user设为必填项,自然触发验证失败。
解决方案
核心思路:不需要把user字段放在表单里让用户提交,直接在后台从已认证用户对象赋值,既安全又能避免验证问题。
1. 修改表单定义(forms.py)
移除表单中的user字段,只保留需要用户填写的rating和body;如果要在页面显示用户名,直接在模板里渲染即可,不用通过表单字段:
class ReviewForm(forms.ModelForm): class Meta: model = Review fields = ("rating", "body") # 移除user字段
如果一定要在页面显示用户名且不让用户修改,不要用disabled,改用readonly(readonly字段会被提交,但用户无法编辑),不过更推荐上面的方案:
class ReviewForm(forms.ModelForm): class Meta: model = Review fields = ("user", "rating", "body") widgets = { 'user': forms.TextInput(attrs={"readonly": "readonly"}) # 用readonly代替disabled }
这种情况下要注意:后台需要覆盖提交的user值,防止恶意修改。
2. 优化视图逻辑(views.py)
简化代码,利用commit=False给Review实例赋值user和book:
from django.views.decorators.http import require_POST from django.shortcuts import get_object_or_404, redirect, render from .models import Book, Review from .forms import ReviewForm @require_POST def post_review(request, bookid): book = get_object_or_404(Book, bookid=bookid) form = ReviewForm(data=request.POST) if request.user.is_authenticated and form.is_valid(): review = form.save(commit=False) review.book = book review.user = request.user # 直接从request取用户对象,不是用户名 review.save() return redirect(review.book.get_absolute_url()) # 未认证或表单验证失败,返回表单页面 return render(request, "book/review.html", {"book": book, "form": form})
3. 模板调整(review.html)
如果需要显示当前用户名,直接在模板中渲染,不依赖表单字段:
<p>当前用户:{{ request.user.username }}</p> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">add review</button> </form>
为什么之前的写法无效?
disabled属性导致user字段数据不会被提交到服务器,表单验证时因缺少该字段值失败。- 你在视图中设置
form.fields["user"].initial是在表单初始化之后,对已经接收request.POST的表单来说,初始值不会覆盖提交数据(何况提交数据里根本没有这个字段)。
内容的提问来源于stack exchange,提问作者Lyssa Flynn
相关产品推荐
相关产品推荐

