我们正在使用Django 1.4的新表单向导功能构建向导 关于此的文档非常简洁,我们找不到任何高级示例。我们正在使用一个命名步骤向导(需要支持我们使用的listview / datagrid)和一个会话后端。 该向导用于编辑角色和链接权限,旨在提供添加和编辑功能。我们通过在第一步询问用户是否要添加或编辑来执行此操作。
下一步取决于该选择; 如果用户想要编辑,则会有一个搜索屏幕,然后是显示结果的listview/datagrid。然后,用户可以选择其中一个结果并转到详细信息屏幕,然后是FilteredSelectMultiple页面,允许他/她将权限链接到此角色。
如果用户想要添加新角色,则会跳过搜索和结果屏幕,用户会直接进入详细信息屏幕,然后是链接屏幕。
在urls.py中使用 condition_dict 这一切都很有效,但我们想知道关于一般功能的一些事情:
如果选择了特定的预先存在的角色,我们如何使用相应的数据填充详细信息和链接屏幕?
我们是否实例化一个角色对象并以某种方式将其传递给两个表单,如果是这样,我们在哪里实例化它,我们是否需要分别对每个表单执行此操作(这似乎有点过头)?
保存时,通常的做法是创建角色对象的另一个实例,将表单数据添加到它并保存,或者我们可以以某种方式重新使用表单中使用的对象吗?
我们已经尝试重载 get_form_instance 来返回角色的实例,我们已经在文档中查看了 instance_dict ,但感觉就像错误的方法而且没有示例在网上找到,我们甚至不确定这些是用来预先填充数据,甚至是在我们正确的轨道上。
逻辑上,我会说在选择现有角色的步骤中,我需要使用所选对象的实例填充向导变量,这些将显示在表单中。在向导结束时,我们反转该过程并从向导变量中获取所有数据,并将它们添加到新实例化的角色对象中并保存。理想情况下,如果需要执行INSERT或UPDATE,此实例将自行确定,具体取决于是否填充了前缀键。
如果有人可以提供一个例子,或者在正确的方向上轻推,那将非常感激。
views.py中wizardview类的代码如下:
class RolesWizard(NamedUrlSessionWizardView):
def get_template_names(self):
# get template for each step...
if self.steps.current == 'choice':
return 'clubassistant/wizard_neworeditrole.html'
if self.steps.current == 'search':
return 'clubassistant/wizard_searchrole.html'
if self.steps.current == 'results':
return 'clubassistant/wizard_pickrole.html'
if self.steps.current == 'details':
return 'clubassistant/wizard_detailsrole.html'
elif self.steps.current == 'rights':
return 'clubassistant/wizard_roles.html'
def get_context_data(self, form, **kwargs):
# get context data to be passed to the respective templates
context = super(RolesWizard, self).get_context_data(form=form, **kwargs)
# add the listview in the results screen
if self.steps.current == 'results':
# get search text from previous step
cleaned_data = self.get_cleaned_data_for_step('search')
table = RolesTable(Roles.objects.filter(
role_name__contains=cleaned_data['searchrole'])
)
RequestConfig(self.request, paginate={
"per_page": 4,
}).configure(table)
# add the listview with results
context.update({'table': table})
# add a role instance based on the chosen primary key
if self.steps.current == 'rights':
cleaned_data = self.get_cleaned_data_for_step('results')
role_id = cleaned_data['role_uuid']
role = get_object_or_404(Roles, pk=role_id)
context.update({'role': role})
return context
def done(self, form_list, **kwargs):
# this code is executed when the wizard needs to be completed
# combine all forms into a single dictionary
wizard = self.get_all_cleaned_data()
if wizard.get("neworeditrole")=="add":
role = Roles()
else:
role = get_object_or_404(Roles, pk=wizard.get("role_uuid"))
# many-to-many rights/roles
role.role_rights_new_style.clear()
for each_right in wizard.get('role_rights_new_style'):
RightsRoles.objects.create(role=role, right=each_right,)
# other properties
for field, value in self.get_cleaned_data_for_step('details'):
setattr(role, field, value)
role.save()
# return to first page of wizard...
return HttpResponseRedirect('/login/maintenance/roles/wizard/choice/')
答案 0 :(得分:2)
未来的googlers:
我使用get_form()取得了一些成功,因为它在呈现表单之前被调用。从几个ModelForms开始:
class Wizard1(models.ModelForm):
class Meta:
model = MyModel
fields = ('field0', 'model0')
class Wizard2(models.ModelForm):
class Meta:
model = MyModel
excludes = ('field0', 'model0')
然后,在SessionWizardView中:
class MyWizard(SessionWizardView):
def get_form(self, step=None, data=None, files=None):
form = super(ExtensionCreationWizard, self).get_form(step, data, files)
if step is not None and data is not None:
# get_form is called for validation by get_cleaned_data_for_step()
return form
if step == "0":
# you can set initial values or tweak fields here
elif step == "1":
data = self.get_cleaned_data_for_step('0')
if data is not None:
form.fields['field1'].initial = data.get('field0')
form.fields['field2'].widget.attrs['readonly'] = True
form.fields['field3'].widget.attrs['disabled'] = True
form.fields['model1'].queryset = Model1.objects.filter(name="foo")
return form
操作全部在步骤1.您从步骤0请求经过验证的数据(触发对步骤0的另一个get_form()调用,因此请小心)然后您可以访问在步骤0中设置的任何值。 / p>
我提供了几个可以在字段上更改的设置示例。您可以更新查询集以限制ChoiceField中的值,或者再次重新显示值,但将其设置为只读。我注意到一个警告...... readonly在ChoiceField上不起作用。您可以将其禁用,但在提交表单时不会传播该值。
答案 1 :(得分:1)
让我们看看我是否可以提供帮助。我做了一个表单向导,根据答案添加步骤。在每个步骤中,我将所有表单保存在会话变量中,如下所示:
def process_step(self, request, form, step):
request.session['form_list'] = self.form_list
request.session['initial'] = self.initial
然后,每次呈现该视图时,我都会实例化一个包含所有先前数据的新表单向导:
def dynamic_wizard(request):
if not request.session.get('form_list'):
form = Wizard([Form1])
else:
form = Wizard(request.session.get('form_list'), initial = request.session['initial'])
return form(context=RequestContext(request), request=request)