2015-08-30 89 views
0

我有一個使用多個formset的表單。 formset表單是通過JS動態添加的。我一直在尋找幾個不同的地方來幫助自己。Django formset沒有帖子上的數據

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

我遇到的問題是,當我發表我的數據外形式有數據,但我的表單集的非實際擁有的cleaned_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> 

The 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; 
    } 
+0

你怎麼知道?您的'post'方法不會對已清理的數據執行任何操作,也不會將無效的表單返回給模板。 –

+0

對不起,丹尼爾,我應該指定。我使用Pycharm,並用他們的調試器逐步完成代碼。這就是爲什麼我停止向Post發展的原因,因爲我沒有爲Formset取回任何東西。 – grantk

回答

0

有兩個問題引起麻煩在這裏。

  1. 我有酥脆的形式助手爲每個formset呈現窗體標籤。這是一個壞主意。設置form_tag = False修正了這個問題。
  2. 我已經忘記在我創建的視圖中通過JavaScript抓取下一個表單時在我的表單集上設置前綴參數。

一旦這兩項都已實施,現在可以從提交的表單中獲得數據。