我有一个使用多个formset的表单。 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
我遇到的问题是,当我发布我的数据时,外部表单有数据,但是当我开始循环遍历时,我的表单集中没有任何数据实际上在cleaning_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;
}