Django模型:电子邮件字段唯一,如果不为null /空白

Bra*_*sen 15 python django

假设你有一个简单的模型:

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)
Run Code Online (Sandbox Code Playgroud)

我想做的是设置电子邮件是唯一的,但是,这样做我必须这样做,以便我排除空白的电子邮件地址 - 我不希望这样.

我在考虑这样的事情,但我想知道是否有更好的方法来处理它.

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)
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?

Bra*_*sen 21

不幸的是,它并不像设置null = True,unique = True,blank = True那么简单.每当您尝试使用csv或其他基于文本的源进行导入时,Django的某些部分出于唯一性的目的将""视为不应重复的内容.

解决方法是覆盖save方法,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

然后,使用unique,null和blank将按预期工作.

Class Contact(models.Model):
    email = models.EmailField(max_length=70,blank=True, null= True, unique= True)
Run Code Online (Sandbox Code Playgroud)

  • 太棒了,布兰登!但我认为最好从save方法中进行验证,如下所示:`def clean(self):if self.email而不是email_re.match(self.email):引发ValidationError(你'%s不是电子邮件address,dummy!'%self.email)`你可以在save方法中编写更少的代码. (5认同)

Fer*_*ves 10

这样做:

class Contact(models.Model):
    email = models.EmailField(max_length=70, null=True, blank=True, unique=True)
Run Code Online (Sandbox Code Playgroud)

  • 这仍然存在问题.空白的电子邮件地址,即""标记为重复. (20认同)

rad*_*tek 7

我试图使用保存,但仍然无法正常工作,因为已经在clean方法中引发了错误,所以我覆盖了我的模型,它看起来像这样:

Class MyModel(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)
    phase_id = models.CharField('The Phase', max_length=255, null=True, blank=True, unique=True)

    ...

    def clean(self):
        """
        Clean up blank fields to null
        """
        if self.phase_id == "":
            self.phase_id = None
Run Code Online (Sandbox Code Playgroud)

这对我很有用,并且使用save的答案可能适用于某些情况,这里的这个应该通过在基类clean中进行其余验证之前将""重置为None来工作.干杯:)