自定义Django字段以存储多个邮箱地址

9 投票
4 回答
9524 浏览
提问于 2025-04-16 06:25

我正在尝试在Django模型中添加一个字段,用来表示一系列电子邮件地址。我希望用户能在管理界面中输入一个用逗号分隔的地址列表,然后我的应用程序会解析这些地址,以便发送一系列电子邮件。

我现在的实现基本上能做到这一点,但有一个很大的限制。在管理界面中,如果我输入像 foo@example.com, bar@example.com 这样的字符串,它会正确地将其写入数据库,变成 [u'foo@example.com', u'bar@example.com']。但是,管理界面显示的却是这个序列化的值,而不是人类可读的字符串。更重要的是,如果我编辑并保存记录,而没有做任何更改,这个转换会把 [u'foo@example.com', u'bar@example.com'] 变成 [u"[u'foo@example.com'", u"u'bar@example.com']"]

我该如何将Python列表的表示形式转换回字符串,以便在管理界面中使用?这是否是 value_to_string 方法的目的,还是我需要在其他地方进行转换?

我现在的自定义模型字段如下:

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)

这个字段是基于这里描述的 SeparatedValuesFieldhttp://www.davidcramer.net/code/181/custom-fields-in-django.html

4 个回答

3

这个问题已经没有人讨论了,但你可以通过给你的 Python 变量添加特定的展示方式来实现这个功能。

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(',')])    
4

我参考了文档,但这是一个模型字段:

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())
3

我不会那样做。我会让你的 EmailListField 和电子邮件地址字段之间的关系是一对多的。

撰写回答