我希望我的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
答案 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'])
最后一行代码是密钥!