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

上一篇: 如何以编程方式在Android中创建和阅读WEP / EAP WiFi配置?

下一篇: Django:创建类似于django admin的内联表单