5

Django 1.4 の新しいフォーム ウィザード機能を使用してウィザードを構築しています。
これに関するドキュメントは非常に簡潔で、高度な例は見つかりません。名前付きステップ ウィザード (使用するリストビュー/データグリッドをサポートするために必要) とセッション バックエンドを使用しています。ウィザードは、ロールとリンクされた権限を編集することを目的としており、追加と編集の両方の機能を提供するように構築されています。これを行うには、最初のステップでユーザーに追加または編集するかどうかを尋ねます。

次のステップは、その選択によって異なります。ユーザーが編集したい場合は、検索画面があり、その後に結果を表示するリストビュー/データグリッドが続きます。次に、ユーザーは結果の 1 つを選択して詳細画面に移動し、続いてFilteredSelectMultipleページに移動して、権限をこのロールにリンクできるようにします。

ユーザーが新しい役割を追加したい場合、検索画面と結果画面はスキップされ、ユーザーは詳細画面に直接移動し、その後にリンク画面が続きます。urls.py でcondition_dict
を使用すると、すべてうまく機能しますが、一般的な機能についていくつか疑問があります。

特定の既存のロールが選択された場合、詳細とリンク画面に対応するデータをどのように入力できますか?

役割オブジェクトをインスタンス化し、それを何らかの方法で 2 つのフォームに渡しますか? もしそうなら、どこでインスタンス化し、フォームごとに個別にそれを行う必要がありますか?

保存するとき、ロール オブジェクトの別のインスタンスを作成し、それにフォーム データを追加して保存するのが一般的な方法ですか、それともフォームで使用されているオブジェクトを何らかの方法で再利用できますか?

ロールのインスタンスを返すために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/')
4

2 に答える 2

3

将来の Google 社員向け:

フォームがレンダリングされる前に呼び出されるため、 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 で設定された任意の値にアクセスできます。

フィールドで変更できる設定の例をいくつか紹介しました。クエリーセットを更新して ChoiceField の値を制限したり、値を再表示して読み取り専用にすることができます。私が気づいた1つの注意点... readonlyはChoiceFieldでは機能しません。無効にすることはできますが、フォームを送信しても値は反映されません。

于 2013-02-28T22:12:14.780 に答える
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)
于 2012-06-21T09:49:26.147 に答える