Django:ModelForm 未绑定到 request.POST
Django: ModelForm not binding to request.POST
我有以下型号:
class Tracking(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
week = models.IntegerField(choices=settings.WEEK_CHOICES, blank=True)
term = models.IntegerField(choices=settings.TERM_CHOICES, blank=True)
year = models.IntegerField(choices=settings.YEAR_CHOICES, blank=True)
target = models.CharField(max_length=256, blank=True)
monday = models.IntegerField()
tuesday = models.IntegerField()
wednesday = models.IntegerField()
thursday = models.IntegerField()
friday = models.IntegerField()
链接到此表单:
class AddTrackingForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddTrackingForm, self ).__init__(*args, **kwargs)
class Meta:
model = models.Tracking
fields = '__all__'
用户填写表单后,我想将实例保存到数据库中:
class TrackingView(generic.TemplateView):
template_name = "tracking.html"
def get(self, request, *args, **kwargs):
form = forms.AddTrackingForm()
form.fields['person'].queryset = models.Person.objects.filter(active=True).order_by('-last_name', '-first_name')
return render(request, self.template_name, {'form': form, })
def post(self, request, *args, **kwargs):
form = forms.AddTrackingForm(request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.person = models.Person.objects.get(id=int(request.POST['person']))
model_instance.save()
return redirect('/tracking')
然而,form.is_valid()
永远不会 returns 正确。打印出错误让我对 form.errors
和 <bound method BaseForm.non_field_errors of <AddTrackingForm bound=False, valid=False, fields=(person;week;term;year;b1;b2;monday;tuesday;wednesday;thursday;friday)>>
对于 form.non_field_errors
.
空白
无论我怎么尝试,我都无法绑定实例。我认为可能 post 数据是作为字符串接收的,而不是 model.IntegerField()
的有效数据,所以我可能需要覆盖 form.clean()
并将所有相关字段转换为整数.但是,那没有用。还有什么可能导致我的表单无法绑定到实例?
更新
这是我的模板。表单位于 table 中,我进行了 Ajax 查询以确保在提交表单之前尚未输入数据:
<tbody>
<tr>
<form id="tracking_form" method="POST" action="/tracking">
{% csrf_token %}
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
<td><input type="button" class="btn btn-default" onclick="submitIfUnique()" value="Add Points"></td>
</form>
</tr>
</tbody>
...
<script>
var form_data = {
'person': $('#id_person').val(),
'year': $('#id_year').val(),
'term': $('#id_term').val(),
'week': $('#id_week').val(),
};
$.ajax({
url: "/api/tracking/is_unique",
method: "GET",
dataType: "json",
data: form_data,
success: function(response){
var form = $('#tracking_form');
var submit = true;
if(!response['is_unique']){
confirm = confirm("This data has already been entered for " + response['person'] + ". Are you sure you want to overwrite this?");
if(!confirm){ submit = false; }
}
if(submit){ form.submit(); }
}
});
</script>
我知道表单提交正确,因为我可以打印出 TrackingView.post()
中请求的所有数据。为了完整起见,这是在浏览器中呈现模板后的表单:
<form id="tracking_form" method="POST" action="/tracking">
<input type='hidden' name='csrfmiddlewaretoken' value='EZ...Uc' />
<td><select name="person" required id="id_person">
<option value="18" selected>Test Person 1</option>
<option value="19">Test Person 2</option>
</select></td>
<td><select name="week" required id="id_week">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></td>
<td><select name="term" required id="id_term">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></td>
<td><select name="year" required id="id_year">
<option value="2017">2017</option>
<option value="2018">2018</option>
</select></td>
<td><input type="text" name="target" required id="id_target" /></td>
<td><input type="number" name="monday" min="0" max="100" required id="id_monday" /></td>
<td><input type="number" name="tuesday" min="0" max="100" required id="id_tuesday" /></td>
<td><input type="number" name="wednesday" min="0" max="100" required id="id_wednesday" /></td>
<td><input type="number" name="thursday" min="0" max="100" required id="id_thursday" /></td>
<td><input type="number" name="friday" min="0" max="100" required id="id_friday" /></td>
<td><input type="button" class="btn btn-default" onclick="submitIfUnique()" value="Add Points"></td>
你误解了你得到的输出。形式 是 绑定的,否则 form.errors
将不起作用。但是 non_field_errors
是一个 方法 ,你需要调用它:form.non_field_errors()
.
主要问题是您总是在 post 之后重定向,即使表单无效也是如此。你应该只在 有效时这样做;否则,您应该重新显示具有无效表单的模板。此外,您应该在该模板中显示 {{ form.errors }}
。
另请注意,您使用了错误的视图基础class; CreateView 将完成您的代码所做的一切,包括在出错时重新显示表单。通常,如果您发现自己在基于 class 的视图上覆盖了 get
和 post
,那么您做错了什么。
我有以下型号:
class Tracking(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
week = models.IntegerField(choices=settings.WEEK_CHOICES, blank=True)
term = models.IntegerField(choices=settings.TERM_CHOICES, blank=True)
year = models.IntegerField(choices=settings.YEAR_CHOICES, blank=True)
target = models.CharField(max_length=256, blank=True)
monday = models.IntegerField()
tuesday = models.IntegerField()
wednesday = models.IntegerField()
thursday = models.IntegerField()
friday = models.IntegerField()
链接到此表单:
class AddTrackingForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AddTrackingForm, self ).__init__(*args, **kwargs)
class Meta:
model = models.Tracking
fields = '__all__'
用户填写表单后,我想将实例保存到数据库中:
class TrackingView(generic.TemplateView):
template_name = "tracking.html"
def get(self, request, *args, **kwargs):
form = forms.AddTrackingForm()
form.fields['person'].queryset = models.Person.objects.filter(active=True).order_by('-last_name', '-first_name')
return render(request, self.template_name, {'form': form, })
def post(self, request, *args, **kwargs):
form = forms.AddTrackingForm(request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.person = models.Person.objects.get(id=int(request.POST['person']))
model_instance.save()
return redirect('/tracking')
然而,form.is_valid()
永远不会 returns 正确。打印出错误让我对 form.errors
和 <bound method BaseForm.non_field_errors of <AddTrackingForm bound=False, valid=False, fields=(person;week;term;year;b1;b2;monday;tuesday;wednesday;thursday;friday)>>
对于 form.non_field_errors
.
无论我怎么尝试,我都无法绑定实例。我认为可能 post 数据是作为字符串接收的,而不是 model.IntegerField()
的有效数据,所以我可能需要覆盖 form.clean()
并将所有相关字段转换为整数.但是,那没有用。还有什么可能导致我的表单无法绑定到实例?
更新 这是我的模板。表单位于 table 中,我进行了 Ajax 查询以确保在提交表单之前尚未输入数据:
<tbody>
<tr>
<form id="tracking_form" method="POST" action="/tracking">
{% csrf_token %}
{% for field in form %}
<td>{{ field }}</td>
{% endfor %}
<td><input type="button" class="btn btn-default" onclick="submitIfUnique()" value="Add Points"></td>
</form>
</tr>
</tbody>
...
<script>
var form_data = {
'person': $('#id_person').val(),
'year': $('#id_year').val(),
'term': $('#id_term').val(),
'week': $('#id_week').val(),
};
$.ajax({
url: "/api/tracking/is_unique",
method: "GET",
dataType: "json",
data: form_data,
success: function(response){
var form = $('#tracking_form');
var submit = true;
if(!response['is_unique']){
confirm = confirm("This data has already been entered for " + response['person'] + ". Are you sure you want to overwrite this?");
if(!confirm){ submit = false; }
}
if(submit){ form.submit(); }
}
});
</script>
我知道表单提交正确,因为我可以打印出 TrackingView.post()
中请求的所有数据。为了完整起见,这是在浏览器中呈现模板后的表单:
<form id="tracking_form" method="POST" action="/tracking">
<input type='hidden' name='csrfmiddlewaretoken' value='EZ...Uc' />
<td><select name="person" required id="id_person">
<option value="18" selected>Test Person 1</option>
<option value="19">Test Person 2</option>
</select></td>
<td><select name="week" required id="id_week">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></td>
<td><select name="term" required id="id_term">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></td>
<td><select name="year" required id="id_year">
<option value="2017">2017</option>
<option value="2018">2018</option>
</select></td>
<td><input type="text" name="target" required id="id_target" /></td>
<td><input type="number" name="monday" min="0" max="100" required id="id_monday" /></td>
<td><input type="number" name="tuesday" min="0" max="100" required id="id_tuesday" /></td>
<td><input type="number" name="wednesday" min="0" max="100" required id="id_wednesday" /></td>
<td><input type="number" name="thursday" min="0" max="100" required id="id_thursday" /></td>
<td><input type="number" name="friday" min="0" max="100" required id="id_friday" /></td>
<td><input type="button" class="btn btn-default" onclick="submitIfUnique()" value="Add Points"></td>
你误解了你得到的输出。形式 是 绑定的,否则 form.errors
将不起作用。但是 non_field_errors
是一个 方法 ,你需要调用它:form.non_field_errors()
.
主要问题是您总是在 post 之后重定向,即使表单无效也是如此。你应该只在 有效时这样做;否则,您应该重新显示具有无效表单的模板。此外,您应该在该模板中显示 {{ form.errors }}
。
另请注意,您使用了错误的视图基础class; CreateView 将完成您的代码所做的一切,包括在出错时重新显示表单。通常,如果您发现自己在基于 class 的视图上覆盖了 get
和 post
,那么您做错了什么。