Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Django Field to store a list of email addresses

Tags:

python

django

I'm trying to add a field to a Django model that will represent a list of email addresses. I would like a user to enter a comma separated list of addresses into a form in the admin, which my app will then parse to send out a series of emails.

My current implementation covers the basic idea, but has a significant limitation. In the admin, if I enter a string like [email protected], [email protected], then it correctly writes this to the database as [u'[email protected]', u'[email protected]']. But the admin displays this serialized value instead of the humanized string. More importantly, if I edit and save the record, without making any changes, the same conversion changes [u'[email protected]', u'[email protected]'] to [u"[u'[email protected]'", u"u'[email protected]']"].

How do I convert the python list representation back to a string for use in the admin? Is that the purpose of the value_to_string method or do I need to make the conversion someplace else?

My current custom model field is as follows:

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)

This is based on the SeparatedValuesField described here: http://www.davidcramer.net/code/181/custom-fields-in-django.html.

like image 698
AndrewF Avatar asked Nov 02 '10 12:11

AndrewF


2 Answers

I based this off the docs but its a model field instead:

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())
like image 94
radtek Avatar answered Sep 23 '22 08:09

radtek


I wouldn't do that. I would make whatever your EmailListField is supposed to be associated with be one-to-many with email address fields.

like image 23
hughdbrown Avatar answered Sep 26 '22 08:09

hughdbrown