Django模型:电子邮件字段是唯一的,如果不是空/空的话

时间:2021-03-04 11:51:09

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?

有更好的方法吗?

4 个解决方案

#1


18  

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.

不幸的是,它并不像设置null=True、unique=True、blank=True那样简单。每当您试图使用csv或其他基于文本的源文件(Django的一部分)进行导入时,为了惟一性的目的,将“”视为不应该被复制的东西。

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

解决方法是覆盖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)

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

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

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

#2


7  

I tried to use the save but that still didn't work because errors are already raised in the clean method, so I overwrote that instead for my model, it looks something like this:

我尝试使用save,但它仍然不起作用,因为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

This works great for me, and the answer using the save may work for some cases, this one here should work by resetting the "" to None before the rest of the validation takes place in the base class clean. Cheers :)

这对我来说非常有用,使用save的答案在某些情况下可能是有效的,这里的方法是在基类clean中进行其余验证之前将“”重置为None。欢呼:)

#3


7  

Just do this:

只是这样做:

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

#4


1  

Allow the CharField to null and default it to None. As long as you don't have multiple blank field ("""), no integrity error will be raised.

允许CharField为null,并将其默认为None。只要您没有多个空白字段(“”),就不会引发完整性错误。

#models.py
Class Contact(models.Model):
    email = models.EmailField(max_length=70, blank=True, null=True, unique=True, default=None)
# protect the db from saving any blank fields (from admin or your app form)
def save(self, *args, **kwargs):
    if self.email is not None and self.email.strip() == "":
        self.email = None
    models.Model.save(self, *args, **kwargs)

#1


18  

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.

不幸的是,它并不像设置null=True、unique=True、blank=True那样简单。每当您试图使用csv或其他基于文本的源文件(Django的一部分)进行导入时,为了惟一性的目的,将“”视为不应该被复制的东西。

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

解决方法是覆盖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)

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

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

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

#2


7  

I tried to use the save but that still didn't work because errors are already raised in the clean method, so I overwrote that instead for my model, it looks something like this:

我尝试使用save,但它仍然不起作用,因为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

This works great for me, and the answer using the save may work for some cases, this one here should work by resetting the "" to None before the rest of the validation takes place in the base class clean. Cheers :)

这对我来说非常有用,使用save的答案在某些情况下可能是有效的,这里的方法是在基类clean中进行其余验证之前将“”重置为None。欢呼:)

#3


7  

Just do this:

只是这样做:

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

#4


1  

Allow the CharField to null and default it to None. As long as you don't have multiple blank field ("""), no integrity error will be raised.

允许CharField为null,并将其默认为None。只要您没有多个空白字段(“”),就不会引发完整性错误。

#models.py
Class Contact(models.Model):
    email = models.EmailField(max_length=70, blank=True, null=True, unique=True, default=None)
# protect the db from saving any blank fields (from admin or your app form)
def save(self, *args, **kwargs):
    if self.email is not None and self.email.strip() == "":
        self.email = None
    models.Model.save(self, *args, **kwargs)