Django: Create inline forms similar to django admin
this has been asked before, but not answered (from what I could find).
I have two models;
class Invoice(models.Model):
invoice_number = models.CharField(max_length=30)
invoice_date = models.DateField()
class LineItem(models.Model):
description = models.CharField(max_length=50)
unit_price = models.DecimalField(max_digits=9, decimal_places=2)
quantity = models.PositiveSmallIntegerField()
invoice = models.ForeignKey(Invoice)
In the django admin interface I have LineItem as an Inline to Invoice. This works well because I want to add my invoice line items at the same time as raising my invoice.
Are there example patterns on how similar nested/inline forms have been achieved in django applications? The view I would like to present to the user is similar to the admin interface where lineitems can be entered at the time of invoice creation.
Appreciate any guidance.
I've researched the few suggestions I received here, and have decided on a solution that is slightly different but very much on track with @rix suggestion of using django formsets; model based inlineformset.
I ended up using the django inlineformset_factory
for LineItems and kept Invoice as a standard ModelForm
.
My forms;
#forms.py
...
class LineItemForm(ModelForm):
class Meta:
model = LineItem
fields = ['description','unit_price','quantity']
class InvoiceForm(ModelForm):
class Meta:
model = Invoice
fields = ['invoice_date','invoice_number']
My view;
#views.py
...
def add_invoice(request):
LineItemFormSet = inlineformset_factory(Invoice, LineItem, form=LineItemForm, extra=5)
if request.method == 'POST':
invoice_form = InvoiceForm(request.POST, prefix='invoice')
lineitem_formset = LineItemFormSet(request.POST, request.FILES, prefix='line')
if invoice_form.is_valid() and lineitem_formset.is_valid():
invoice = invoice_form.save()
# I recreate my lineitem_formset bound to the new invoice instance
lineitem_formset = LineItemFormSet(request.POST, request.FILES, prefix='line', instance=invoice)
# I have to validate (again - so I'm confident) to access clean data
lineitem_formset.is_valid()
lineitem_formset.save()
if 'submit_more' in request.POST:
return HttpResponseRedirect(reverse('invoices:add_invoice'))
else:
return HttpResponseRedirect(reverse('invoices:get_invoices'))
else:
return render(request, 'invoices/invoice_add.html', {
'message' : "Check your form",
'invoice_form' : invoice_form,
'lineitem_formset' : lineitem_formset,
})
else:
invoice_form = InvoiceForm(prefix='invoice')
lineitem_formset = LineItemFormSet(prefix='line')
return render(request, 'invoices/invoice_add.html', {
'invoice_form' : invoice_form,
'lineitem_formset' : lineitem_formset,
})
Now, as suggested by @tr33hous, I'm playing with JS to add new inline forms.
I'm pretty happy with the outcome.
However, i'm wondering if there is a better way then creating and validating my inline formset to make sure it's all valid before saving my invoice and then recreating the formset object bound to the new invoice instance, not a major overhead, but it doesn't look as clean as it could.
I think you might be looking for formsets:
https://docs.djangoproject.com/en/dev/topics/forms/formsets/
链接地址: http://www.djcxy.com/p/65432.html