需要澄清使用Django 1.4表单向导,特别是预先填充和保存 [英] Need clarification on using Django 1.4 Form Wizards, specifically pre-filling and saving

查看:100
本文介绍了需要澄清使用Django 1.4表单向导,特别是预先填充和保存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用Django 1.4的新表单向导功能构建一个向导。

这个文档很简洁,我们找不到任何高级示例。我们使用命名步骤向导(需要支持我们使用的listview / datagrid)和会话后端。
该向导旨在编辑角色和链接权限,并构建为提供添加和编辑功能。我们通过第一步询问用户是否要添加或编辑来做到这一点。

We are building a wizard using Django 1.4's new form wizard functionality.
The docs on this are very terse and we can't find any advanced examples. We are using a named step wizard (needed to support a listview/datagrid we use) and a session backend. The wizard is meant to edit roles and linked rights and is built to provide both add and edit functionality. We do this by asking the user in the first step if he/she wants to add or edit.

下一步依赖于这个选择;
如果用户想要编辑,则有一个搜索屏幕,其后是 listview / datagrid 显示结果。然后,用户可以选择其中一个结果并转到详细信息屏幕,然后选择一个 FilteredSelectMultiple 页面,允许他/她将权限链接到此角色。

The next step depends on that choice; If the user wants to edit, there is a search screen, followed by a listview/datagrid that displays results. The user can then select one of the results and goes to a details-screen, followed by a FilteredSelectMultiple page, allowing him/her to link rights to this role.

如果用户想要添加新角色,则会跳过搜索结果屏幕,用户直接进入详细屏幕,然后是链接屏幕。 br>
这一切都很好,在urls.py中使用了一个 condition_dict ,但是我们想知道一些关于一般功能的几个方面:

If the user wants to add a new role, the search and results screens are skipped and the user goes directly to the details screen, followed by the link-screen.
It all works pretty well, using a condition_dict in urls.py, but we are wondering a couple of things about the general functionality:

当选择一个特定的预先存在的角色时,我们如何用相应的数据填充细节和链接屏幕?

When a specific pre-existing role is selected, how can we fill the details and the link-screen with the corresponding data?

我们实例化一个角色对象,并以某种方式将其传递给两种形式,如果是这样,我们在哪里实例化,我们需要分别为每个表单(这似乎有点超过顶部)?

Do we instantiate a roles-object and pass it somehow to the two forms, if so, where do we instantiate it and do we need to do that for every form separately (which seems a bit over the top)?

保存时,创建角色对象的另一个实例是通常的做法,将表单数据添加到其中并保存,或者我们可以重新使用形式不知何故?

When saving, is it common practice to create another instance of a role object, add the form data to it and save, or can we re-use the object used in the forms somehow?

我们已经尝试重载 get_form_instance 以返回角色实例,我们在文档中查看了 instance_dict 但是感觉是错误的做法,没有在线查找的例子,我们甚至不确定这些用于预先填写数据,即使我们处于正确的轨道。

We have tried overloading get_form_instance to return instances of roles, and we have looked at instance_dict in the docs, but it feels like the wrong approach and there are no examples to be found online, and we're not even sure these are used to pre-fill data or even if we're on the right track.

在逻辑上,我会在选择现有角色的步骤中说,我需要使用所选对象的实例填充向导变量,并且这些变量显示在表单中。在向导结束时,我们反转进程,并从向导变量中获取所有数据,并将其添加到新实例化的角色对象中并保存。理想情况下,这个实例将决定自己是否需要执行INSERT或UPDATE,这取决于是否填写了promire密钥。

Logically, I would say in the step that selects an existing role, I need to fill the wizard-variables using an instance of the chosen object, and these get displayed in the forms. At the end of the wizard we reverse the process and get all data from the wizard-variables and add them to a newly instantiated roles-object and save it. Ideally this instance will determine itself if it needs to perform an INSERT or an UPDATE, depending on whether or not the promary key is filled.

如果有人可以提供一个例子,或者以正确的方向进行微调,那将是非常感激的。

If anyone can provide an example, or a nudge in the right direction, it would be very much appreciated.

view.py中的wizardview类的代码如下:

The code of the wizardview class in views.py is below:

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/')


推荐答案

对于未来的Google员工:

For future googlers:

我使用get_form()取得了一些成功,因为它在呈现表单之前被调用。从几个ModelForms开始:

I had some success with using get_form() because it is called before a form is rendered. Start with a couple of ModelForms:

class Wizard1(models.ModelForm): 
    class Meta:
        model = MyModel
        fields = ('field0', 'model0')
class Wizard2(models.ModelForm): 
    class Meta:
        model = MyModel
        excludes = ('field0', 'model0')

然后,在你的SessionWizardView中:

Then, in your 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中的验证数据(触发另一个调用get_form()来执行步骤0,因此请小心),然后可以访问在步骤0中设置的任何值。

The action is all in step 1. You request validated data from step 0 (which triggers another call to get_form() for step 0, so be careful) and then you can access any values that were set in step 0.

我扔了几个可以在字段上改变的设置的例子。您可以更新一个查询器来限制ChoiceField中的值,或者再次重新显示一个值,但是使其成为只读。一个警告我注意到... readonly不工作在ChoiceField。您可以将其禁用,但是当您提交表单时,该值不会传播。

I threw in a couple of examples of settings you can change on the fields. You can update a queryset to limit the values in a ChoiceField, or re-display a value again but make it read-only. One caveat I noticed... readonly does not work on ChoiceField. You can make it disabled, but then the value is not propagated when you submit the form.

这篇关于需要澄清使用Django 1.4表单向导,特别是预先填充和保存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆