对于我的项目,我需要许多“工作流程”表单。我解释一下自己:
用户在第一个字段中选择一个值,根据第一个字段值验证表单和新字段。然后,根据其他字段,可以显示新字段...
如何以通用方式实现?
答案 0 :(得分:3)
我认为您正在寻找的解决方案是django form wizard
基本上,您可以为不同的页面定义单独的表单,并根据之前屏幕中的输入自定义下一个表单,最后,您可以将所有表单的数据放在一起。
具体看一下表单向导上的process step高级选项。
FormWizard.process_step()
"""
Hook for modifying the wizard's internal state, given a fully validated Form object. The Form is guaranteed to have clean, valid data.
This method should not modify any of that data. Rather, it might want to set self.extra_context or dynamically alter self.form_list, based on previously submitted forms.
Note that this method is called every time a page is rendered for all submitted steps.
The function signature:
"""
def process_step(self, request, form, step):
# ...
如果您只需要根据同一表单中的其他下拉菜单修改下拉列表值,您应该查看已实施的 dajaxproject
答案 1 :(得分:1)
我认为这取决于问题的严重程度。
您可以编写一些显示和隐藏表单字段的通用JavaScript(然后在表单本身中应用这些css类)。这对于显示和隐藏字段的数量相对较少很有效。
如果你想要更进一步,你需要考虑在Django中开发动态表单。我建议你不要像Ghislain建议的那样修改课堂上的['field']。这里有一篇关于dynamic forms的好文章,它向您展示了一些方法。
我认为一个好的解决方案可能是将上面帖子中的动态表单与django FormWizard结合起来。 FormWizard将引导您完成各种不同的表单,然后允许您在最后保存整个数据。
它有一些陷阱,因为你不能轻易地退回一步而不会丢失你的步骤数据。同时显示所有表单将需要对FormWizard进行一些自定义。有些API没有记录或被认为是公开的(所以要警惕它在Django的未来版本中的变化)但是如果你看一下the source你可以很容易地扩展和覆盖表单向导的部分来做你的事情需要。
最后一个更简单的FormWizard方法是说5个静态表单,然后在向导中自定义表单选择并更改下一个表单,只显示相关表单。这又可以很好地运作,但这取决于形式在以前的选择上有多大变化。
希望有所帮助,如有任何问题可以提出任何问题!
答案 2 :(得分:-1)
听起来你想要一个AJAXy类型的解决方案。查看Taconite plugin以获取jQuery。我用这个来填充表格上的下拉等。工作得非常好。
至于“通用”......您可能在容器类上有标准方法返回子项列表,然后有一个模板片段知道如何以某种“标准”方式格式化它。
答案 3 :(得分:-1)
好的,我找到了一个根本不使用ajax的解决方案,对我来说似乎很好看:
根据需要创建任意数量的表单,并使它们成为彼此的子类。将整数隐藏字段放入第一个:
class Form1(forms.Form):
_nextstep = forms.IntegerField(initial = 0, widget = forms.HiddenInput())
foo11 = forms.IntegerField(label = u'First field of the first form')
foo12 = forms.IntegerField(label = u'Second field of the first form')
class Form2(Form1):
foo21 = forms.CharField(label = u'First field of the second form')
class Form3(Form2):
foo31 = forms.ChoiceField([],
label=u'A choice field which choices will be completed\
depending on the previous forms')
foo32 = forms.IntegerField(label = u'A last one')
# You can alter your fields depending on the data.
# Example follows for the foo31 choice field
def __init__(self, *args, **kwargs):
if self.data and self.data.has_key('foo12'):
self.fields['foo31'].choices = ['make','a','nice','list',
'and you can','use your models']
好的,现在这里的表格就是视图:
def myview(request):
errors = []
# define the forms used :
steps = [Form1,Form2,Form3]
if request.method != 'POST':
# The first call will use the first form :
form = steps[0]()
else:
step = 0
if request.POST.has_key('_nextstep'):
step = int(request.POST['_nextstep'])
# Fetch the form class corresponding to this step
# and instantiate the form
klass = steps[step]
form = klass(request.POST)
if form.is_valid():
# If the form is valid, increment the step
# and use the new class to create the form
# that will be displayed
data = form.cleaned_data
data['_nextstep'] = min(step + 1, len(steps) - 1)
klass = steps[data['_nextstep']]
form = klass(data)
else:
errors.append(form.errors)
return render_to_response(
'template.html',
{'form':form,'errors':errors},
context_instance = RequestContext(request))
我看到的唯一问题是,如果在模板中使用{{form}},它会调用form.errors,因此会使用前一个(Form1)的数据自动验证新表单(例如Form2)。所以我所做的就是遍历表单中的项目,只使用{{item.id}},{{item.label}}和{{item}}。由于我已经在视图中获取了上一个表单的错误并将其传递给模板,因此我添加了一个div以在页面顶部显示它们。