JavaRush /Курсы /Модуль 3: Django /Валидация данных при регистрации

Валидация данных при регистрации

Модуль 3: Django
15 уровень , 5 лекция
Открыта

Представьте, что вы охранник на входе в клуб. Каждый раз, когда кто-то пытается войти, вы проверяете его документы, чтобы убедиться, что всё в порядке. Аналогично, валидация помогает программе убедиться, что данные, введённые пользователем, соответствуют ожидаемым требованиям.

Django предоставляет нам как встроенные инструменты для валидации, так и возможность создавать свои собственные валидаторы. В этой лекции мы разберём оба подхода.

Встроенные валидаторы Django

Django из коробки предоставляет множество удобных и мощных валидаторов, которые облегчают жизнь разработчику. Эти валидаторы можно использовать прямо в моделях или формах.

Примеры встроенных валидаторов

  1. Проверка уникальности данных (например, username и email): Django автоматически проверяет уникальность полей, если вы указали это в модели.

  2. Проверка на минимальную и максимальную длину: такие валидаторы используются для проверки длины текста, вводимого пользователем.

  3. Проверка формата email: Django предоставляет валидатор для проверки корректности формата email.

  4. Валидация пароля: встроенные валидаторы пароля помогают убедиться, что придуманный пользователем пароль достаточно сложен.

Пример использования встроенных валидаторов

Давайте добавим дополнительную проверку уникальности username и корректности формата email в форму регистрации:

from django import forms
from django.contrib.auth.models import User

class RegistrationForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username', 'email', 'password']

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if User.objects.filter(username=username).exists():
            raise forms.ValidationError("Такое имя пользователя уже занято. Пожалуйста, выберите другое.")
        return username

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError("Email уже используется. Пожалуйста, укажите другой.")
        return email
  • Метод clean_<field> вызывается для каждого поля. Здесь мы проверяем уникальность username и email.
  • Если данные некорректны, вызывается forms.ValidationError, который автоматически передаёт сообщение об ошибке в шаблон.

Кастомные валидаторы

Но что делать, если встроенные валидаторы не покрывают всех наших нужд? Например, если мы хотим, чтобы имя пользователя начиналось с буквы и содержало только буквы и цифры. Для таких случаев Django позволяет создавать кастомные валидаторы.

Пример кастомного валидатора

Мы создадим валидатор, который проверяет, чтобы имя пользователя начиналось с буквы.

import re
from django.core.exceptions import ValidationError

def validate_username(value):
    if not re.match("^[A-Za-z][A-Za-z0-9]*$", value):
        raise ValidationError(
            "Имя пользователя должно начинаться с буквы и содержать только буквы и цифры."
        )

Теперь мы можем подключить этот валидатор в нашей форме регистрации:

class RegistrationForm(forms.ModelForm):
    username = forms.CharField(validators=[validate_username])

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

И, вуаля, наш пользователь больше не сможет регистрироваться как "123abc".

Предотвращение уязвимостей

Данные от пользователя всегда должны быть под подозрением, особенно если они поступают через веб-формы. Валидация — это первый рубеж обороны. Без неё ваш сайт может стать жертвой:

  • SQL-инъекций: злоумышленники могут пытаться передать SQL-код вместо данных.
  • XSS-атак: вставка скриптов для выполнения на стороне клиента.
  • Дубликатов данных: повторяющиеся записи в базе данных.

Когда вы пишете валидацию, подумайте, что может пойти не так, и закройте все дыры.

Обработка ошибок валидации

Ошибки валидации — это не катастрофа, а просто сигнал пользователю, что он сделал что-то не так. В Django это обрабатывается через объект form.errors.

Пример отображения ошибок в шаблоне:

<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    {% if form.errors %}
        <ul>
            {% for field, errors in form.errors.items %}
                <li>{{ field }}: {{ errors|join:", " }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    <button type="submit">Регистрация</button>
</form>

Теперь, если у пользователя что-то пошло не так, он увидит вежливое сообщение об ошибке.

Проверка паролей

Пароли — это отдельная песня. Django предоставляет PasswordValidator для проверки сложности пароля. Например, вы можете добавить проверку длины пароля или его схожести с именем пользователя.

Пример настройки валидаторов пароля в settings.py:

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 8,
        }
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

Таким образом, пользователи не смогут использовать "12345678" или "password" в качестве своих паролей.

Практическая задача

Допустим, нам нужно реализовать следующую логику валидации:

  1. Имя пользователя должно быть уникальным и начинаться с буквы.
  2. Email не должен уже существовать в базе данных.
  3. Пароль должен быть не менее 8 символов, содержать хотя бы одну цифру и одну букву.

Попробуем реализовать это:

from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
import re

def validate_password_strength(password):
    if len(password) < 8:
        raise ValidationError("Пароль должен содержать не менее 8 символов.")
    if not re.search(r"\d", password):
        raise ValidationError("Пароль должен содержать хотя бы одну цифру.")
    if not re.search(r"[A-Za-z]", password):
        raise ValidationError("Пароль должен содержать хотя бы одну букву.")

class RegistrationForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput, validators=[validate_password_strength])

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if not re.match("^[A-Za-z][A-Za-z0-9]*$", username):
            raise forms.ValidationError("Имя пользователя должно начинаться с буквы и содержать только буквы и цифры.")
        if User.objects.filter(username=username).exists():
            raise forms.ValidationError("Такое имя пользователя уже занято.")
        return username

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError("Этот email уже используется.")
        return email

Теперь наши формы готовы любой атаке, ну или почти любой!

Типичные ошибки при валидации

  • Забвение об использовании метода cleaned_data. В итоговой форме обрабатываются только данные, прошедшие валидацию.
  • Отсутствие проверки уникальности на уровне модели. Даже если валидатор пропустит данные, база данных не должна.
  • Слишком общие сообщения об ошибках. Пользователи не должны догадываться, что они сделали не так.

Теперь, когда вы знаете, как работать с валидацией, ваши проекты смогут справляться с любой пользовательской "креативностью". Не забывайте тестировать свои валидаторы и регулярно обновлять их в зависимости от требований приложения.

1
Задача
Модуль 3: Django, 15 уровень, 5 лекция
Недоступна
Проверка уникальности email
Проверка уникальности email
1
Задача
Модуль 3: Django, 15 уровень, 5 лекция
Недоступна
Кастомный валидатор для username
Кастомный валидатор для username
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ