Django测试中Client.post提交表单提示字段必填问题排查
Django测试中Client POST表单无效,但浏览器提交正常的问题
问题详情
- 测试视图表单逻辑时,
Client().post提交的表单在视图中验证失败,但浏览器正常提交功能正常 form.errors提示name和address字段必填,但form.data中明明有对应值- 测试代码里提交前
form.is_valid()返回True,到了视图里却验证不通过
测试代码
@pytest.mark.django_db def test_add_bar_with_logged_in_user_form(setUpUser, django_user_model): from ..models.forms import BarForm from django.test import Client bar_name = "foo bar2" address = "2344 foo st" user = setUpUser client = Client() client.force_login(user=user) client.login(username=user.username, password=user.password, email=user.email) form = BarForm() form_data = { "name": bar_name, "address": address, } form = BarForm(data=form_data) assert form.is_valid() is True response = client.post(urls.reverse("add_bar"), form.data, content_type="application/x-www-form-urlencoded", follow=True) assert response.status_code == 200
视图相关代码
def add_bar(request): # If this is a POST then the user has submitted the form to add a new bar if request.method == "POST": active_user = auth.get_user(request) # Only logged in users should be able to submit if not active_user.is_authenticated: messages.error(request, "Must be logged in to do that") return HttpResponseForbidden("Authentication required") form = BarForm(request.POST) logger.info(f"*=-===-= form.data : {form.data}") if form.is_valid(): logger.info(f"*=-===-= form.data : {form.data}") cleaned_data = form.cleaned_data created_by_id = active_user.id bar_new = Bar.objects.create(**cleaned_data, submitted_by=active_user) messages.success( request, f" - Thanks! Bar submited.", ) return redirect("index") elif form.errors: errors = form.errors messages.error(request, "Form is invalid") logger.info(f"** test_add_bar_with_logged_in_user -> form.errors: {errors}") for error in form.errors: logger.info(f"** test_add_bar_with_logged_in_user -> error: {error}") logger.info(f"*=-===-= form.data : {form.data}") return redirect("index") elif form.non_field_errors(): for error in form.non_field_errors(): logger.info(f"** test_add_bar_with_logged_in_user -> error: {error}") return False
问题原因及解决方法
问题出在你用form.data作为POST数据传给Client。Django表单的data是QueryDict对象,直接传递它会因为QueryDict的特性(比如不可变性、内部格式),导致视图接收到的数据无法被表单正确解析,看似有值但实际未被识别。
修复步骤:
- 把POST请求里的
form.data换成原始的form_data字典:
response = client.post(urls.reverse("add_bar"), form_data, content_type="application/x-www-form-urlencoded", follow=True)
- 删掉测试中多余的
client.login(...)调用——client.force_login(user=user)已经完成了登录,重复调用没必要。
为什么这样能解决?
测试里实例化表单验证通过,说明表单逻辑本身没问题。但form.data是表单处理后的QueryDict,和原始字典的传递格式有差异,Client提交时用原始字典才能保证视图里的request.POST和浏览器提交的格式一致,表单就能正确读取字段值完成验证。
内容的提问来源于stack exchange,提问作者LtDan33
相关产品推荐
相关产品推荐

