【问题标题】:Django formset error: select fields cause partially filled formsDjango formset错误:选择字段导致部分填写的表单
【发布时间】:2016-11-28 23:26:20
【问题描述】:

我有一个表单,它利用了我创建了一个表单集的选择参数。当呈现包含表单集的页面时,使用选项参数的字段显示下拉选择小部件。用户填写的表格没有错误。但是,用户未填写的表单对于所有其他字段都有“此字段是必需的”错误,但使用选择小部件的字段除外。

似乎选择字段的初始值导致表单被视为半填表单,因此表单验证过程会为未填写的必填字段引发错误。

# Form:
class OwnerForm(forms.Form):
    name = forms.CharField(label = 'Name', max_length = 20)
    owner_entity = forms.ChoiceField(label = 'Owner Entity', choices = OWNER_ENTITIES)
    num_of_shares = forms.DecimalField(label = 'Number of Shares' , min_value = 0.0, max_digits = 5, decimal_places = 2)
    share_class = forms.ChoiceField(label = 'Share Class', choices = SHARE_CLASSES)
    joined_date = forms.DateField(label = 'Joined Date', help_text = 'mm/dd/yyyy')

# View:
#    In Get method:
OwnersFormSet = formset_factory(OwnerForm, extra = 5)
...

#    In Post method:
the_owners_forms = OwnerFormSet(request.POST)

if not the_owners_forms.is_valid():
    the_owners_forms_errors = the_owners_forms.errors

那么,问题是我该如何处理这种行为,以使未填充的表单不会因为 select 方法的初始值而被视为 hal 填充的表单?

【问题讨论】:

  • 我在发布问题之前确实尝试过,但没有奏效。我在 OWNER_ENTITIES 中添加了一个 (None, '------------'),但它跳过了这个并选择了元组中的下一个元素。我的想法是在收到表单时手动删除这些初始值并在手动修改后运行 is_valid。
  • 如果你想使用 javascript,我有一个更优雅的解决方案来解决你的问题
  • 非常欢迎您的解决方案!我也想知道如何使用 Django 解决这个问题。

标签: django forms django-forms django-views


【解决方案1】:

你的forms.py这个怎么样?

默认情况下,您的 Select 字段将具有“------”作为值,并且在处理表单时将被视为无效。

EMPTY_CHOICE = ((None, '-------------),)

class OwnerForm(forms.Form):
    ...
    owner_entity = forms.ChoiceField(label = 'Owner Entity', choices = EMPTY_CHOICE + OWNER_ENTITIES)
    ...
    share_class = forms.ChoiceField(label = 'Share Class', choices = EMPTY_CHOICE + SHARE_CLASSES)

【讨论】:

  • 请在原帖下查看我的评论:我在发布问题之前确实尝试过,但没有成功。
【解决方案2】:

因此,此解决方案与 javascript 相结合。所以,你不应该使用extra=5 来拥有更多的表格。如果您想添加更多表单,可以使用“添加更多”按钮:

在 template.html 上:

{{ the_owners_forms.management_form }}
{% for form in the_owners_forms.forms %}
    <div class='table'>
    <table class='no_error'>
        {{ form.as_table }}
    </table>
    </div>
{% endfor %}
<input type="button" value="Add More" id="add_more">
<script>
    $('#add_more').click(function() {
        cloneMore('div.table:last', 'form');
    });
function cloneMore(selector, type) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + type + '-TOTAL_FORMS').val();
    newElement.find(':input').each(function() {
        var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
        var id = 'id_' + name;
        $(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
    });
    newElement.find('label').each(function() {
        var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
        $(this).attr('for', newFor);
    });
    total++;
    $('#id_' + type + '-TOTAL_FORMS').val(total);
    $(selector).after(newElement);
}
</script>

让我们试试……

【讨论】:

    【解决方案3】:

    我解决这个问题的方法有点变通。但是,它有效。

    问题来了: 似乎选择字段的初始值导致表单被视为半填充表单,因此表单验证过程会为未填写的必填字段引发错误。

    解决方法如下: 只需复制您从真正填写的表单中收到的所有数据,而不是从具有选择的字段的表单中复制,而不是由用户真正填写。然后,重构 ManagementForm:

    formset_data = {'form-TOTAL_FORMS': total_forms,
                    'form-INITIAL_FORMS': initial_forms ,
                    'form-MAX_NUM_FORMS': max_num_forms,
                   }
    
    # Selectively get the data from the formset of the get request and build 
    # correct data into the formset_data by updating it:
    for form in formset:
        # formset_data.update(<the correct data>)
    
    OwnersFormsetCopy = formset_factory(form = OwnerForm, extra = extra_forms )        
    owners_formset_copy = OwnersFormsetCopy(formset_data)
    
    # Then, run is_valid() on the new formset to take advantage of 
    # Django's form validation utility
    

    【讨论】:

      猜你喜欢
      • 2015-02-11
      • 2017-07-30
      • 1970-01-01
      • 2018-08-04
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 2016-03-24
      • 2013-08-12
      相关资源
      最近更新 更多