Добавлена валидация уникальности email и phone для клиентов
Изменения: - Добавлено ограничение unique=True для поля email в модели Customer - Email теперь поддерживает NULL значения (несколько клиентов могут быть без email) - Добавлены методы clean_email() и clean_phone() в CustomerForm для валидации - Переписан API endpoint api_create_customer для использования формы вместо прямого создания - Создано две миграции: сначала разрешение NULL, затем добавление unique constraint - В текущей БД преобразованы пустые строки email в NULL (4 записи) Это исправляет: - Возможность создания дубликатов клиентов с одинаковыми email/phone - Работает как в веб-форме, так и в модальном окне создания заказа - Устранена уязвимость race condition через использование DB constraints 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from phonenumber_field.widgets import PhoneNumberPrefixWidget
|
||||
from .models import Customer
|
||||
@@ -6,6 +7,7 @@ from .models import Customer
|
||||
class CustomerForm(forms.ModelForm):
|
||||
phone = PhoneNumberField(
|
||||
region='BY',
|
||||
required=False,
|
||||
help_text='Формат: +375XXXXXXXXX или 80XXXXXXXXX',
|
||||
widget=forms.TextInput(attrs={'placeholder': '+375XXXXXXXXX'})
|
||||
)
|
||||
@@ -35,4 +37,44 @@ class CustomerForm(forms.ModelForm):
|
||||
field.widget.attrs.update({'class': 'form-control'})
|
||||
else:
|
||||
# Regular input fields get form-control class
|
||||
field.widget.attrs.update({'class': 'form-control'})
|
||||
field.widget.attrs.update({'class': 'form-control'})
|
||||
|
||||
def clean_email(self):
|
||||
"""Проверяет уникальность email при создании/редактировании"""
|
||||
email = self.cleaned_data.get('email')
|
||||
|
||||
# Если email пустой, это нормально (blank=True)
|
||||
if not email:
|
||||
return email
|
||||
|
||||
# Проверяем уникальность
|
||||
queryset = Customer.objects.filter(email=email)
|
||||
|
||||
# При редактировании исключаем текущий экземпляр
|
||||
if self.instance and self.instance.pk:
|
||||
queryset = queryset.exclude(pk=self.instance.pk)
|
||||
|
||||
if queryset.exists():
|
||||
raise ValidationError('Клиент с таким email уже существует.')
|
||||
|
||||
return email
|
||||
|
||||
def clean_phone(self):
|
||||
"""Проверяет уникальность телефона при создании/редактировании"""
|
||||
phone = self.cleaned_data.get('phone')
|
||||
|
||||
# Если телефон пустой, это нормально (blank=True)
|
||||
if not phone:
|
||||
return phone
|
||||
|
||||
# Проверяем уникальность
|
||||
queryset = Customer.objects.filter(phone=phone)
|
||||
|
||||
# При редактировании исключаем текущий экземпляр
|
||||
if self.instance and self.instance.pk:
|
||||
queryset = queryset.exclude(pk=self.instance.pk)
|
||||
|
||||
if queryset.exists():
|
||||
raise ValidationError('Клиент с таким номером телефона уже существует.')
|
||||
|
||||
return phone
|
||||
Reference in New Issue
Block a user