Django模型:电子邮件字段在非空白时唯一

17 投票
4 回答
38084 浏览
提问于 2025-04-17 19:10

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

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)

我想把电子邮件设置为唯一,也就是说每个电子邮件地址不能重复。但是这样做的话,我就会把空白的电子邮件地址排除在外,而我并不想这样。

我在考虑类似这样的做法,但我在想有没有更好的方法来处理这个问题。

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)

有没有更好的办法呢?

4 个回答

7

我试着使用保存功能,但还是不行,因为在清理方法中已经出现了错误。所以我决定重写这个方法,针对我的模型,它大致是这样的:

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

这个方法对我来说效果很好,虽然使用保存功能在某些情况下也可能有效,但我这个方法是在基本类的清理方法进行其他验证之前,把""(空字符串)重置为None。希望对你有帮助!

10

只需要这样做:

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

不幸的是,这个问题没有那么简单,仅仅设置 null=True、unique=True 和 blank=True 是不够的。每当你尝试使用 CSV 文件或其他文本来源导入数据时,Django 的某些部分会把空字符串 "" 当作不应该重复的内容来处理。

解决这个问题的方法是重写保存数据的方法,具体做法如下:

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)

这样一来,使用 unique、null 和 blank 就能按预期工作了。

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

撰写回答