如何将mac地址序列化为BigInteger字段?

时间:2015-12-04 22:36:07

标签: django django-rest-framework

我希望我的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-framework在我之前运行了一个验证,但是如何覆盖这种行为呢?

的Tx

2 个答案:

答案 0 :(得分:1)

这是一个解决方案。这是一个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)

答案 1 :(得分:0)

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

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

然后,我需要一个带有验证器的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'])

最后一行代码是密钥!