Index: db/models/fields/__init__.py =================================================================== --- db/models/fields/__init__.py (revision 17904) +++ db/models/fields/__init__.py (working copy) @@ -627,6 +627,31 @@ defaults.update(kwargs) return super(CharField, self).formfield(**defaults) +class DomainNameField(CharField): + """An Internationalized Domain Name in ASCII or UTF format, stored as idna-encoded (ASCII) string.""" + description = _("Internet Domain Name") + + def __init__(self, *args, **kwargs): + accept_idna = kwargs.pop('accept_idna', True) + kwargs['max_length'] = 255 + super(CharField, self).__init__(*args, **kwargs) + self.validators.append(validators.DomainNameValidator(accept_idna=accept_idna)) + + def to_python(self, value): + # we always store domain names in ASCII format + value = super(DomainNameField, self).to_python(value) + # make sure we got called on RAW data, because django calls to_python() + # even on already-python data. IDNA-decoding UTF would raise exception. + if value.encode('idna') != value: # value is UTF (python) already + return value + # value is RAW or python-ASCII, safe to encode in either case + return value.decode('idna') + + def get_prep_value(self, value): + # we always store domain names in ASCII format + return value.encode('idna') + + # TODO: Maybe move this into contrib, because it's specialized. class CommaSeparatedIntegerField(CharField): default_validators = [validators.validate_comma_separated_integer_list]