Django formsets没有发布数据

Posted

技术标签:

【中文标题】Django formsets没有发布数据【英文标题】:Django formsets no data on post 【发布时间】:2015-11-24 17:02:09 【问题描述】:

我有一个使用多个表单集的表单。 formset表单是通过JS动态添加的。我一直在寻找几个不同的地方来帮助自己。

Add a dynamic form to a django formset using javascript in a right way

A nice post by Kevin Dias - Django class-based views with multiple inline formsets

我遇到的问题是,当我发布数据时,外部表单有数据,但是当我开始循环遍历它们时,我的表单集实际上没有任何数据在 clean_data 字典中。关于我可能遗漏的任何想法?第二个formset添加了一个非常相似的JS方法。

表格

class ShippingForm(Form):
    is_partial = BooleanField(label='Partial?')


class ShippingActualProduct(Form):

    box_no = CharField(label='Box Number', max_length=3)
    upc = CharField(
        widget=forms.TextInput(attrs='class':'upcAjax'),
    )
    serial_no = CharField(
        label='Serial Number',
        widget=forms.TextInput(attrs='class':'serial'),
    )
    sku = CharField(
        widget=forms.TextInput(attrs='class':'skuAjax'),
    )
    description=CharField(label='Description')
    on_hand=CharField(label='On Hand')

    def __init__(self, *args, **kwargs):
        super(ShippingActualProduct,self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_show_labels = True
        self.helper.form_class = 'form-inline'


class ShippingNonInventoryProduct(Form):

    non_box_no = CharField(label='Box Number', max_length=3)
    quantity = IntegerField()
    description = CharField()
    serial_no = CharField()

    def __init__(self, *args, **kwargs):
        super(ShippingNonInventoryProduct,self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_show_labels = True
        self.helper.form_class = 'form-inline'



ActualProductFormSet = formset_factory(ShippingActualProduct, extra=1,       can_delete=True)
NonInventoryProductFormSet = formset_factory(ShippingNonInventoryProduct, extra=1, can_delete=True)

观看次数

    class ShippingCreate(FormView):
    template_name = 'jinja2/Shipping/shipping_create.html'
    form_class = ShippingForm
    success_url = reverse_lazy('shipping_create')


    def get_context_data(self, **kwargs):

        context = super(ShippingCreate, self).get_context_data(**kwargs)
        input_invoice_no = self.request.GET['invoice_no']
        try:
            self.object = Invoice.objects.get(invoice_no = input_invoice_no)
            context['invoice'] = self.object
        except Invoice.DoesNotExist:
            messages.error(self.request, 'We were unable to find invoice number %s, please try again' % input_invoice_no)

        try:
            context['voucher'] = Voucher.objects.get(voucher_no = self.object.voucher_no)
        except Voucher.DoesNotExist:
            messages.error(self.request, 'We were unable to find an installation voucher for claim number %s' % self.object.voucher_no)

        context['actual_items_forms'] = ActualProductFormSet(prefix='actual')
        context['non_inventory_items_forms'] = NonInventoryProductFormSet(prefix='non')
        context['form'] = ShippingForm()
        return context

    def get(self, request, *args, **kwargs):

        self.object = None
        context = self.get_context_data()
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        actual_product = ActualProductFormSet(self.request.POST, prefix='actual')
        non_inv_product = NonInventoryProductFormSet(self.request.POST, prefix='non')
        if actual_product.is_valid():
            for product in actual_product:
                data = product.cleaned_data
                sku = data.get('sku')
        context=
        return render(request, self.template_name, context)

模板

    % extends "base.html" %
% load crispy_forms_tags %
%  load static from staticfiles %
%  load socialaccount %
%  load sitetree %
% block headcss %
     block.super 
    <link rel="stylesheet" href="%  static "css/shipping.css" %">
% endblock headcss %
%  block headjs %
     block.super 
    <script src="%  static "js/shipping.js" %"></script>

%  endblock headjs %
% block content %
    % block messages %
         block.super 
    % endblock messages %

    <div class="container-fluid">
        <form action="." method="post">
            <div>
                <h3>Item information:</h3>
                        %  csrf_token %
                         actual_items_forms.management_form 
                        <div id="actual-items-form-container">
                        </div>
                        <a href="#" id="actual-item-btn" class="btn btn-info fa fa-plus-square add-item"> Add Item</a>
            </div>
            <div>
                <h3>Non Inventory Items Shipped:</h3>
                     non_inventory_items_forms.management_form 
                    <div id="non-inv-items-form-container">
                    </div>
                    <a href="#" id="add-non-inv-item-btn" class="btn btn-info fa fa-plus-square add-non-item"> Add Item</a>
            </div>
              form.as_p 
            <input type="submit" value="Complete" class="submit btn btn-success" />
        </form>

    </div>

    %  include "jinja2/hub/loading_modal.html" %
% endblock content %
</html>

JavaScript

    function getNewActualItemForm() 
        // unbind this ajax call from the overlay displayed when looking data up.
        $(document).unbind(".items");
        var count = $('#actual-items-form-container').children().length;
        $.get("/forms/actualitemform",function(data, status)
            var form = data.replace(/__prefix__/g, count);
            // Get the html contents of the form, all together to iterate over.
            var htmlForm = $('<form>').html(form).contents();
            // Just grab the children of that form
            var rows = htmlForm.children();
            // loop through the inputs locating the DELETE input and label.
            $(rows).each( function(index, value) 
                var row = $(this);
                var del = $(row).find('input:checkbox[id $= "-DELETE"]');
                // Only move forward if we have found the DELETE input
                if (del.length)
                    //Write the form ot the Dom so the search for the label will succeed.
                    $('div#actual-items-form-container').append(form);
                    var label ='label[for="id_form-' + count + '-DELETE"]';
                    $(label).hide();
                
            );

            // update form count
            $('#id_actual-TOTAL_FORMS').attr('value', count+1);

            // some animate to scroll to view our new form
            $('html, body').animate(
                scrollTop: $('#actual-item-btn').position().top-200
            , 800);

            // get the max box number.
            var maxBoxNo = getBoxNo();

            // Set focus to the next UPC
            var boxID = '#id_form-var-box_no';
            var upcID = '#id_form-var-upc';
            var nextBox = boxID.replace('var',count);
            var nextUpc = upcID.replace('var',count);
            // set the box number for the new line.
            $(nextBox).val(maxBoxNo);
            $(nextUpc).focus();


        );
        return count;
    

【问题讨论】:

你怎么知道的?您的 post 方法不会对清理后的数据执行任何操作,也不会将无效表单返回到模板。 对不起丹尼尔,我应该指定的。我使用 Pycharm 并使用他们的调试器逐步执行代码。这就是我停止在 Post 上继续前进的原因,因为我在表单集方面没有得到任何回报。 【参考方案1】:

这里有两个问题造成了麻烦。

    我让脆皮表单助手为每个表单集呈现表单标签。这是一个坏主意。设置 form_tag = False 解决了这个问题。 我忘记在我创建的视图中为我的表单集设置前缀参数,以便通过 JavaScript 获取下一个表单。

一旦实现了这两个,数据现在可以从提交的表单中获得。

【讨论】:

以上是关于Django formsets没有发布数据的主要内容,如果未能解决你的问题,请参考以下文章

Django CBV - Formsets:'NoneType'对象没有属性'id'

访问django formset数据

没有实例的 Django Formset

Django-dynamic-formsets 不工作

django InlineFormsets错误报告,其中formset错误列表为空

django 如何用formset 显示数据库里的经过 过滤的数据?用户资料和修改资料?