Validation errors on foreign keys...


I would appreciate any help in debugging the following issue. I have the following model:

class Business(models.Model):
    name = models.CharField('Affaire',max_length=200, null = True, blank=True)
    customer = models.ForeignKey(Company,related_name = 'customer',on_delete=models.CASCADE,verbose_name='Client')
    beneficiary = models.ForeignKey(Company,related_name = 'beneficiary', on_delete=models.CASCADE,verbose_name='Bénéficiaire',
       null = True,blank = True)
    customer_ref = models.CharField('Référence client', max_length=250, 
        null=True, blank=True)
    framework_agreement = models.ForeignKey(Framework_agreement, on_delete=models.SET_NULL, verbose_name='Accord-cadre', null=True, blank=True)
    po_market = models.ForeignKey(PO_market, on_delete=models.SET_NULL, verbose_name='Marché à bons de commande', null=True, blank=True)
    default_contact = models.ForeignKey(Contact, related_name = 'set_business_contact', on_delete=models.SET_NULL, \
        null=True, blank=True, verbose_name='Contact client par défaut:')   
    default_addressee = models.ForeignKey(Contact, related_name="set_business_adressee" ,on_delete=models.SET_NULL, \
        null=True, blank=True, verbose_name='Destinataire par défaut:')
    default_address =models.ForeignKey(Address, on_delete=models.SET_NULL, \
        null=True, blank=True, verbose_name='Adresse par défaut:')
    account_exec = models.ForeignKey(Account_exec,on_delete=models.SET_NULL, null = True, blank = True, verbose_name='Chargé d\'affaires')
    amount = models.DecimalField('Montant',max_digits=9, decimal_places=2, null=True,blank=True)
    ponderation = models.ForeignKey(BusinessStatus, on_delete=models.RESTRICT, default=1)
    creation_date = models.DateField('Date de création',
    signature_date = models.DateField('Signée le', null = True, blank = True)
    expiration_date = models.DateField('Date de fin',null=True,blank=True)
    last_modification_date = models.DateTimeField('Date de dernière modification',
        auto_now= True,null = True, blank = True,)  
    vat_rate=models.ForeignKey(VATRates, on_delete=models.SET_NULL, null = True, blank = True)     

When I create a business, I’m getting validation error when I select a value for any foreign key field (I choose a value which is ok). I have notice that the field is ok in the request.POST, but is None in the method clean:

    def clean(self):
        print("CLEAN BUSINESS FORM")
        cleaned_data = super().clean()
        name = cleaned_data.get('name')
        amount = cleaned_data.get('amount')
        ponderation = cleaned_data.get('ponderation')
        signature_date = cleaned_data.get('signature_date')
        vat_rate = cleaned_data.get('vat_rate')
        framework_agreement = cleaned_data.get('framework_agreement')
        po_market = cleaned_data.get('po_market')
        customer = cleaned_data.get('customer')
        print(f"fa:{framework_agreement} et customer:{customer}")

        if not(name):
            msg = ('Veuillez compléter le nom de l\'affaire')
            self.add_error('name', msg)      
        if not (amount):
            msg = ('Veuillez définir le montant de l\'affaire')
            self.add_error('amount', msg)
        if ponderation.weight == 100 and not
            if not signature_date:
                msg = ('Bravo, l\'affaire est signée! Merci de préciser à quelle date')
                self.add_error('signature_date', msg) 
        if signature_date:
            print("signature date:", signature_date)
            if self.instance.po_market:
                print("associé à un po_market")
                po_market = self.instance.po_market
                if po_market.signature_date:
                    if po_market.signature_date > signature_date:
                        formatted_date = po_market.signature_date.strftime('%d/%m/%y')
                        msg = f"Cette date doit être postérieure ou égale à la date de signature du marché de commande:   {formatted_date}"
                        self.add_error('signature_date', msg) 
            if self.instance.framework_agreement:
                print("associé à un fa")
                framework_agreement = self.instance.framework_agreement
                if framework_agreement.signature_date:
                    print("signature fa:", framework_agreement.signature_date)
                    if framework_agreement.signature_date > signature_date:
                        formatted_date = framework_agreement.signature_date.strftime('%d/%m/%y')
                        msg = f"Cette date doit être postérieure ou égale à la date de signature de l\'accord cadre:   {formatted_date}"
                        self.add_error('signature_date', msg) 
                    print("pas de fa associé")
        if vat_rate is None:
            # Rechercher le taux par défaut dans VATRates
            default_vat_rate = VATRates.objects.filter(default_rate=True).first()
            if default_vat_rate:
                cleaned_data['vat_rate'] = default_vat_rate  
        if customer and framework_agreement:
            # Vérifier si le framework_agreement est associé au customer sélectionné
            if framework_agreement.customer != customer:
                self.add_error('framework_agreement', 'Le choix ne fait pas partie des options disponibles.')
            else: print('fa en phase avec customer')
        if customer and po_market:
            # Vérifier si le po_market est associé au customer sélectionné
            if po_market.customer != customer:
                self.add_error('po_market', 'Le choix ne fait pas partie des options disponibles.')
            else: print('po en phase avec customer')

        if self.errors:
            # Copier les données du formulaire
            data_copy =
            # Réaffecter les valeurs sélectionnées pour framework_agreement et po_market
            framework_agreement = cleaned_data.get('framework_agreement')
            po_market = cleaned_data.get('po_market')
            data_copy['framework_agreement'] = framework_agreement
            data_copy['po_market'] = po_market
            # Assigner la copie modifiée à
   = QueryDict('', mutable=True)
        return cleaned_data        

For instance, I may have the following request.POST: <QueryDict: {‘csrfmiddlewaretoken’: [‘CgKECDaRZ9tRlNuOK4kJxVSD6Bhc3e0LClQb86Pqk7G5qit5q8lzUiBRlVJkVujQ’, ‘CgKECDaRZ9tRlNuOK4kJxVSD6Bhc3e0LClQb86Pqk7G5qit5q8lzUiBRlVJkVujQ’], ‘customer’: [‘4’], ‘beneficiary’: [‘’], ‘account_exec’: [‘’], ‘name’: [‘New’], ‘amount’: [‘3300’], ‘ponderation’: [‘1’], ‘signature_date’: [‘’], ‘framework_agreement’: [‘5’], ‘po_market’: [‘’], ‘vat_rate’: [‘’], ‘customer_ref’: [‘’], ‘invoice_set-TOTAL_FORMS’: [‘1’], ‘invoice_set-INITIAL_FORMS’: [‘0’], ‘invoice_set-MIN_NUM_FORMS’: [‘0’], ‘invoice_set-MAX_NUM_FORMS’: [‘1000’], ‘invoice_set-0-id’: [‘’], ‘invoice_set-0-label’: [‘’], ‘invoice_set-0-amount’: [‘’], ‘invoice_set-0-issuance_date’: [‘’], ‘invoice_set-0-due_date’: [‘’], ‘update’: [‘’]}> where ‘framework_agreement’: [‘5’], but the clean method displays :
fa:None et customer:GPM Guyane

Does anyone have an idea of what I’am missing?


The cleaned_data dict is going to contain the values after they have been converted to their Django representation. If you’ve got no value in cleaned_data['framework_agreement'], then that is telling you that you don’t have an entry in your Framework_agreement model with a pk=5.

Thanks for such a qucik feedbak, Ken,

But I do have en framework_agreement entry with id = 5:

That’s what I do not understand…:frowning:

Then I’d need to see the form you are using along with the view that is displaying and processing that form.

Hi Ken,

In the meantime, I’ve found the issue.
My business_form was initializing the foreign keys made available to those which where related to the customer I was creating the business for.
But, as I also have a JS which updates the foreign keys when the user changes the customer. As a result, these keys were not part of the initial values anymore…

I fixed this by letting the business form initialised with all foreign keys possible, but a JS restricts the select list to the relevant ones.