/
fields.py
117 lines (100 loc) · 4.1 KB
/
fields.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import django
from django.core.exceptions import ValidationError
from django.db import models
from netaddr import EUI, AddrFormatError
from .formfields import MACAddressField as MACAddressFormField
from . import default_dialect, format_mac, mac_linux
import warnings
class MACAddressField(models.Field):
description = "A MAC address validated by netaddr.EUI"
empty_strings_allowed = False
dialect = None
def __init__(self, *args, **kwargs):
self.integer = kwargs.pop('integer', True)
if not self.integer: # If storing MAC address as string, set max_length to default (17) or use supplied kwarg value.
kwargs['max_length'] = kwargs.get('max_length', 17)
super(MACAddressField, self).__init__(*args, **kwargs)
def deconstruct(self):
''' Django 1.7 migrations require this method
https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#field-deconstruction
'''
name, path, args, kwargs = super(MACAddressField, self).deconstruct()
kwargs['integer'] = self.integer
return name, path, args, kwargs
@classmethod
def set_dialect(cls, new_dialect_clazz):
''' Setting dialect for EUI (MAC addresses) globally to this Field
class.
Class new_dialect_clazz should (finally) extend
netaddr.strategy.eui48.mac_eui48.
'''
warnings.warn(
"The set_dialect method has been deprecated, in favor of the default_dialect utility function and "
" settings.MACADDRESS_DEFAULT_DIALECT. See macaddress.__init__.py source or the project README for "
"more information.",
DeprecationWarning,
)
cls.dialect = new_dialect_clazz
def get_prep_value(self, value):
if value is None:
return None
if not isinstance(value, EUI):
value = self.to_python(value)
if self.integer:
return int(value)
return str(value)
value.dialect = default_dialect(self)
if self.integer:
return int(value)
return str(value)
def get_internal_type(self):
if self.integer:
return 'BigIntegerField'
return 'CharField'
if django.VERSION < (2, 0):
def from_db_value(self, value, expression, connection, context=None):
return self.to_python(value)
else:
def from_db_value(self, value, expression, connection):
return self.to_python(value)
def to_python(self, value):
if value is None:
return value
if isinstance(value, EUI):
value.dialect = default_dialect(value)
return value
try:
return EUI(value, version=48, dialect=default_dialect())
except (TypeError, ValueError, AddrFormatError):
raise ValidationError(
"This value must be a valid MAC address.")
def formfield(self, **kwargs):
defaults = {'form_class': MACAddressFormField}
defaults.update(kwargs)
return super(MACAddressField, self).formfield(**defaults)
def get_prep_lookup(self, lookup_type, value):
# data is stored internally as integer so searching as string
# yield 0 result. for example: useful for search in admin.
if lookup_type in ('exact', 'iexact', 'icontains', 'icontains'):
try:
return self.get_prep_value(value)
except AddrFormatError:
return None
elif lookup_type in ('in'):
try:
macs = []
for mac in value:
macs += [self.get_prep_value(mac)]
return macs
except AddrFormatError:
return None
else:
raise TypeError('Lookup type %r not supported.' % lookup_type)
if django.VERSION < (1, 8):
from django.utils.six import add_metaclass
MACAddressField = add_metaclass(models.SubfieldBase)(MACAddressField)
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^macaddress\.fields\.MACAddressField"])
except ImportError:
pass