如何将mac地址串行化为BigInteger字段



我希望我的API能够将mac地址处理为整数和字符串。

在我的模型中,我设置了:

class WifiAccessPoint(models.Model):
    bssid = models.BigIntegerField(null=False, blank=False)

我试过这个:

def mac_address(value):
    # return integer if value is either (1) int or (2) "xx:xx:xx:xx:xx"
    # raises Validation error
    try:
        ret = int(value)
        return ret
    except:
        try:
            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.IntegerField(validators=[mac_address])
    class Meta:
        model = WifiAccessPoint
        fields = ('bssid', 'ssid', 'rssi', 'channel',)

但这不起作用:当我发布一个字符串mac地址(xx:xx:xx:xx:xx)时,我会得到一个400错误:需要整数。

我知道rest框架在我之前运行了一个验证器,但我该如何覆盖这种行为呢?

Tx

这里有一个解决方案。这是一个MacIntegerField,它将自动将字符串MAC值转换为整数(必须是64位系统,否则会丢失一些MAC,因为MAC是48位)。虽然我还没有试过,但它应该有效。

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)

好的,我有解决方案。事实上,这里有一个验证器来验证数据,而不是更改它

因此,如果您想将字符串更改为整数,则必须在创建时执行此操作。

然后,我需要一个带有验证器的CharField:

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',)

这只会验证传入的数据。

然后,在序列化程序的创建函数中,我添加了以下代码:

def create(self, validated_data):
     wap = validated_data.pop('wifiaccesspoint')      
     wap['bssid']=mac_address(wap['bssid'])

这最后一行代码就是密钥

最新更新