Update: Reading directly the django source code i got one undocumented missing piece to solve my problem. Thanks to Brandon that solved half of the problem by giving me one of the missing pieces. See my own answer to see my solution (i dont want to mix things here).
I have the following (simplified) models:
Order(models.Model):
status = models.CharField( max_length=25, choices=STATUS_CHOICES, default='PENDING')
total = models.DecimalField( max_digits=22, decimal_places=2)
def clean(self):
if self.estatus == 'PAID' or self.estatus == 'SENT':
if len(self.payment.all()) > 0:
raise ValidationError("The status cannot be SENT or PAID if there is no payment for the order")
Payment(models.Model):
amount = models.DecimalField( max_digits=22, decimal_places=2 )
order = models.ForeignKey(Order, related_name="payment")
def clean(self):
if self.amount < self.order.total or self.amount <= 0:
ValidationError("The payment cannot be less than the order total")
In my admin.py i have:
class paymentInline(admin.StackedInline):
model = Payment
max_num = 1
class OrderAdmin(admin.ModelAdmin):
model = Order
inlines = [ paymentInline, ]
The validation in the clean method of the Order does not work because there is no payment saved when the validation occurs (obviously it has not been saved to the database).
The validation inside the payment works fine (if editing or adding a new payment).
I want to validate if the order has a payment if the status is ‘PAID’ or ‘SENT’, but as i cannot doit the way is in the clean method.
My question is, how can i access the ‘payment.amount’ value entered by the user in the inline (payment) of the Order form, to accomplish my validation? (considering im in the clean method of the Order model)
After reading the django source code i found one property of the BaseInlineFormSet that contains the Parent Instance of the Inline, in my case, the Order instance being edited.
Brandon gave me another important piece, iterating over the self.forms of the BaseInlineFormSet to get each of the instances (even not saved or not cleaned or empty), in my case, each Payment Instance being edited.
These are the two pieces of information needed to check if the Order with status ‘PAID’ or ‘SENT’ has a payment or not. Iterate over the cleaned_data of the formset would not give Order data (i.e. when not changing the Order, just changing the Payment, or when not adding a Payment -and an empty Payment- but changing the Order) which is needed to decide to save the model if the order status is different than ‘PAID’ or ‘SENT’, so this method was discarded before.
The models are keep the same, I only modified the admin.py to add the next: