I often use Ethernet addresses (or MAC addresses) for computer description, in addition to IP addresses. So I think it could be useful to have this kind of field type defined by default. Here comes a patch to add it.
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py (revision 3206)
+++ django/db/models/fields/__init__.py (working copy)
@@ -525,6 +525,17 @@
def validate(self, field_data, all_data):
validators.isValidEmail(field_data, all_data)
+class EthernetAddressField(Field):
+ def __init__(self, *args, **kwargs):
+ kwargs['maxlength'] = 17
+ Field.__init__(self, *args, **kwargs)
+
+ def get_manipulator_field_objs(self):
+ return [forms.EthernetAddressField]
+
+ def validate(self, field_data, all_data):
+ validators.isValidEthernetAddress(field_data, None)
+
class FileField(Field):
def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs):
self.upload_to = upload_to
Index: django/db/backends/ado_mssql/creation.py
===================================================================
--- django/db/backends/ado_mssql/creation.py (revision 3206)
+++ django/db/backends/ado_mssql/creation.py (working copy)
@@ -5,6 +5,7 @@
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'smalldatetime',
'DateTimeField': 'smalldatetime',
+ 'EthernetAddressField': 'char(17)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
Index: django/db/backends/postgresql/creation.py
===================================================================
--- django/db/backends/postgresql/creation.py (revision 3206)
+++ django/db/backends/postgresql/creation.py (working copy)
@@ -9,6 +9,7 @@
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'timestamp with time zone',
+ 'EthernetAddressField':'varchar(17)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
Index: django/db/backends/sqlite3/creation.py
===================================================================
--- django/db/backends/sqlite3/creation.py (revision 3206)
+++ django/db/backends/sqlite3/creation.py (working copy)
@@ -8,6 +8,7 @@
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
+ 'EthernetAddressField': 'char(17)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
Index: django/db/backends/mysql/creation.py
===================================================================
--- django/db/backends/mysql/creation.py (revision 3206)
+++ django/db/backends/mysql/creation.py (working copy)
@@ -9,6 +9,7 @@
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
+ 'EthernetAddressField':'char(17)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
Index: django/db/backends/oracle/creation.py
===================================================================
--- django/db/backends/oracle/creation.py (revision 3206)
+++ django/db/backends/oracle/creation.py (working copy)
@@ -5,6 +5,7 @@
'CommaSeparatedIntegerField': 'varchar2(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'date',
+ 'EthernetAddressField':'char(17)',
'FileField': 'varchar2(100)',
'FilePathField': 'varchar2(100)',
'FloatField': 'number(%(max_digits)s, %(decimal_places)s)',
Index: django/forms/__init__.py
===================================================================
--- django/forms/__init__.py (revision 3206)
+++ django/forms/__init__.py (working copy)
@@ -873,6 +873,23 @@
except validators.ValidationError, e:
raise validators.CriticalValidationError, e.messages
+class EthernetAddressField(TextField):
+ def __init__(self, field_name, length=17, maxlength=17, is_required=False, validator_list=None):
+ if validator_list is None: validator_list = []
+ validator_list = [self.isValidEthernetAddress] + validator_list
+ TextField.__init__(self, field_name, length=length, maxlength=maxlength,
+ is_required=is_required, validator_list=validator_list)
+
+ def isValidEthernetAddress(self, field_data, all_data):
+ try:
+ validators.isValidEthernetAddress(field_data, all_data)
+ except validators.ValidationError, e:
+ raise validators.CriticalValidationError, e.messages
+
+ def html2python(data):
+ return data or None
+ html2python = staticmethod(html2python)
+
class IPAddressField(TextField):
def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
@@ -890,6 +907,7 @@
return data or None
html2python = staticmethod(html2python)
+
####################
# MISCELLANEOUS #
####################
Index: django/core/validators.py
===================================================================
--- django/core/validators.py (revision 3206)
+++ django/core/validators.py (working copy)
@@ -24,6 +24,7 @@
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$', re.IGNORECASE) # domain
+eth_re = re.compile(r'^[0-9A-F]{2}(:[0-9A-F]{2}){5}$', re.IGNORECASE)
integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
@@ -101,6 +102,10 @@
if not ip4_re.search(field_data):
raise ValidationError, gettext("Please enter a valid IP address.")
+def isValidEthernetAddress(field_data, all_data):
+ if not eth_re.search(field_data):
+ raise ValidationError, gettext("Please enter a valid Ethernet address.")
+
def isNotEmpty(field_data, all_data):
if field_data.strip() == '':
raise ValidationError, gettext("Empty values are not allowed here.")
Do we need/want it?