Select field validation issue

Hello,
I am facing an issue with validation of select fields. Here is the context:
I have the following models:

class Framework_agreement( models.Model):
    number = models.CharField('Numéro',max_length=30,)
    customer=models.ForeignKey(Company, on_delete=models.CASCADE, verbose_name='Client')

class PO_market(models.Model):
    number = models.CharField('Numéro',max_length=30,)
    customer=models.ForeignKey(Company, on_delete=models.CASCADE, verbose_name='Client')
    signature_date= models.DateField('Date de signature',null=True,blank=True)
    expiration_date = models.DateField('Date de fin',null=True,blank=True)
    framework_agreement = models.ForeignKey(Framework_agreement, on_delete=models.SET_NULL, null=True, blank=True,\
        verbose_name="Accord-cadre")

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, default="",
        null=True, blank=True)
    engagement_number= models.CharField("N° d'engagement", max_length=250, default="",
        null=True, blank=True)
    organisational_unit= models.CharField("Direction", max_length=250, default="",
        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)

I have a the following view

class BusinessUpdateView(LoginRequiredMixin, UpdateView):
    model = Business
    form_class = BusinessForm
    template_name = 'salesforecast/business_form.html'
    
    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        return form
    
    def get_initial(self):
        initial = super().get_initial()
        return initial
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['business_form'] = context['form']
        if self.object.ponderation.facturable is False and self.object.ponderation.final:
            InvoiceFormSet = inlineformset_factory(Business, Invoice,
                                form=InvoiceInLineForm, 
                                can_delete=False,
                                extra=0)
        else:
            InvoiceFormSet = inlineformset_factory(Business, Invoice,
                                form=InvoiceInLineForm,
                                can_delete=True,
                                extra=1)
        if self.request.POST:
            context['invoice_formset'] = InvoiceFormSet(self.request.POST, instance=self.object)
        else:
            context['invoice_formset'] = InvoiceFormSet(instance=self.object)
        return context
    
    def form_invalid(self, form):
        print("valaeur iniitale de po_market:", self.initial.get('po_market'))
        print("valeur saisie de po_market:", self.request.POST.get('po_market'))
        print("valeur iniitale de framework_agreement:", self.initial.get('framework_agreement'))
        print("valeur saisie de framework_agreement:", self.request.POST.get('framework_agreement'))
        return super().form_invalid(form)

    def form_valid(self, form):
        print("valaeur iniitale de po_market:", self.initial.get('po_market'))
        print("valeur saisie de po_market:", self.request.POST.get('po_market'))
        # On met à jour l'objet business
        response = super().form_valid(form)
        context = self.get_context_data()
        invoices = context['invoice_formset']
        with transaction.atomic():
            self.object = form.save()
            if invoices.is_valid():
                invoices.instance = self.object
                invoices.save() # le save inclut l'initialisation de contact, addressee, address et comment à partir de business
        # On informe le user de l'impact du changement de framework_agreement et po_market
        msg = ""
        if form.has_changed() or invoices.has_changed():
            msg = "Les modifications ont été enregistrées."
            if ('initial_framework_agreement') in form.changed_data:
                if self.object.framework_agreement:
                    msg += f'\nL\'affaire a été rattachée à l\'accord cadre "{self.object.framework_agreement}"'
                else:
                    msg += f'\nL\'affaire a été détachée du contrat cadre "{self.object.framework_agreement}"'
            if ('po_market' in form.changed_data):
                if self.object.po_market:
                    msg += f'\nL\'affaire a été rattachée au marché à bons de commande "{self.object.po_market}"'
                else:
                    msg += f'\nL\'affaire a été détachée du marché à bons de commande "{self.object.po_market}"'
        if self.object.collected_amount() == self.object.amount:
            final_status = BusinessStatus.objects.filter(weight=100, final=True).first()
            print("Status:",final_status.label)
            self.object.ponderation = final_status
            self.object.save()
            msg += "\nToutes les factures ont été émises et encaissées. L'affaire est terminée."
        if msg != "":
            messages.success(self.request, msg)
        return response

which is based on the following form:

class BusinessForm(ModelForm):
    
    def clean_framework_agreement(self):
        customer = self.cleaned_data.get('customer')
        framework_agreement = self.cleaned_data.get('framework_agreement')
        print(f'METHODE clean_framework_agreement - customer: {customer}, fa:{framework_agreement}')
        # Mettez à jour les options de framework_agreement en fonction de la valeur actuelle de customer
        self.fields['framework_agreement'].queryset = Framework_agreement.objects.filter(customer=customer)
        # On s'assure que la valeur soumise par l'utilisateur est dans les options acceptables
        if framework_agreement not in self.fields['framework_agreement'].queryset and framework_agreement is not None:
            raise forms.ValidationError("La valeur du champ n'est pas valide.")
        return framework_agreement
    
    def clean_po_market(self):
        customer = self.cleaned_data.get('customer')
        framework_agreement = self.cleaned_data.get('framework_agreement')
        po_market = self.cleaned_data.get('po_market')
        print(f'METHODE clean_po_market - customer: {customer}, fa:{framework_agreement}, po:{po_market}',)
        # Mettez à jour les options de po_market en fonction de la valeur actuelle de framework_agreement
        if framework_agreement:
            self.fields['po_market'].queryset = PO_market.objects.filter(framework_agreement=framework_agreement)
            print("po_market queryset:", PO_market.objects.filter(framework_agreement=framework_agreement))
        else:
            self.fields['po_market'].queryset = PO_market.objects.filter(customer=customer, framework_agreement=None)
        # On s'assure que la valeur soumise par l'utilisateur est dans les options acceptables
        if po_market not in self.fields['po_market'].queryset and po_market is not None:
            raise forms.ValidationError("La valeur du champ po_market n'est pas valide.")
        return po_market

    def clean(self):
        cleaned_data = super().clean()
        print("PO MARKET Avant clean:", cleaned_data.get('po_market') )
        self.clean_framework_agreement()
        self.clean_po_market()
        print("Exécution de la méthode CLEAN")
        name = cleaned_data.get('name')
        amount = cleaned_data.get('amount')
        ponderation = cleaned_data.get('ponderation')
        framework_agreement = cleaned_data.get('framework_agreement')
        print("framework_agreement clean exécuté")
        po_market = cleaned_data.get('po_market')
        print("po_market clean exécuté")
        customer = cleaned_data.get('customer')
        beneficiary = cleaned_data.get('beneficiary')
        
        account_exec = cleaned_data.get('account_exec')
        signature_date = cleaned_data.get('signature_date')
        vat_rate = cleaned_data.get('vat_rate')
        
        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 'account_exec' in self.fields:
            if not (account_exec):
                msg = ('Veuillez choisir le chargé d\'affaire')
                self.add_error('account_exec', msg)
        if 'signature_date' in self.fields:
            if ponderation.weight == 100 and not ponderation.final:
                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:
                if self.instance.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:
                    framework_agreement = self.instance.framework_agreement
                    if 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) 
        if 'vat_rate' in self.fields:
            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  

        # si pas de bénéficiaire saisi, c'est le client qui est bénéficiaire
        if not beneficiary:
            cleaned_data['beneficiary'] = customer

        '''if self.errors:
            # Copier les données du formulaire
            data_copy = self.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 à self.data
            self.data = QueryDict('', mutable=True)
            self.data.update(data_copy)'''
        return cleaned_data        
    
    # fonctions d'initialisation des valeurs calculées        
    def init_calculated_fields(self):
        if self.instance.pk:
            self.fields['business_warning'].initial = self.instance.business_warning()
            self.fields['amount_ratio'].initial = self.instance.amount_ratio()
            self.fields['weighted_amount'].initial = self.instance.weighted_amount()
            self.fields['amount_to_plan'].initial = self.instance.amount_to_plan()
            self.fields['weighted_amount_ratio'].initial = self.instance.weighted_amount_ratio()
            self.fields['weighted_amount_ratio_complement'].initial = self.instance.weighted_amount_ratio_complement()
            self.fields['billed_amount'].initial = self.instance.billed_amount()
            self.fields['billed_amount_ratio'].initial = self.instance.billed_amount_ratio()
            self.fields['billed_amount_ratio_complement'].initial = self.instance.billed_amount_ratio_complement()
        else:
            self.fields['business_warning'].initial = False
            self.fields['amount_ratio'].initial = 0
            self.fields['weighted_amount'].initial = 0
            self.fields['amount_to_plan'].initial = 0
            self.fields['weighted_amount_ratio'].initial = 0
            self.fields['weighted_amount_ratio_complement'].initial = 0
            self.fields['billed_amount'].initial = 0
            self.fields['billed_amount_ratio'].initial = 0
            self.fields['billed_amount_ratio_complement'].initial = 0
        
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)        
        # La restiction des  listes de choix de framework_agreement,  des po_market, 
        # des contacts et adresse par défaut au client en cours est géré par Javascript
        #if self.instance.pk
        # On initialise les montants calculés
        self.init_calculated_fields()
        # Par défaut, on applique les mêmes conditions de règlement
        p = Param.objects.get()
        default_payment_period = p.payment_period
        if p.payment_period and 'payment_period' in self.fields:
            self.fields['payment_period'].initial= default_payment_period
            
        # Format d'affichage des champs
        optionalFields = ['vat_rate', 'payment_period', 'currency']
        for field in optionalFields:
            if field in self.fields:
                self.fields[field].required = False
        if 'vat_rate' in self.fields:
            self.fields['vat_rate'].label = "Taux de TVA"
        for _, value in self.fields.items():
           value.widget.attrs['class'] = 'form-control text-primary' 
                  
        if self.instance.pk:
            if self.instance.amount_to_plan() != 0:
                self.fields['amount_to_plan'].widget.attrs.update(
                    {'class': 'form-control text-danger ','style': 'font-weight: bold;'})
        
        self.fields['name'].widget.attrs.update({'placeholder': 'Saisir une nouvelle affaire'})
        self.fields['amount'].label = self.instance._meta.get_field('amount').verbose_name
               
        self.fields['weighted_amount'].disabled = True
        self.fields['amount_to_plan'].disabled = True
        self.fields['amount_ratio']. disabled = True
        self.fields['weighted_amount_ratio'].disabled = True
        self.fields['weighted_amount_ratio_complement'].disabled = True
        self.fields['billed_amount'].disabled = True
        self.fields['billed_amount_ratio'].disabled = True
        self.fields['billed_amount_ratio_complement'].disabled = True

        if not self.instance.pk:
            # si l'instance n'existe pas, on met la pondération au minimum
            default_ponderation = BusinessStatus.objects.filter(final=False, facturable=False).order_by('weight').first()  
            if default_ponderation:
                self.initial['ponderation'] = default_ponderation
            else:
                self.initial['ponderation'] = 2 #pk initial de "détectée"  
        else:
            # On limite les options de framework_agreement à celles qui sont associées au client
            customer = self.instance.customer
            self.fields['framework_agreement'].queryset = Framework_agreement.objects.filter(customer=customer)
            # On limite les options du champ po_market en fonction du framework agreement auquel est associé le business
            if self.instance.framework_agreement:
                self.fields['po_market'].queryset = PO_market.objects.filter(framework_agreement=self.instance.framework_agreement)
            else:
                self.fields['po_market'].queryset = PO_market.objects.filter(customer=customer, framework_agreement=None )
            # On limite les options de default_contact, default_addressee et default_address à ceux qui sont associés au client
            if 'default_contact' in self.fields:
                self.fields['default_contact'].queryset = Contact.objects.filter(customer=customer)
            if 'default_addressee' in self.fields:
                self.fields['default_addressee'].queryset = Contact.objects.filter(customer=customer)
            if 'default_address' in self.fields:    
                self.fields['default_address'].queryset = Address.objects.filter(customer=customer)
            # si l'instance existe, que l'affaire est terminée ou perdue, les champs ne sont plus modifiables
            # à l'exception du champ "ponderation"
            if self.instance.ponderation.final == True:
                print("INIT BUSINESS - affaire terminée perdue")
                for fieldName, field in self.fields.items():
                    print("champ traité:", fieldName, field)
                    if fieldName != 'ponderation':
                        field.widget.attrs.update({'readonly': True, 'class': 'readonly-field form-control text-primary'})  
                    else:
                        print("champ pondération")      
                        field.widget.attrs.update({'readonly': False, 'class': 'form-control text-primary'})      
        
    weighted_amount = forms.DecimalField(disabled=True, label="Montant pondéré",widget=AmountInput)
    amount_to_plan = forms.DecimalField(disabled = True, label="A planifier",widget=AmountInput)
    amount_ratio = forms.DecimalField(required=False, label='ratio montant/100',widget=AmountInput)
    weighted_amount_ratio =forms.DecimalField(required=False, label='ratio confiance')
    weighted_amount_ratio_complement = forms.DecimalField(required=False, label = "complément")
    billed_amount = forms.DecimalField(required = False,widget=AmountInput)
    billed_amount_ratio = forms.CharField(required=False)
    billed_amount_ratio_complement = forms.DecimalField(required=False,) 
    amount = forms.DecimalField(required=False,max_digits=10, decimal_places=2, localize=True)
    business_warning = forms.BooleanField(required=False)
    
    
    class Meta:
        model = Business
        fields = ['name', 'customer', 'beneficiary','framework_agreement','po_market', 'amount','ponderation','signature_date', 'account_exec',\
            'customer_ref','engagement_number', 'organisational_unit', 'default_contact','default_addressee','default_address',\
            'currency', 'vat_rate', 'payment_period','comment']
        widgets = {
            'creation_date': DatePickerInput,
            'signature_date': DatePickerInput
        }
 

The init limits the options of framework_agreement depending on the relations with the customer and the options of the po_markets depending on the framework_agreement.
On the client side, a javascrpt updates the po_market option every time the user changes the framework_agreement.

When the user changes the framework_agremeent and the po_market, the validation fails: po_market is not part of valid options. I have noticed thant while the request.POST has the expected value for po_market, it’s always “None” in the clean method.

I do not understand what’s going on! Where is the po_market value turned from the right value (the one in the request.POSt) to “None”???

I could let the init method with all possible options and rely on the the JS, but I don’t like it: it opens some security issues, doesn’it?
I’d rather have the server validate the po_market selected is in line with the framework_agreement.

Any help will be appreciated!

Richard