Search code examples
djangoformsmodelform

Django Update of table doesn't work because of clean method in modelForm


Here is my form

class TypeCompteForm(forms.Form):
    LIBELLES = (("xxxxx","xxxxxxx"),("xxxxxxxx","xxxxxxxxxx"))
    libelle = forms.ChoiceField(required=True,choices=LIBELLES,error_messages=err_msg,widget=forms.Select(attrs={"class":"form-control","placeholder": "Libellé du type"}))
    code = forms.CharField(required=True, max_length=50,widget=forms.TextInput(attrs={"class":"form-control","placeholder": "Code de du type"}))

    def clean_libelle(self):
        data = self.cleaned_data["libelle"]
        if TypeMagasin.objects.filter(libelle=data).exists():
            raise ValidationError("Un type de magasin avec ce libellé existe déjà !")
        return data

With this form I manage to insert the data in the data base. But when I try to modify one record the clean_libelle method executes. Below is the view I use for updating

def updateView(request,id):
    instance = MyModel.objects.get(pk=id)
    form = ModelForm(instance=instance)
    if request.method == "POST":
        form = ModelForm(request.POST, instance=instance)
        if form.is_valid():
            form.save()
        else:
            print(form.errors)
        return render(request,"template.html")
    return render(request,"reconciliation/template.html",{"form":form})

Solution

  • In your update view, the form instance is created twice. The first time it is created with form = ModelForm(instance=instance) and the second time it is created with form = ModelForm(request.POST, instance=instance). The first time it is created, the clean_libelle method is not called. The second time it is created, the method is called, which raises the validation error. To fix this issue, you need to skip the validation of the libelle field if the instance already exists in the database. You can achieve this by manually setting the value of the libelle field in the form before calling the is_valid method. Here's the updated view code:

    def updateView(request, id):
        instance = MyModel.objects.get(pk=id)
        form = ModelForm(instance=instance)
        if request.method == "POST":
            form = ModelForm(request.POST, instance=instance)
            if instance.libelle == form.cleaned_data["libelle"]:
                form.cleaned_data["libelle"] = instance.libelle
            if form.is_valid():
                form.save()
            else:
                print(form.errors)
            return render(request, "template.html")
        return render(request, "reconciliation/template.html", {"form": form})