Brandon Bertelsen Brandon Bertelsen - 4 months ago 88
Python Question

Django model: Email field unique if not null/blank

Let's say you have a simple model:

Class Contact(models.Model):
email = models.EmailField(max_length=70,blank=True)
first = models.CharField(max_length=25,blank=True)
last = models.CharField(max_length=25,blank=True)


What I would like to do is set email to be unique, however, in doing so I necessarily make it such that I exclude blank email addresses - and I don't want that.

I was thinking about something like this but I'm wondering if there is a better way to deal with it.

from django.core.validators import email_re
from django.core.exceptions import ValidationError

def save(self, *args, **kwargs):
# ... other things not important here
self.email = self.email.lower().strip() # Hopefully reduces junk to ""
if self.email != "": # If it's not blank
if not email_re.match(self.email) # If it's not an email address
raise ValidationError(u'%s is not an email address, dummy!' % self.email)
if Contact.objects.filter(email = self.email) # If it already exists
raise ValidationError(u'%s already exists in database, jerk' % self.email)
super(Contact, self).save(*args, **kwargs)


Is there a better way to do this?

Answer

Unfortunately, it's not as simple as just setting null=True, unique=True, blank=True. Whenever you try to import using csv, or some other text based source, some part of Django, for the purpose of uniqueness treats "" as something that ought not to be duplicated.

The work-around, is to overwrite the save method, as follows:

def save(self, *args, **kwargs):
    # ... other things not important here
    self.email = self.email.lower().strip() # Hopefully reduces junk to ""
    if self.email != "": # If it's not blank
        if not email_re.match(self.email) # If it's not an email address
            raise ValidationError(u'%s is not an email address, dummy!' % self.email)
    if self.email == "":
        self.email = None
    super(Contact, self).save(*args, **kwargs)

Then,using unique, null and blank will work as intended.

Class Contact(models.Model):
    email = models.EmailField(max_length=70,blank=True, null= True, unique= True)
Comments