【问题标题】:Django: How to add an extra form to a formset after it has been constructed?Django:如何在表单集构建后添加额外的表单?
【发布时间】:2011-06-24 10:50:06
【问题描述】:

这大致就是我想要做的:

def post(request):
    VehicleFormSet = formset_factory(StaffVehicleForm)
    if request.method == 'POST':
        vehicle_formset = VehicleFormSet(request.POST)
        if 'add_vehicle' in request.POST:
            if vehicle_formset.is_valid():
                form_count = vehicle_formset.total_form_count()
                vehicle_formset.forms.append(vehicle_formset._construct_form(form_count))

基本上,如果用户单击“添加”按钮并且他们的条目有效,我想将另一个空白表单添加到表单集中,并隐藏前一个。

上面代码的问题是我不知道如何增加total_form_count()。我现在的方式,它会工作一次,然后如果你再次按下它,什么都不会发生,大概是因为form_count 是一样的。我也不喜欢打电话给_construct_form 依赖内部。

【问题讨论】:

    标签: django django-forms


    【解决方案1】:
    class RequiredFormSet(BaseFormSet):
        def add_form(self, **kwargs):
            # add the form
            tfc = self.total_form_count()
            self.forms.append(self._construct_form(tfc, **kwargs))
            self.forms[tfc].is_bound = False
    
            # make data mutable
            self.data = self.data.copy()
    
            # increase hidden form counts
            total_count_name = '%s-%s' % (self.management_form.prefix, TOTAL_FORM_COUNT)
            initial_count_name = '%s-%s' % (self.management_form.prefix, INITIAL_FORM_COUNT)
            self.data[total_count_name] = self.management_form.cleaned_data[TOTAL_FORM_COUNT] + 1
            self.data[initial_count_name] = self.management_form.cleaned_data[INITIAL_FORM_COUNT] + 1
    
        def add_fields(self, form, index):
            super(RequiredFormSet, self).add_fields(form, index)
            form.empty_permitted = False
    

    这样就可以了。只用了7个小时就搞清楚了。而且我仍然不知道为什么我需要.is_bound = False 来使初始值不会搞砸。

    【讨论】:

    • is_bound 应该始终为 False,除非您的表单绑定到提交的 POST(或获取)数据。
    • @Humphrey:是的……确实如此。整个表单集是。不过,我不希望绑定尚未添加的空白表单。
    • @mpen 我应该如何调用这个方法以及从哪里得到 TOTAL_FORM_COUNT 和其他变量。
    • @CrazyGeek 不知道。这是我 6 年前写的。对不起
    • 感谢您提供时间提示,有时我觉得几行字就没有时间了,这让我很担心!
    【解决方案2】:

    我使用 javascript 执行此操作。由于formset渲染了三个管理字段

    <input type="hidden" id="id_TOTAL_FORMS" value="1" name="TOTAL_FORMS">
    <input type="hidden" id="id_INITIAL_FORMS" value="1" name="INITIAL_FORMS">.
    <input type="hidden" id="id_MAX_NUM_FORMS" name="MAX_NUM_FORMS">
    

    您可以使用 javascript 来增加 id_TOTAL_FORMS 值,然后添加额外的字段。所以我会像这样创建我的字段集:

    VehicleFormSet = modelformset_factory(StaffVehicleForm, extra = 0, max_num = None)
    

    棘手的是在 javascript 中创建额外的表单字段。我通常使用 AJAX 从自定义视图中获取新行。

    【讨论】:

    • BaseFormSet 上的 empty_form 属性可能在这里有用。 docs.djangoproject.com/en/1.2/topics/forms/formsets/#empty-form “返回一个前缀为 __prefix__ 的表单实例,以便更轻松地在带有 JavaScript 的动态表单中使用”我认为您可以将其作为模板进行克隆。
    • 哦,好的提示 Reiner Gerecke!下次我肯定会使用它:-)
    • @Reiner:如果绑定了表单集,则 empty_form 不尊重表单字段的默认值......一个相当烦人的错误(表单将完全空白,而不是包含默认值)。跨度>
    • 我如何调用我的视图并要求它向我发送一个额外的表单,因为我的表单包含几个下拉字段和很多数据库绑定选项?您能告诉我们您是如何使用 AJAX 从自定义视图中获取一行的吗?谢谢!
    【解决方案3】:

    对于后代来说,这是另一种在没有 JS(或与 JS 一起)的情况下工作的方式,它不需要深入了解 formset 方法。相反,您可以只检查 POST 数据并对其进行调整,就好像 JS 在客户端完成了一些工作一样。以下确保在表单集的末尾始终(至少)有一个空表单:

    def hsview( request):
        HS_formset = formset_factory( HSTestForm, extra=3 )
        prefix='XYZZY'
        testinpost, empty = 'key', ''  # field in the form and its default/empty value
        extra=3
    
    # I prefer to do the short init of unbound forms first, so I invert the usual test ...   
        if request.method != 'POST':
    
            formset = HS_formset( prefix=prefix)
        else:
           # process POSTed forms data. 
           # pull all relevant things out of POST data, because POST itself is not mutable
            # (it doesn't matter if prefix allows in extraneous items)
    
            data = { k:v for k,v in request.POST.items() if k.startswith(prefix) } 
    
            #if there are no spare empty forms, tell it we want another form, in place of or extra to client-side JS
            #don't want to crash if unvalidated POST data is nbg so catch all ...
            try:
                n = int( data[ prefix + '-TOTAL_FORMS']) 
                test = '{}-{}-{}'.format(prefix, n-1, testinpost)
                #print(test)
                test = data.get( test, empty)
            except Exception:
                test = 'bleagh'
                # log the error if it matters enough ...
            if test != empty: 
                data[ prefix + '-TOTAL_FORMS'] = n + 1 
    
            # now the usual formset processing ...
            formset = HS_formset( data, prefix=prefix)
            # other_form = OtherForm( request.POST)
            if formset.is_valid(): 
                ...            
    

    【讨论】:

      【解决方案4】:

      我在 Vue.js 方法中使用 RegEx:

      addForm: function () {
          this.count++
          let form_count = this.count
          form_count++
      
          let formID = 'id_form-' + this.count
          incremented_form = this.vue_form.replace(/form-\d/g, 'form-' + this.count)
          this.formList.push(incremented_form)
          this.$nextTick(() => {
              let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
              (function (ele, idx) {
                  ele.value = form_count
              })
          })
      },
      
      delForm: function () {
          if (this.count != 0) {
              this.count--
              let form_count = this.count
              form_count++
      
              let formID = 'id_form-' + this.count
              this.formList.pop()
              this.$nextTick(() => {
                  let total_forms = document.getElementsByName('form-TOTAL_FORMS').forEach
                  (function (ele, idx) {
                      ele.value = form_count
                  })
              })
          }
          else return
      },
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-16
        • 2018-01-24
        • 1970-01-01
        • 1970-01-01
        • 2011-06-04
        • 1970-01-01
        • 2011-07-04
        • 2012-07-14
        相关资源
        最近更新 更多