Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django UpdateView with unique fields

Is there a way to update a unique field in update view? I have a model that has a name and age field but when I try to update the age without even changing the value of the name, it returns an error that the name already exists in the database

models.py

class MyModel(models.Model)
  name = models.CharField(max_length=200, unique=True)
  age = models.IntegerField()

views.py

class MyModelUpdateView(UpdateView):
    def get(self):
        self.object = self.get_object()
        my_model = self.object

        form = MyModelForm(instance=my_model)

        return self.render_to_response(
            self.get_context_data(pk=my_model.pk, form=form)
        )

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()

        my_model = self.object

        form = MyModelForm(data=request.POST, instance=my_model)

        if form.is_valid():
            form.save()

            return some_url

        return self.render_to_response(
            self.get_context_data(pk=my_model.pk, form=form)
        )

forms.py

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel
        fields = (
            'name',
            'age',
        )

    def clean(self):
        cleaned_data = super().clean()

        if MyModel.objects.filter(
            active=True, name=cleaned_data.get('name')
        ).exists():
            raise forms.ValidationError('MyModel already exists.')

        return cleaned_data

What am I missing here? Thank you.

like image 273
dahyunism Avatar asked Nov 29 '25 16:11

dahyunism


1 Answers

Since you update a model, and you do not change the name, of course a record with that name already exists: that specific record. You thus should alter the checking code, to:

class MyModelForm(forms.ModelForm):

    def clean(self, *args, **kwargs):
        cleaned_data = super().clean(*args, **kwargs)
        if MyModel.objects.exclude(pk=self.instance.pk).filter(
            active=True, name=cleaned_data.get('name')
        ).exists():
            raise forms.ValidationError('MyModel already exists.')
        return cleaned_data

    class Meta:
        model = MyModel
        fields = ('name', 'age')

Please do not alter the boilerplate logic of the UpdateView, you can easily implement this with:

class MyModelUpdateView(UpdateView):
    form_class = MyModelForm
    success_url = 'some url'

That being said, since if you already have set the field to unique=True, then there is no need to implement the check yourself. It seems here, that you already have a unique=True constraint:

class MyModel(models.Model)
  name = models.CharField(max_length=200, unique=True)
  age = models.IntegerField()

In that case, you can simply let the ModelForm do the work, so then your form looks like:

class MyModelForm(forms.ModelForm):

    class Meta:
        model = MyModel
        fields = ('name', 'age')

It is only if you want a more sophisticated uniqness (like with active=True?), and you can not represent it (easily) you should do your own validation.

like image 121
Willem Van Onsem Avatar answered Dec 02 '25 05:12

Willem Van Onsem



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!