0

複数のフォームセットを使用するフォームがあります。フォームセット フォームは、JS を介して動的に追加されます。私は自分自身を助けるためにいくつかの異なる場所を見てきました。

javascriptを正しい方法で使用してdjangoフォームセットに動的フォームを追加する

Kevin Dias による素敵な投稿 - 複数のインライン フォームセットを使用した Django クラスベースのビュー

私が抱えている問題は、データを投稿すると外側のフォームにデータが含まれているが、ループを開始したときに実際に clean_data 辞書にデータが含まれていないフォームセットがないことです。私が見逃している可能性があるものについて何か考えはありますか? 2 番目のフォームセットは、非常によく似た 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;
    }
4

1 に答える 1

0

ここで問題を引き起こした 2 つの問題がありました。

  1. 各フォームセットのフォーム タグをレンダリングするクリスピー フォーム ヘルパーを用意しました。これは悪い考えです。form_tag = False を設定すると、それが修正されました。
  2. JavaScript を介して次のフォームを取得するために作成したビューのフォームセットにプレフィックス引数を設定するのを忘れていました。

これらの両方が実装されると、送信時にフォームからデータを利用できるようになりました。

于 2015-09-10T00:43:55.690 に答える