Index: core/validators.py
===================================================================
--- core/validators.py	(revision 17904)
+++ core/validators.py	(working copy)
@@ -33,6 +33,37 @@
         if not self.regex.search(smart_unicode(value)):
             raise ValidationError(self.message, code=self.code)
 
+class DomainNameValidator(RegexValidator):
+    # from URLValidator + there can be most 127 labels (at most 255 total chars)
+    regex = re.compile(
+            r'^(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.){0,126}(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?))$',
+            re.IGNORECASE
+            )
+    message = 'Enter a valid plain or IDNA domain name value'
+
+    def __init__(self, *args, **kwargs):
+        if 'accept_idna' in kwargs:
+            self.accept_idna = kwargs['accept_idna']
+        else:
+            self.accept_idna = True
+        super(DomainNameValidator, self).__init__(*args, **kwargs)
+
+    def __call__(self, value):
+        # validate
+        try:
+            super(DomainNameValidator, self).__call__(value)
+        except ValidationError as e:
+            # maybe this is a unicode-encoded IDNA string?
+            if not self.accept_idna: raise
+            if not value: raise
+            # convert it unicode -> ascii
+            try:
+                asciival = smart_unicode(value).encode('idna')
+            except UnicodeError:
+                raise e # raise the original ASCII error
+            # validate the ascii encoding of it
+            super(DomainNameValidator, self).__call__(asciival)
+
 class URLValidator(RegexValidator):
     regex = re.compile(
         r'^(?:http|ftp)s?://' # http:// or https://

