So I have a question about the form_valid for django-extra-views. I used the CreateWithInlinesView method to create a form with multiple inline formsets.
The base form called "Order" contains two different formsets, "Booking" and "Payment". An Order always has to include a minimum of one Booking but does not necessarily need to have a Payment when the Order is created.
The form for the Payment will be generated nonetheless. I would like to validate the Payment form on a "payment_amount" > 0. If no payment is made at the moment the order is created, no PaymentInline should be saved.
class BookingInline(InlineFormSetFactory):
model = Booking
form_class = BookingForm
prefix = 'booking_formset'
factory_kwargs = {
'extra': 0,
'min_num': 1,
'validate_min': True,
'can_delete': True
}
class PaymentInline(InlineFormSetFactory):
model = Payment
form_class = PaymentForm
prefix = 'payment_formset'
factory_kwargs = {
'extra': 1,
'min_num': 0,
'validate_min': False,
'can_delete': True
}
class OrderCreateView(NamedFormsetsMixin, CreateWithInlinesView):
model = Order
inlines = [BookingInline, PaymentInline]
inlines_names = ['booking_formset', 'payment_formset']
form_class = OrderForm
template_name = 'orders/order_form.html'
def get_success_url(self):
return reverse_lazy('order_detail', kwargs={'pk': self.object.pk})
def forms_valid(self, form, inlines):
"""
If the form and formsets are valid, save the associated models.
"""
self.object = form.save(commit=False)
self.object.created_by = self.request.user
form.save(commit=True)
for formset in inlines:
formset.save()
return HttpResponseRedirect(self.get_success_url())
So the logic would need to be something like the following, though I get an error saying 'Order' object has no attribute 'payment', since it is a reversed relation...
def forms_valid(self, form, inlines):
"""
If the form and formsets are valid, save the associated models.
"""
self.object = form.save(commit=False)
self.object.created_by = self.request.user
form.save(commit=True)
for booking_formset in inlines:
booking_formset.save()
for payment_formset in inlines:
if self.object.payment.amount > 0:
payment_formset.save()
else:
pass
return HttpResponseRedirect(self.get_success_url())
Does anyone know how to address the different formsets within the form?
Thanks in advance!
I'm not sure which fields are available on your formset but you could save with commit=False
then iterate over the un-committed payment instances to get the total payment amount.
def forms_valid(self, form, inlines):
booking_formset = inlines[0]
payment_formset = inlines[1]
self.object = form.save(commit=False)
self.object.created_by = self.request.user
form.save(commit=True)
booking_formset.save()
payments = payment_formset.save(commit=False)
total_payment = sum(payment.amount for payment in payments)
if total_payment > 0:
payment_formset.save()
return HttpResponseRedirect(self.get_success_url())
UPDATE:
The lines booking_formset in inlines:
and payment_formset in inlines:
will cause a problem. Assuming inlines
is a list you will be iterating over the list twice. It's the equivalent of doing below:
lst = [1, 2]
for x in lst:
print(x)
for y in lst:
print(y)
>>> 1
>>> 2
>>> 1
>>> 2