【问题标题】:Django: how to change label using formset extra?Django:如何使用 formset extra 更改标签?
【发布时间】:2013-01-04 09:49:15
【问题描述】:

我使用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:

【问题讨论】:

    标签: python django django-forms formset


    【解决方案1】:

    我假设您希望第一个表单的结果确定第二个表单的字段数及其标签,您可能需要查看Django form wizards。但这是一种简单的非表单向导(可能不太理想/可维护)的方法,利用表单集的__init__ 方法来修改表单标签*:


    forms.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)
    

    views.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,所以你必须执行验证在这里并介绍验证逻辑,而不是把它放在一个地方——表单)。如果您需要在第一个表单中添加一个新字段,您可能最终不得不修改代码。因此,为什么我建议您查看form wizards


    【讨论】:

      【解决方案2】:

      我能想到的唯一方法是在将 FormSet 传递给您的模板之前在您的视图中调整它。

      您可以遍历不同的表单和标签并相应地更改它们的值。

      另一种可能的解决方案是将默认标签设置为“光束线名称-”。 在您的模板中执行类似

      {% for field in form %}
          <td>{{ field.label_tag }}{{ forloop.counter1 }}</td> 
      {% endfor %}
      

      【讨论】:

      • 我使用了 counter 它对两个标签都显示 1,1,如果我使用 counter1 没有任何反应,如果我使用 counter0 它对两个标签都显示 0,0。我不明白为什么会这样!
      猜你喜欢
      • 2021-09-26
      • 2014-05-09
      • 2014-05-31
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      • 2019-09-23
      • 1970-01-01
      相关资源
      最近更新 更多