1👍
Here is a solution. This is a MacIntegerField
that will automatically convert values from string MAC values to integer (has to be a 64bit system, otherwise some of MAC will be lost, since MACs are 48bits). Although I haven’t tried it, it should work.
import re
from rest_framework.fields import Field
from django.core.validators import RegexValidator
MAC_GROUPS = 6
MAC_DELIMITER = ':'
MAC_RE = re.compile("([0-9a-f]{2})" +
("\%s([0-9a-f]{2})" % MAC_DELIMITER) * (MAC_GROUPS - 1),
flags=re.IGNORECASE)
def mac2int(mac):
match = re.match(MAC_RE, mac)
mac_int = 0
if match is None:
raise ValueError("Not a mac address")
#raise ValidationError(_("Not a mac address"))
for g in match.groups():
mac_int = mac_int << 8
mac_int = mac_int | int(g, 16)
return mac_int
def int2mac(mac_int):
mac = ""
for n in range(MAC_GROUPS):
mac = "{0}{1:0{2}x}{3}".format(MAC_DELIMITER, mac_int & 0xff, 2, mac)
mac_int = mac_int >> 8
return mac[1:]
class MacIntegerField(Field):
MAX_STRING_LENGTH = 17
default_error_messages = {
'invalid': _("Not a mac address")
}
def __init__(self, **kwargs):
super(MacIntegerField, self).__init__(**kwargs)
self.validators.append(
RegexValidator(MAC_RE, message=self.error_messages['invalid']))
def to_internal_value(self, data):
try:
return mac2int(data)
except ValueError:
self.fail('invalid', input=data)
def to_representation(self, value):
return int2mac(value)
0👍
OK, I have the solution.
In fact, a validator is here to validate the data, not changing it.
So if you want to change the string to a an integer, you have to perform this action on the creation.
Then, I need a CharField with my validator:
def mac_address(value):
# return integer if value is either (1) int or (2) "xx:xx:xx:xx:xx"
# raises Validation error
try:
# is value an integer?
ret = int(value)
return ret
except:
try:
# value is not an integer, try to resolve a mac address
ret = int((value).replace(":", ""), 16)
return ret
except:
raise ValidationError(_("Not a mac address"))
class WifiAccessPointSerializer(serializers.ModelSerializer):
# specify mac address field, to enable 2 forms (int and "xx:xx:xx")
bssid = serializers.CharField(validators=[mac_address,])
class Meta:
model = WifiAccessPoint
fields = ('bssid', 'ssid', 'rssi', 'channel',)
This will just validate incoming data.
Then, in my create function of the serializer, I add this code:
def create(self, validated_data):
wap = validated_data.pop('wifiaccesspoint')
wap['bssid']=mac_address(wap['bssid'])
This last line of code id the key!
Source:stackexchange.com