Пользовательское поле Django для хранения списка адресов электронной почты
Я пытаюсь добавить в модель 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)
Это основано на SeparatedValuesField
описано здесь: http://www.davidcramer.net/code/181/custom-fields-in-django.html.
4 ответа
Я бы не стал этого делать. Я бы сделал все, что вы EmailListField
должен быть связан с полями адреса электронной почты "один-ко-многим".
Я основал это на документации, но вместо этого это модельное поле:
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())
Вопрос мертв, но вы можете сделать это, добавив конкретную презентацию в ваш 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(',')])
Ниже приведено поле модели с проверкой каждого электронного письма и правильной обработкой администратором. Основано на eviltnan и 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(',')])