2010-11-02 7 views
8

J'essaie d'ajouter un champ à un modèle Django qui représentera une liste d'adresses e-mail. Je voudrais qu'un utilisateur entre une liste d'adresses séparées par des virgules dans un formulaire dans l'admin, que mon application analysera ensuite pour envoyer une série de courriels.Champ Django personnalisé pour stocker une liste d'adresses e-mail

Ma mise en œuvre actuelle couvre l'idée de base, mais a une limitation importante. Dans l'admin, si j'entre une chaîne comme [email protected], [email protected], alors il écrit correctement dans la base de données [u'[email protected]', u'[email protected]']. Mais l'administrateur affiche cette valeur sérialisée au lieu de la chaîne humanisée. Plus important encore, si je modifie et enregistre l'enregistrement, sans apporter de modifications, la même conversion change [u'[email protected]', u'[email protected]'] en [u"[u'[email protected]'", u"u'[email protected]']"]. Comment puis-je convertir la représentation de la liste python en une chaîne à utiliser dans l'admin? Est-ce le but de la méthode value_to_string ou ai-je besoin de faire la conversion ailleurs?

Mon champ actuel modèle personnalisé est la suivante:

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) 

Ceci est basé sur le SeparatedValuesField décrit ici: http://www.davidcramer.net/code/181/custom-fields-in-django.html.

+0

t-il besoin d'être une liste serait quelque chose comme la liste séparées par des virgules dans l'exemple docs - http://docs.djangoproject.com/en/dev/ref/forms/validation/#form-field- travail de nettoyage par défaut? – JamesO

+0

Merci, mais cet exemple est pour un champ de formulaire, pour valider l'entrée d'un utilisateur. Ce dont j'ai besoin, c'est d'un champ de modèle, pour enregistrer plusieurs adresses dans la base de données. – AndrewF

Répondre

3

Je ne ferais pas cela. Je ferais tout ce que votre EmailListField est censé être associé à un-à-plusieurs avec des champs d'adresse email.

+0

Je vois comment c'est plus simple, mais ces adresses e-mail ne sont pas réellement liées à d'autres éléments de données dans mon application. Est-il sensé d'introduire une nouvelle table email_address dans la base de données, juste pour contenir une colonne? – AndrewF

+1

Oui, c'est le meilleur moyen. Cela aidera aussi d'autres façons, comme la recherche, etc – zsquare

+1

Je suis d'accord avec zsquare. C'est la façon sensée de le faire. Vous pouvez également consulter le gestionnaire admin.TabularInline de django afin que votre application d'administration puisse afficher la liste des courriels "en ligne" avec l'objet Profile (ou tout ce à quoi vous vous attendez à associer EmailListField). –

3

La question est morte, mais vous pouvez le faire en ajoutant la présentation particulière à votre python 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

Je me suis basé au large des docs, mais son champ de modèle à la place:

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

Voici le champ de modèle avec la validation de chaque email et la manipulation d'admin correcte. Basé sur les réponses d'eviltnan et d'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(',')]) 
Questions connexes