Валидация серийного номера на соответствие маске
Есть две таблицы - тип оборудования и оборудование, у типа есть строка с маской серийного номера, у оборудования есть строка с серийным номером. При создании нового оборудования, должна пройти валидация, то есть строку с серийным номером сравнивают с каждой маской типа оборудования и если обнаруживается соответствие - оборудование прявязывается к типу, вопрос такой, как это лучше реализовать на 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, но кто-то мне порекомендовал делать это через представления, заранее извиняюсь за ужасный код, стараюсь быть лучше.