[Fixed]-How to serialize a mac address into a BigInteger field?

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)
👤lehins

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!

Leave a comment