题
我有一个 Web 报告,它使用 Django 表单(新表单)作为控制用于生成报告的查询的字段(开始日期、结束日期……)。我遇到的问题是,页面应该使用表单的初始值(未绑定)来工作,但除非我调用 is_valid(),否则我无法访问 clean_data 字段。但 is_valid() 在未绑定的表单上总是失败。
Django 的表单似乎是根据编辑数据的用例而设计的,因此未绑定的表单除了显示 HTML 之外并没有真正的用处。
例如,如果我有:
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
如果这是一个 GET (因为它是未绑定的), is_valid() 将失败,并且如果我这样做:
if request.method == 'GET':
form = MyForm()
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
第一次调用 do_query 会触发 form.cleaned_data 上的异常,该数据不是有效字段,因为尚未调用 is_valid()。看来我必须做这样的事情:
if request.method == 'GET':
form = MyForm()
do_query(form['start_date'].field.initial, form['end_date'].field.initial)
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
也就是说,没有用于在绑定表单和未绑定表单之间检索表单值的通用接口。
有谁看到更干净的方法来做到这一点?
解决方案
如果将此方法添加到表单类中:
def get_cleaned_or_initial(self, fieldname):
if hasattr(self, 'cleaned_data'):
return self.cleaned_data.get(fieldname)
else:
return self[fieldname].field.initial
然后你可以将你的代码重写为:
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.method.POST)
form.is_valid()
do_query(form.get_cleaned_or_initial('start_date'), form.get_cleaned_or_initial('end_date'))
其他提示
未绑定 表示没有与表单关联的数据(无论是初始的还是稍后提供的),因此验证可能会失败。正如其他答案(以及您自己的结论)中提到的,您必须提供初始值并检查绑定数据和初始值。
表单的用例是表单处理 和 验证,因此在访问之前您必须有一些数据进行验证 cleaned_data
.
您可以将初始值的字典传递给您的表单:
if request.method == "GET":
# calculate my_start_date and my_end_date here...
form = MyForm( { 'start_date': my_start_date, 'end_date': my_end_date} )
...
请参阅 官方表单API文档, ,他们展示了这一点。
编辑:根据其他用户的回答,也许这是最干净的解决方案:
if request.method == "GET":
form = MyForm()
form['start_date'] = form['start_date'].field.initial
form['end_date'] = form['end_date'].field.initial
else:
form = MyForm(request.method.POST)
if form.is_valid():
do_query(form.cleaned_data['start_date'], form.cleaned_data['end_date'])
不过我还没有尝试过;有人可以确认这有效吗?我认为这比创建新方法更好,因为这种方法不需要其他代码(可能不是由您编写)来了解新的“神奇”访问器。
不隶属于 StackOverflow