2013-03-15 9 views
10

Angenommen Sie haben ein einfaches Modell haben:Django Modell: E-Mail-Feld eindeutig, wenn nicht null/leer

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) 

Was ich möchte, ist zu tun, setzen E-Mail eindeutig zu sein, aber dabei unbedingt ich machen es so, dass ich leere E-Mail-Adressen ausschließe - und das will ich nicht.

Ich dachte über so etwas nach, aber ich frage mich, ob es einen besseren Weg gibt, damit umzugehen.

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) 

Gibt es einen besseren Weg, dies zu tun?

+1

Haben Sie versucht,' null = true' Einstellung und 'einzigartig = true'? Was ist los mit der Verwendung von 'null' und' unique' zur gleichen Zeit? – CppLearner

+0

Für das Leben von mir kann ich nicht herausfinden, wo ich lese, dass es nicht möglich war, blank = True und einzigartig = True auf einem charfield. –

+0

lol ich Angenommen, du hast es schon ausprobiert :) Schön zu sehen, dass jemand mich echauffiert – CppLearner

Antwort

18

Leider ist es nicht so einfach wie nur null = True setzen, einzigartig = True, blank = True. Immer wenn Sie versuchen, mit CSV oder einer anderen textbasierten Quelle zu importieren, behandelt ein Teil von Django zum Zweck der Eindeutigkeit "" als etwas, das nicht dupliziert werden sollte.

Die Work-around, ist das Speichern Methode überschrieben werden soll, wie folgt:

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) 

Dann unter Verwendung der einzigartigen, null und leer wird wie vorgesehen.

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

Großartig, Brandon! Aber ich denke, es ist besser, die Validierung aus der Speichermethode, wie folgt zu tun: 'def clean (self): wenn self.email und nicht email_re.match (self.email): auslösen ValidationError (u '% s ist keine E-Mail-Adresse, Dummy! '% self.email) ' und Sie können weniger Code in Ihre Speichermethode schreiben. –

6

Genau dies tun:

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

Ich glaube, dass Blank ist wirklich für Formular-Rendering, die höchstwahrscheinlich in der Admin passieren (es sei denn, wir rendern ein Formular basierend auf Modell am Front-End - oder einige Drittanbieter) Richtig? Da wir 'blank = True' gesetzt haben, sagen wir, dass dieses Feld optional ist. Ich möchte es nur bestätigen. – CppLearner

+0

Sie haben recht, aber' null = True 'allow' NUL L' auf der Datenbank. –

+0

Ja :) danke! – CppLearner

7

Ich habe versucht, die speichern zu verwenden, aber das immer noch nicht funktioniert, da Fehler bereits im Rein Verfahren angehoben werden, so überschrieb ich, dass statt für mein Modell, es so etwas wie folgt aussieht:

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 

Das funktioniert gut für mich, und die Antwort mit dem Speichern kann in einigen Fällen funktionieren, sollte dieser hier funktionieren, indem Sie das "" auf None zurücksetzen, bevor der Rest der Validierung in der Basisklasse sauber erfolgt. Prost :)

+0

endlich funktionierte das für mich und ich benutze django 1.9 und python 3.5. Vielen Dank – Amir

0

Lassen Sie das CharField auf null und setzen Sie es auf None. Solange Sie („“ ") nicht mehrere leere Feld haben, werden keine Integritätsfehler erhöht werden.

#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)