2010-11-02 3 views
8

Sto provando ad aggiungere un campo a un modello Django che rappresenterà un elenco di indirizzi e-mail. Vorrei che un utente inserisse un elenco di indirizzi separati da virgole in un modulo nell'admin, che verrà poi analizzato dalla mia app per inviare una serie di email.Campo Django personalizzato per memorizzare un elenco di indirizzi e-mail

La mia attuale implementazione copre l'idea di base, ma ha un limite significativo. Nell'amministratore, se inserisco una stringa come [email protected], [email protected], la scrive correttamente nel database come [u'[email protected]', u'[email protected]']. Ma l'amministratore visualizza questo valore serializzato invece della stringa umanizzata. Ancora più importante, se modifico e salvo il record, senza apportare modifiche, la stessa conversione cambia da [u'[email protected]', u'[email protected]'] a [u"[u'[email protected]'", u"u'[email protected]']"].

Come si converte la rappresentazione della lista Python in una stringa da utilizzare nell'amministratore? È questo lo scopo del metodo value_to_string o devo effettuare la conversione da qualche altra parte?

Il mio attuale campo Modello personalizzato è la seguente:

class EmailListField(models.TextField): 
    __metaclass__ = models.SubfieldBase 

    def to_python(self, value): 
     if not value: 
      return 
     if isinstance(value, list): 
      return value 
     return [address.strip() for address in value.split(',')] 

    def get_db_prep_value(self, value): 
     if not value: 
      return 
     return ','.join(unicode(s) for s in value) 

    def value_to_string(self, obj): 
     value = self._get_val_from_obj(obj) 
     return self.get_db_prep_value(value) 

Questo si basa sul SeparatedValuesField descritto qui: http://www.davidcramer.net/code/181/custom-fields-in-django.html.

+0

Ha bisogno di essere una lista avrebbe lista qualcosa di simile al separati da virgola nell'esempio docs - http://docs.djangoproject.com/en/dev/ref/forms/validation/#form-field- lavoro di pulizia di default? – JamesO

+0

Grazie, ma quell'esempio è per un campo modulo, per convalidare l'input di un utente. Quello di cui ho bisogno è un campo modello, per salvare più indirizzi nel database. – AndrewF

risposta

3

Non lo farei. Vorrei fare qualunque cosa si supponga che il tuo EmailListField sia associato con uno-a-molti con campi di indirizzi email.

+0

Capisco come sia più semplice, ma questi indirizzi email non sono in realtà correlati a nessun altro dato nella mia app. Ha senso introdurre una nuova tabella email_address nel database, solo per contenere una colonna? – AndrewF

+1

Sì, è il modo migliore. Questo aiuterà anche in altri modi, come la ricerca, ecc. – zsquare

+1

Devi essere d'accordo con zsquare. È il modo ragionevole per farlo. Potresti anche voler dare un'occhiata al gestore di admin.TabularInline di django in modo che l'app di amministrazione possa mostrare l'elenco di email "in-line" con l'oggetto Profile (o qualsiasi altra cosa ti aspetti di associare a EmailListField). –

3

La domanda è morto, ma è possibile farlo aggiungendo la presentazione particolare al pitone val

class EmailDomainsListField(models.TextField): 
    __metaclass__ = models.SubfieldBase 

    class Presentation(list): 

     def __unicode__(self): 
      return u",".join(self) 
     def __str__(self): 
      return ",".join(self) 
    ... 

    def to_python(self, value): 
     if not value: 
      return 
     if isinstance(value, EmailDomainsListField.Presentation): 
      return value 
     return EmailDomainsListField.Presentation([address.strip() for address in  value.split(',')])  
1

ho basato questo fuori i documenti ma è un campo Modello invece:

class MultiEmailField(models.TextField): 

    def to_python(self, value): 

     if not value: 
      return None # [] 

     cleaned_email_list = list() 
     #email_list = filter(None, value.split(',')) 
     email_list = filter(None, re.split(r';|,\s|\n', value)) 

     for email in email_list: 
      if email.strip(' @;,'): 
       cleaned_email_list.append(email.strip(' @;,')) 

     print cleaned_email_list 
     cleaned_email_list = list(set(cleaned_email_list)) 

     return ", ".join(cleaned_email_list) 

    def validate(self, value, model_instance): 
     """Check if value consists only of valid emails.""" 

     # Use the parent's handling of required fields, etc. 
     super(MultiEmailField, self).validate(value, model_instance) 

     email_list = value.split(',') 

     for email in email_list: 
      validate_email(email.strip()) 
1

Di seguito è riportato il campo del modello con la convalida di ciascuna e-mail e la corretta gestione dell'amministratore. Basato sulle risposte di eviltnan e AndrewF.

from django.core import validators 
from django.db import models 


class EmailListField(models.CharField): 
    __metaclass__ = models.SubfieldBase 

    class EmailListValidator(validators.EmailValidator): 
     def __call__(self, value): 
      for email in value: 
       super(EmailListField.EmailListValidator, self).__call__(email) 

    class Presentation(list): 

     def __unicode__(self): 
      return u", ".join(self) 

     def __str__(self): 
      return ", ".join(self) 

    default_validators = [EmailListValidator()] 

    def get_db_prep_value(self, value, *args, **kwargs): 
     if not value: 
      return 
     return ','.join(unicode(s) for s in value) 

    def value_to_string(self, obj): 
     value = self._get_val_from_obj(obj) 
     return self.get_db_prep_value(value) 

    def to_python(self, value): 
     if not value: 
      return 
     if isinstance(value, self.Presentation): 
      return value 
     return self.Presentation([address.strip() for address in value.split(',')]) 
Problemi correlati