Django models avoid duplicates

Question:

In models:

class Getdata(models.Model):
    title = models.CharField(max_length=255)
    state = models.CharField(max_length=2, choices=STATE, default="0")
    name = models.ForeignKey(School)
    created_by = models.ForeignKey(profile)

    def __unicode__(self):
        return self.id()

In templates:

<form>
    <input type="submit" value="save the data" />
</form> 

If the user clicks on the save button and the above data is saved in the table, how to avoid the duplicates, i.e. if the user again clicks on the same submit button there should not be another entry for the same values. Or is it something that has to be handled in views?

Asked By: Hulk

||

Answers:

If an individual field needs to be unique, then you just add unique=True:

class Getdata(models.Model):
    title = models.CharField(max_length=255, unique=True)
    state = models.CharField(max_length=2, choices=STATE, default="0")
    name = models.ForeignKey(School)
    created_by = models.ForeignKey(profile)

If you want a combination of fields to be unique, you need unique_together:

class Getdata(models.Model):
    title = models.CharField(max_length=255)
    state = models.CharField(max_length=2, choices=STATE, default="0")
    name = models.ForeignKey(School)
    created_by = models.ForeignKey(profile)
    class Meta:
        unique_together = ["title", "state", "name"]
Answered By: Mike DeSimone

The unique_together also suggested is the best way, but if that’s not appropriate for your needs, you can handle it in your form’s clean method. eg

def clean(self):
   try:
      Getdata.objects.get(title=self.cleaned_data['title'], 
                          state=self.cleaned_data['state'],
                          name=self.cleaned_data['name'],
                          created_by=self.cleaned_data['created_by'] )
      #if we get this far, we have an exact match for this form's data
      raise forms.ValidationError("Exists already!")
   except Getdata.DoesNotExist:
      #because we didn't get a match
      pass

   return self.cleaned_data
Answered By: Steve Jalim

I think injecting a Jquery/JS code to hide the save button would be a good idea.

Create a custom_validate.js file like below and place it in directory static(static file directory)

if (!$) {
    $ = django.jQuery;
}

$( document ).ready(function() {
    $("[name=_save]").click(function() {
       $("[name=_save]").css("visibility", "hidden");
    });
});

And in admin.py, add the below code.

class CustomDataForm(forms.ModelForm):

    class Meta:
        model = GetData

class GetDataAdmin(admin.ModelAdmin):
    # ....
    .....
    form = CustomDataForm

    class Media:
        js = ('/static/custom_validate.js', )
Answered By: SuperNova

I ran into this problem myself as well, unique_together seems to work nicely.

class Getdata(models.Model):
    title = models.CharField(max_length=255)
    state = models.CharField(max_length=2, choices=STATE, default="0")
    name = models.ForeignKey(School)
    created_by = models.ForeignKey(profile)
    class Meta:
        unique_together = ["title", "state", "name"]
Answered By: Mack