﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
2239	Add a new EthernetAddress Field Type	kilian.cavalotti@…	Adrian Holovaty	"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."")
}}}"	enhancement	closed	Database layer (models, ORM)		minor	wontfix	field type, ethernet address	kilian.cavalotti@…	Design decision needed	0	0	0	0	0	0
