В этой лекции мы поговорим о том, как стилизовать наши формы, добавлять пользовательские методы для проверки данных и переопределять стандартные методы форм для внедрения специфической логики.
Добавление стилей к формам
Представьте, что вы зашли на сайт, который должен предложить вам крутой функционал, но выглядит он как страница из 2005-го года. Боюсь, вы не задержитесь там надолго. Так что нам нужно не только функционально, но и эстетически улучшить наши формы.
Django Forms автоматически генерируют HTML-код. Но вот беда: этот HTML, как правило, выглядит просто. Просто! А значит, нужно добавить немного магии CSS.
Где стилизовать?
Стили можно добавлять прямо в шаблоне или в самой форме. Мы рассмотрим обе опции.
Пример: добавление CSS и Bootstrap классов
Вот как можно добавить стили полям формы, используя атрибут widgets:
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(
max_length=100,
widget=forms.TextInput(attrs={
'class': 'form-control', # Bootstrap класс
'placeholder': 'Ваше имя', # Подсказка
})
)
email = forms.EmailField(
widget=forms.EmailInput(attrs={
'class': 'form-control',
'placeholder': 'Ваш Email',
})
)
message = forms.CharField(
widget=forms.Textarea(attrs={
'class': 'form-control',
'placeholder': 'Ваше сообщение',
'rows': 5,
})
)
attrs— это магический словарь, где вы задаёте HTML-атрибуты для поля: классы, подсказки, размеры.- Мы использовали Bootstrap классы для стилизации полей формы (
form-control), а также задали удобные поляplaceholderдля пользователей.
При этом в вашем шаблоне ничего не нужно менять:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Отправить</button>
</form>
Результат: красивая форма с минимальными усилиями. Эстетика спасает мир!
Переопределение методов формы
Иногда нужно работать не только с внешним видом, но и с внутренней магией. Например, что, если нужно изменить метки полей (labels) или порядок их отображения? Или передавать в форму динамически изменяемые данные? Давайте разберёмся.
Переопределяем метод __init__
Метод __init__ используется для инициализации формы. Это отличное место для изменений — например, добавления к полям каких-нибудь стартовых данных.
Пример: динамические метки полей
Допустим, у нас есть форма регистрации, и мы хотим, чтобы поле имени могло быть локализованным. Например, "Name" для английского и "Имя" для русского.
class RegistrationForm(forms.Form):
username = forms.CharField(max_length=50)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
def __init__(self, *args, **kwargs):
user_language = kwargs.pop('language', 'en') # Получаем язык из аргументов
super().__init__(*args, **kwargs)
if user_language == 'ru':
self.fields['username'].label = 'Имя пользователя'
self.fields['email'].label = 'Электронная почта'
self.fields['password'].label = 'Пароль'
else:
self.fields['username'].label = 'Username'
self.fields['email'].label = 'Email'
self.fields['password'].label = 'Password'
Теперь можно передать язык формы при её инициализации:
form = RegistrationForm(language='ru')
И вуаля — форма корректно отобразит метки на русском языке.
Изменение порядка полей
Всё ещё метод __init__, но теперь мы поменяем порядок отображения полей в форме.
class CustomOrderForm(forms.Form):
first = forms.CharField()
second = forms.CharField()
third = forms.CharField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.order_fields(['third', 'first', 'second']) # Меняем порядок
Метод order_fields() — встроенный метод Django Forms. У него есть только один недостаток: задний фронт HTML всё равно останется в том же порядке, если ваша форма рендерится через {% for field in form %}. Для красивого подхода лучше явно перестраивать порядок в шаблоне.
Пользовательские методы
Иногда встроенной валидации недостаточно. Например, вы хотите проверить, существует ли введённый email в базе. Для этого можно добавить собственные методы.
Пример: метод проверки уникальности
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
class RegistrationForm(forms.Form):
username = forms.CharField(max_length=50)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
def clean_email(self):
email = self.cleaned_data.get('email')
if User.objects.filter(email=email).exists():
raise ValidationError('Такой email уже зарегистрирован.')
return email
def clean_username(self):
username = self.cleaned_data.get('username')
if User.objects.filter(username=username).exists():
raise ValidationError('Имя пользователя занято.')
return username
Что здесь происходит?
- Мы переопределили метод
clean_<fieldname>(). Django автоматически вызывает этот метод, если он существует, для каждого указанного поля. - Если проверка не проходит, выбрасывается исключение
ValidationError, а форма отмечает это поле как невалидное.
Когда понадобятся кастомные методы?
Вы можете использовать их для всего, где требуется специфическая логика. Например:
- Проверка уникальности.
- Проверка формата данных (например, username может содержать только буквы и цифры).
- Предварительная обработка данных (например, избавление от пробелов).
Best practices и хитрости
- Старайтесь инкапсулировать логику. Если ваши методы слишком сильно зависят от формы, подумайте, можно ли вынести логику в отдельную функцию или сервис.
- Будьте осторожны с
init. Не забывайте вызыватьsuper().__init__(*args, **kwargs), иначе ваша форма просто не будет работать. - Минимум логики в шаблонах. Весь сложный функционал и логику размещайте в Python-коде, а не в HTML.
- Красота важна. Никто не станет заполнять форму, если она выглядит как форма налоговой декларации 1980-го года.
Поздравляю! Теперь вы знаете, как превращать простенькие формы в мощные, стильные и функциональные инструменты для ваших Django-приложений. На следующем занятии вы научитесь ещё больше: работать с ошибками форм и кастомизировать их отображение.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ