Валидация серийного номера на соответствие маске

Есть две таблицы - тип оборудования и оборудование, у типа есть строка с маской серийного номера, у оборудования есть строка с серийным номером. При создании нового оборудования, должна пройти валидация, то есть строку с серийным номером сравнивают с каждой маской типа оборудования и если обнаруживается соответствие - оборудование прявязывается к типу, вопрос такой, как это лучше реализовать на django rest framework?

Проверка осуществялется по принципу:
N – цифра от 0 до 9;
A – прописная буква латинского алфавита;
a – строчная буква латинского алфавита;
X – прописная буква латинского алфавита либо цифра от 0 до 9;
Z – символ из списка: “-“, “_”, “@”.

То есть если оборудование имеет серийный номер 0QWER9@123, ему соответствует маска с символами вида NAAAAXZXXX

models.py

from django.db import models
from django.core.validators import MinLengthValidator
from django.core.validators import RegexValidator

class Type_Of_Equipment(models.Model):
    name = models.CharField(verbose_name='Тип оборудования', max_length=64, blank=True, default='Без названия')
    sn_mask = models.CharField(verbose_name='Маска серийного номера', blank=False, max_length=10,
    validators=[MinLengthValidator(10), RegexValidator(regex=r'^[NAaXZ]+$', message='Использованы недопустимые символы')])
    
class Equipment(models.Model):

    code = models.CharField(verbose_name='Код типа оборудования', max_length=64, blank=True)
    sn_number = models.CharField(verbose_name='Серийный номер', max_length=10, blank=False, unique=True, validators=[MinLengthValidator(10), RegexValidator(regex=r'^[A-Za-z0-9-_@]+$', message='Использованы недопустимые символы')])
    
    type_of_equipment = models.ForeignKey(Type_Of_Equipment, on_delete=models.DO_NOTHING)
    
    
    is_deleted = models.BooleanField(default=False)
    
    # Заготовки для мягкого удаления.
    def soft_delete(self):
        self.is_deleted = True
        self.save()

    def restore(self):
        self.is_deleted = False
        self.save()

views.py

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializers import EquipmentSerializer, TypeOfEquipmentSerializer
from .models import Equipment, Type_Of_Equipment
from django.http import Http404
import re

class GetOrCreateEquip(APIView):

    # Получение всего оборудования
    def get(self, request):
        # Получать список с query-параметрами
        equip = Equipment.objects.filter(is_deleted=False)

        code_query = request.query_params.get('code')
        sn_number_query = request.query_params.get('sn_mask')

        if code_query:
            equip = equip.filter(code=code_query)
        elif sn_number_query:
            equip = equip.filter(sn_number=sn_number_query)
            
        serializer = EquipmentSerializer(equip, many=True)
        return Response(serializer.data)
    
    # Создание нового оборудования
    def post(self, request):
        # Создавать объект, только если серийный номер совпадает с маской 
        # Перенести логику валидации данных в функцию clean в моделях?

        sn_shifer = {'N': r'^[0-9]+$',
            'A': r'^[A-Z]+$',
            'a': r'^[a-z]+$',
            'X': r'^[A-Z0-9]+$',
            'Z': r"^[-|_|@]+$"
        }
        success = 0
        for equip in request.data:
        # Логика поиска нужного типа оборудования под серийный номер
            types_of_equipment = Type_Of_Equipment.objects.all()
            equip_sn = equip.get('sn_number')
            for type_of_equipment in types_of_equipment:
                for i in range(10):
                    if re.match(sn_shifer[type_of_equipment.sn_mask[i]], equip_sn[i]):
                        success += 1
                        if success == 10:
                            request.data["type_of_equipment"] = type_of_equipment
                            serializer = EquipmentSerializer(data=request.data, many=True)
                            if serializer.is_valid():
                                serializer.save()
                                return Response(serializer.data, status=201)
                            return Response(serializer.errors, status=400)
                    else:
                        success = 0
                        break

Я пробовал реализовать это в моделях через функцию clean, но кто-то мне порекомендовал делать это через представления, заранее извиняюсь за ужасный код, стараюсь быть лучше.


Ответы (0 шт):