Модель Django: поле электронной почты уникально, если не null/blank
Скажем, у вас простая модель:
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 not blank
if not email_re.match(self.email) # If it 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)
Есть ли лучший способ сделать это?
Ответы
Ответ 1
К сожалению, это не так просто, как просто установка 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 not blank
if not email_re.match(self.email) # If it 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)
Затем использование уникальных, нулевых и пустых будет работать по назначению.
Class Contact(models.Model):
email = models.EmailField(max_length=70,blank=True, null= True, unique= True)
Ответ 2
Я попытался использовать сохранение, но это все еще не сработало, потому что ошибки уже подняты в чистом методе, поэтому я переписал это для моей модели, это выглядит примерно так:
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
Это отлично работает для меня, и ответ с использованием сохранения может работать в некоторых случаях, этот должен работать, сбросив "на" Нет" до того, как остальная часть проверки будет проведена в базовом классе. Приветствия:)
Ответ 3
Просто сделайте следующее:
class Contact(models.Model):
email = models.EmailField(max_length=70, null=True, blank=True, unique=True)
Ответ 4
Разрешить 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)