Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update Django model data with a unique constraint using a ModelForm?

I have two models with one of them defined with a constraint (see "Entities" model below).

I built two forms, one to create new model data and another to update model data. Create form works properly but update form throws an error saying about of already existing items (my constraints is based on the unique combination of two fields). No matter what field I modify within the update form, same error is thrown.

For example, modyfing only "notes" field in an "entity" instance leads to the following error.

Entities with this Name and Company already exists.

How to properly implement my form (and/or models) so that constraint is preserved (an entity with the same name has to be unique within a company) and modification of a non constrained field don't throws an error?

models.py

class Entities(models.Model):
    company = models.ForeignKey(Companies, on_delete=models.CASCADE)
    name =  models.CharField(max_length=50, blank=False, null=False)
    notes = models.TextField(blank=True, null=True)

    class Meta:
        # Constraint here (entity name + company combination name must be unique)
        constraints = [models.UniqueConstraint(fields=['name', 'company'], name='unique_company_entity')]
        managed = True
        db_table = 'entities'

    def __str__(self):
        object_name = self.name + " " + self.company.name
        return object_name 

class Companies(models.Model):
    name =  models.CharField(max_length=50, blank=False, null=False)
    notes = models.CharField(max_length=50, blank=True, null=True)

    class Meta:
        managed = True
        db_table = 'companies'

    def __str__(self):
        object_name = self.name
        return object_name    

views.py

def entity_edit(request,entity_id):
    companies = Companies.objects.all().order_by('name')
    entity_id = int(entity_id)
    entity = Entities.objects.get(id = entity_id)

    if request.method == 'POST': 

        form = EntityEditForm(request.POST,instance=entity)

        if form.is_valid():
            post_result = form.save(commit=True)
            redirect_url_valid = "/contacts/companies/entities/" + str(entity.id) + "/view/"

            return redirect(redirect_url_valid)

    else:
        form = EntityEditForm(instance=entity)

    return render(request,'entity_edit_form.html',{
        'companies': companies,
        'entity': entity,
        'form': form
    }) 

forms.py

 class EntityEditForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.label_suffix = ''
        self.fields['name'] = forms.CharField(label='Name',widget=forms.TextInput(attrs={ 'class': 'form-control' }))
        self.fields['company'] = forms.ModelChoiceField(queryset=Companies.objects.all(),label='Company',required=True,widget=forms.Select(attrs={ 'class': 'form-control' }))   
        self.fields['notes'] = forms.CharField(label='Notes',required=False,widget=forms.Textarea(attrs={ 'class': 'form-control' }))

    class Meta(object):
        model = Entities
        fields = ('name','company','notes')

    # Méthodes de nettoyage des champs du formulaire
    def clean_name(self):
        name = self.cleaned_data['name']
        return name

    def clean_company(self):
        company = self.cleaned_data['company']
        return company

    def clean_notes(self):
        notes = self.cleaned_data['notes']
        return notes
like image 802
donmelchior Avatar asked Nov 25 '25 04:11

donmelchior


1 Answers

When you save a ModelForm that is initialised with an instance, e.g. MyForm(request.POST, instance=instance_to_update), Django will exclude the instance instance_to_update from its query to check for any uniqueness constraints. See the code.

The code you show in your question is correct, but since you're getting the error, there can only be two explanations:

  • Either you forgot to pass the instance to your ModelForm's initialiser (form = EntityEditForm(request.POST)
  • Or you're initialising it with the wrong instance and modifying it to duplicate another already existing instance.
like image 140
dirkgroten Avatar answered Nov 27 '25 18:11

dirkgroten



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!