4

formset を使用して追加のフィールドを作成していますが、formset によって作成された追加のフィールドのラベルを変更する方法がわかりません。

私のコード:

class GetMachine(forms.Form):
    Number_of_Lines = forms.IntegerField(max_value=4)

class GetLine(forms.Form):
    beamline_name = forms.CharField(max_length=15, label='Name of Beamline-%i')

def install(request):
    MachineFormSet = formset_factory(GetMachine, extra=1)
    formset = MachineFormSet()
    if request.method == 'POST':
#        formset = MachineFormSet(request.POST) 
#        if formset.is_valid(): # All validation rules pass
        line_no = request.POST['form-0-Number_of_Lines']
        GetLineFormSet = formset_factory(GetLine, extra=int(line_no))
        formset = GetLineFormSet()
        return render_to_response('install.html', { 'formset': formset, 'action': 'step1'})
    return render_to_response('install.html', { 'formset': formset, })    

install.html テンプレート:

{% for form in formset.forms %}
{% for field in form %}
    <tr>
        <td>{{ field.label_tag }}</td>  <td>{{ field }}</td><td>{{ field.errors }}</td>
    </tr>
{% endfor %}
{% endfor %}

たとえば、「Number_of_Lines」= 2 の場合、ラベル付きの次のフォームが期待されます。

Name of Beamline-1:
Name of Beamline-2:
4

2 に答える 2

5

最初のフォームの結果で 2 番目のフィールドとそのラベルの数を決定する必要があると仮定しています。Django フォーム ウィザードを調べることをお勧めします。__init__しかし、フォームセットのメソッドを利用してフォームラベルを変更する、単純な非フォームウィザード(そしておそらく理想的/保守性が低い)方法を次に示します*:


フォーム.py:

# File: forms.py
from django import forms
from django.forms.formsets import BaseFormSet


# What you've called 'GetMachine'
class MachineForm(forms.Form):
    no_of_lines = forms.IntegerField(max_value=4)


# What you've called 'GetLine'
class LineForm(forms.Form):
    beamline_name = forms.CharField(max_length=15, label='Name of Beamline')


# Create a custom formset and override __init__
class BaseLineFormSet(BaseFormSet):
    def __init__(self, *args, **kwargs):
        super(BaseLineFormSet, self).__init__(*args, **kwargs)
        no_of_forms = len(self)
        for i in range(0, no_of_forms):
            self[i].fields['beamline_name'].label += "-%d" % (i + 1)

ビュー.py:

# File: views.py
from django.forms.formsets import formset_factory
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from forms import MachineForm, LineForm, BaseLineFormSet


def get_no_of_lines(request):
    if request.method == 'POST':
        machine_form = MachineForm(request.POST)
        if machine_form.is_valid():
            # At this point, form fields have already been 
            # converted to Python data types :)
            # so no need to convert `line_no` to an integer
            no_of_lines = machine_form.cleaned_data['no_of_lines']
            return HttpResponseRedirect(reverse('line_form', kwargs={'no_of_lines': no_of_lines}))
    else:
        # It looks to me like you probably don't mean to
        # use formsets here (but a form instead)
        machine_form = MachineForm()

    c = RequestContext(request, {
        'machine_form': machine_form,
    })
    return render_to_response('get_no_of_lines.html', c)


def line_form(request, no_of_lines):
    # You probably should validate this number (again).
    # In fact, you probably need to validate first form (MachineForm).
    # ...But I'm assuming it'll be valid in this example.
    no_of_lines = int(no_of_lines)
    LineFormSet = formset_factory(LineForm, extra=no_of_lines, formset=BaseLineFormSet)
    if request.method == "POST":
        formset = LineFormSet(request.POST, request.FILES)
        if formset.is_valid():
            pass
            # Do stuff with form submission
            # Redirect

    else:
        formset = LineFormSet()

    c = RequestContext(request, {
        'formset': formset,
    })
    return render_to_response('line_form.html', c)

urls.py:

from django.conf.urls import url, patterns
from views import get_no_of_lines, line_form


urlpatterns = patterns('',
     url(r'^$', get_no_of_lines, name='get_no_of_lines'),
     url(r'^line_form/(?P<no_of_lines>\d{1})$', line_form, name='line_form'),
)

get_no_of_lines.html:

<form method="POST">
{% csrf_token %}
{{ machine_form }}
</form>

line_form.html:

<form method="POST">
{% csrf_token %}
{{ formset.as_p }}

このアプローチがおそらくこれを行うための最良の方法ではないと私が言う理由は、ビューno_of_linesに渡されることを検証する必要があるためですline_form(4 を超える可能性があるため、ここで検証を実行し、検証ロジックを導入するのではなく、検証ロジックを導入する必要があります)。 1 か所 — フォーム)。また、最初のフォームに新しいフィールドを追加する必要がある場合は、コードを変更する必要が生じる可能性があります。したがって、フォームウィザードを調べることをお勧めします。


于 2013-01-26T11:35:11.317 に答える
0

この動作を実現する唯一の方法は、テンプレートに渡される直前にビューで FormSet を調整することです。

さまざまなフォームとラベルを反復処理し、それに応じて値を変更できます。

別の可能な解決策は、デフォルトのラベルを「ビームラインの名前-」に設定することです。そして、テンプレートで次のようにします

{% for field in form %}
    <td>{{ field.label_tag }}{{ forloop.counter1 }}</td> 
{% endfor %}
于 2013-01-21T11:14:37.870 に答える