Bonjour,

Je développe un projet Django qui est actuellement en test.

Lors d'un test, l'utilisateur a réussi à saisir 2 fois le même formulaire alors même qu'un contrôle anti-doublon existe à la validation du formulaire (méthode clean)
De mon côté, je n'ai pas réussi à reproduire ce problème et je suis bien bloqué par le contrôle à la validation

je ne comprends pas comment c'est possible ?

models.py :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
class Entree(models.Model):
 
    asp_ent_cle = models.AutoField(primary_key=True)
    asp_ent_loc = models.CharField("Site concerned by the operation", max_length=10, null=True, blank=True)
    med_num = models.CharField("Trial batch number", max_length=3, null=True, blank=True,)
    asp_ent_dat = models.DateField("Entry date", null=True, blank=True)
    asp_ent_pro_pay = models.CharField("Country of treatment origin in case of entry", max_length=10, null=True, blank=True)
    asp_ent_pro_sit = models.CharField("Processing source site in case of entry", max_length=10, null=True, blank=True)
    opr_nom = models.CharField("Input operator", max_length=10, null=True, blank=True)
    opr_dat = models.DateField("Entry date", null=True, blank=True)
    log = HistoricalRecords()
 
    class Meta:
 
        db_table = 'pha_asp_ent'
        verbose_name_plural = 'Entries'
        ordering = ['asp_ent_cle']  
        permissions = [
            ('can_manage_drugs','Can manage trial drugs'),
        ]
form.py :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
class EditForm(forms.ModelForm):

    # surcharge méthode constructeur (__init__) pour avoir accès aux variables de sessions
    # https://stackoverflow.com/questions/3778148/django-form-validation-including-the-use-of-session-data
    def __init__(self, request, *args, **kwargs):
        super(EditForm, self).__init__(*args, **kwargs)
        self.request = request
        self.language = request.session.get('language')
        self.user = request.user.id # id de l'utilisateur
        self.user_pays = request.session.get('user_pays') # id pays de l'utilisateur
        self.user_site_type = request.session.get('user_site_type') # type de site de l'utilisateur ('International','National','Site')
        self.user_site = request.session.get('user_site') # code lettre du site de l'utilisateur '(eg TR pour CHU Treichville)'

        #  Listes déroulantes conditionnées sur le profil utilisateur connecté
        SITE_CONCERNE = Site.options_list_site_concerne(self.user,self.user_pays,self.user_site_type,self.language)
        # Liste de tous les traitements mentionnés en sortie avec destination = SiteConnecté et non entrés dans la pharmacie du site connecté
        MEDICAMENTS = Entree.medicaments_entree(self.user_site)
        PAYS = Pays.options_list(self.user_pays,self.user_site_type,self.language)
        SITE_PROVENANCE = Site.options_list_site_provenance(self.user_site_type,self.user_pays,self.language)

        # si utilisateur connecté = International
        if self.user_site_type == 'International':
            self.fields["asp_ent_loc"] = forms.ChoiceField(label = _("Site concerned by the operation"), widget=forms.Select, choices=SITE_CONCERNE)
        elif self.user_site_type == 'National':
            self.fields["asp_ent_loc"] = forms.ChoiceField(label = _("Site concerned by the operation"), widget=forms.Select, choices=SITE_CONCERNE, initial = self.user_site)
        else:
            self.fields["asp_ent_loc"] = forms.ChoiceField(label = _("Site concerned by the operation"), widget=forms.Select, choices=SITE_CONCERNE, initial = self.user_site, disabled=True)

        # si utilisateur connecté = Site
        if self.user_site_type == 'Site':
            self.fields["med_num"] = forms.ChoiceField(label = _("Trial batch number"), widget=forms.Select, choices=MEDICAMENTS)
        else:
            self.fields["med_num"] = forms.CharField(label = _("Trial batch number"), required=True)
        # empêche l'autocomplétion
        self.fields['med_num'].widget.attrs.update({
            'autocomplete': 'off'
        })
        self.fields["asp_ent_dat"] = forms.DateField(
                label = _("Entry date"),
                required = True,
                # initial = timezone.now(),  
                # initial = datetime.datetime.now(),  
                validators=[validate_date],
            )
        # empêche l'autocomplétion
        self.fields['asp_ent_dat'].widget.attrs.update({
            'autocomplete': 'off'
        })
        # Si utilisateur connecté = Site
        if self.user_site_type == 'Site':
            self.fields["asp_ent_pro_pay"] = forms.ChoiceField(label = _("Country of treatment origin in case of entry"), widget=forms.Select, choices=PAYS, initial = Pays.pays_abreviation(self.user_pays), disabled=True)
        else:
            self.fields["asp_ent_pro_pay"] = forms.ChoiceField(label = _("Country of treatment origin in case of entry"), widget=forms.Select, choices=PAYS)
        self.fields["asp_ent_pro_sit"] = forms.ChoiceField(label = _("Processing source site in case of entry"), widget=forms.Select, choices=SITE_PROVENANCE,)

    def clean(self):
        cleaned_data = super(EditForm, self).clean()
        # controle anti-doublon (profil International et National car liste déroulante conditionnée pour les profils sites)
        entrees = Entree.objects.all()
        if self.user_site_type != 'Site':
            doublon = str(self.data.get('asp_ent_loc')) +'/'+ str(self.data.get('med_num')) +'/'+ str(self.data.get('asp_ent_dat'))
            if len([d for d in entrees if d.asp_ent_loc+'/'+d.med_num+'/'+str(d.asp_ent_dat) == doublon]) > 0:
                raise ValidationError(_('This entry already exist'))

    class Meta:
        model = Entree
        fields = ('asp_ent_loc','med_num','asp_ent_dat','asp_ent_pro_pay','asp_ent_pro_sit',)


    def clean_med_num(self):
        data = self.cleaned_data['med_num']

        # contrôle longueur numéro de lot saisie
        if len(data) != 3:
            raise forms.ValidationError(_("Error on Batch number format (3 letters)"))

        # contrôle existance numéro de lot dans la table médicament (fournie par statisticien)
        if not Medicament.objects.filter(med_num = data).exists():
            raise ValidationError(_('Batch number does not exist'))

        return data

    def clean_asp_ent_dat(self):
        data = self.cleaned_data['asp_ent_dat']
        # try:
        #     entrydate = datetime.datetime.strptime(str(data), "%Y-%m-%d")
        # except expression as identifier:
        #     pass
        # else:
        #     entrydate = datetime.datetime.strptime(str(data), "%d/%m/%Y")
        entrydate = datetime.datetime.strptime(str(data), "%Y-%m-%d")
        currentdate = datetime.datetime.now()
        if entrydate > currentdate:
            raise forms.ValidationError(_("Please control entry date"))
        return data

    def clean_asp_ent_pro_sit(self):
        data = self.cleaned_data['asp_ent_pro_sit']
        if data == '' or data == 'None':
            raise forms.ValidationError(_("This field is required"))
        return data