2010-11-02 20 views
8

Estoy tratando de agregar un campo a un modelo de Django que representará una lista de direcciones de correo electrónico. Me gustaría que un usuario ingrese una lista de direcciones separadas por comas en un formulario en el administrador, que luego mi aplicación analizará para enviar una serie de correos electrónicos.Campo de Django personalizado para almacenar una lista de direcciones de correo electrónico

Mi implementación actual cubre la idea básica, pero tiene una limitación significativa. En el administrador, si ingreso una cadena como [email protected], [email protected], entonces escribe esto correctamente en la base de datos como [u'[email protected]', u'[email protected]']. Pero el administrador muestra este valor serializado en lugar de la cadena humanizada. Más importante aún, si edito y guardo el registro, sin realizar ningún cambio, la misma conversión cambia [u'[email protected]', u'[email protected]'] a [u"[u'[email protected]'", u"u'[email protected]']"].

¿Cómo convierto la representación de la lista de python en una cadena para su uso en el administrador? ¿Es ese el propósito del método value_to_string o necesito hacer la conversión en otro lugar?

Mi campo de modelo personalizado actual es la siguiente:

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) 

Esto se basa en la SeparatedValuesField se describe aquí: http://www.davidcramer.net/code/181/custom-fields-in-django.html.

+0

¿Tiene que ser una lista sería algo así como la lista separada por comas en el ejemplo docs - http://docs.djangoproject.com/en/dev/ref/forms/validation/#form-field- trabajo de limpieza predeterminado? – JamesO

+0

Gracias, pero ese ejemplo es para un campo de formulario, para validar la entrada de un usuario. Lo que necesito es un campo de modelo para guardar varias direcciones en la base de datos. – AndrewF

Respuesta

3

No haría eso. Me gustaría hacer lo que se supone que su EmailListField se asocia con ser uno-a-muchos con campos de dirección de correo electrónico.

+0

Veo cómo es más sencillo, pero estas direcciones de correo electrónico en realidad no están relacionadas con ningún otro dato en mi aplicación. ¿Tiene sentido introducir una nueva tabla email_address en la base de datos, solo para contener una columna? – AndrewF

+1

Sí, es la mejor manera. Esto también ayudará en otras formas, como buscar, etc. – zsquare

+1

Tengo que estar de acuerdo con zsquare. Es la manera sensata de hacerlo. También es posible que desee ver el administrador admin.TabularInline de django para que su aplicación de administrador pueda mostrar la lista de correos electrónicos "en línea" con el objeto Profile (o lo que sea que espera asociar con EmailListField). –

3

La cuestión está muerto, pero se puede hacer mediante la adición de la presentación particular a su pitón 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

basé esto de los documentos, pero es un campo de modelo en su lugar:

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

A continuación se muestra un modelo de campo con validación de cada correo electrónico y el manejo correcto del administrador. Basado en las respuestas eviltnan y 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(',')]) 
Cuestiones relacionadas