You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF设备序列号掩码验证失效问题排查与修复咨询

问题分析与修复方案

你的验证逻辑失效主要是因为模型层、序列化器层的代码存在多处错误,以下是具体修改点:

一、models.py 修正

错误点:

  1. mask = self.type 错误获取了EquipmentType对象,而非其mask字段
  2. 正则表达式中'd'未转义,实际匹配的是字符d而非数字
  3. re.match未限制完整匹配,导致部分符合开头的字符串也能通过
  4. ValidationError的字段名serial_number与模型字段sn不匹配
  5. 模型save方法未主动调用clean,导致模型层验证不触发

修改后的代码:

import re
from django.core.exceptions import ValidationError
from django.db import models

class EquipmentType(models.Model):
    name = models.CharField(max_length=255)
    mask = models.CharField(max_length=100)


class Equipment(models.Model):
    type = models.ForeignKey('EquipmentType', on_delete=models.CASCADE)
    sn = models.CharField(max_length=255, unique=True)
    note = models.CharField(max_length=255)
    
    def clean(self):
        super().clean()  # 调用父类clean方法
        mask = self.type.mask  # 正确获取掩码字段
        regex = '^'  # 匹配字符串开头
        for char in mask:
            if char == 'N':
                regex += r'\d'  # 转义匹配数字
            elif char == 'A':
                regex += '[A-Z]'
            elif char == 'a':
                regex += '[a-z]'
            elif char == 'X':
                regex += '[A-Z0-9]'
            elif char == 'Z':
                regex += '[-_@]'
            else:
                regex += re.escape(char)  # 转义掩码中的特殊字符
        regex += '$'  # 匹配字符串结尾
        
        if not re.fullmatch(regex, self.sn):  # fullmatch确保完整匹配
            raise ValidationError({'sn': '序列号不符合当前设备类型的掩码规则'})

    def save(self, *args, **kwargs):
        self.clean()  # 保存前强制调用clean验证
        super().save(*args, **kwargs)

    class Meta:
        unique_together = ('sn', 'type')

二、serializers.py 修正

错误点:

  1. 验证方法名错误:应为validate_sn而非validate_serial_number,DRF要求字段验证方法命名为validate_<字段名>
  2. 创建新对象时self.instance为None,直接访问会报错
  3. 循环遍历value(sn字符串)的每个字符进行验证,逻辑错误
  4. 正则表达式同样存在未转义、未完整匹配的问题

修改后的代码:

import re
from rest_framework import serializers
from .models import Equipment, EquipmentType

class EquipmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Equipment
        fields = '__all__'

    def validate_sn(self, value):
        # 获取当前设备对应的类型:创建时从initial_data取,更新时从instance取
        if self.instance:
            equipment_type = self.instance.type
        else:
            type_id = self.initial_data.get('type')
            if not type_id:
                raise serializers.ValidationError('必须指定设备类型')
            try:
                equipment_type = EquipmentType.objects.get(id=type_id)
            except EquipmentType.DoesNotExist:
                raise serializers.ValidationError('指定的设备类型不存在')
        
        mask = equipment_type.mask
        regex = '^'
        for char in mask:
            if char == 'N':
                regex += r'\d'
            elif char == 'A':
                regex += '[A-Z]'
            elif char == 'a':
                regex += '[a-z]'
            elif char == 'X':
                regex += '[A-Z0-9]'
            elif char == 'Z':
                regex += '[-_@]'
            else:
                regex += re.escape(char)
        regex += '$'
        
        if not re.fullmatch(regex, value):
            raise serializers.ValidationError(f'序列号不符合掩码规则:{mask}')
        return value


class EquipmentTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = EquipmentType
        fields = '__all__'

三、views.py 修正

错误点:

EquipmentTypeAPIView的get方法中,错误使用Equipment模型获取对象,应改为EquipmentType

修改后的代码片段:

class EquipmentTypeAPIView(APIView):
    def get(self, request,  *args, **kwargs):
        pk = kwargs.get("pk", None)
        if not pk:
            w = EquipmentType.objects.all()
            return Response({'posts': EquipmentTypeSerializer(w, many=True).data})
        # 修正这里的模型为EquipmentType
        mymodel = get_object_or_404(EquipmentType, pk=pk)
        serializer = EquipmentTypeSerializer(mymodel)
        return Response(serializer.data)

额外说明

  • 模型层的clean+save调用确保了即使绕过序列化器直接操作数据库,验证也会生效
  • 序列化器层的验证针对API请求做了更友好的错误提示,同时处理了创建和更新两种场景
  • 使用re.fullmatch替代re.match,确保整个序列号完全符合掩码长度和规则

内容的提问来源于stack exchange,提问作者Александр Филипов

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 07:17:24