Работа с формами
В Django существует два типа форм
- Форма связанная с моделью
- Форма не связанная с моделью
Форма может быть:
- Связанная с данными
- Не связанная с данными
Форма не связанная с моделью
Для создания форм мы в нашем приложении news
создаем файл forms.py
и в данном файле чтобы создать форму создаем класс, кото должен быть наследником класса forms.Form
, далее мы описываем поля формы также, как это делали в модели.
from django import forms
from .models import Category
class NewsForm(forms.Form):
title = forms.CharField(max_length=150, label='Название')
content = forms.CharField(required=False, label='Текст') # Указываем что заполнение не обязательно
is_published = forms.BooleanField(initial=True, label='Опубликованно') # Указываем что умолчанию пункт активирован
category = forms.ModelChoiceField(empty_label='Выберите категорию', queryset=Category.objects.all(), label='Категория') # Указываем что должно быть написано по умолчанию
В файле views.py
мы описываем следующий код:
from django.shortcuts import redirect # Импортируем библиотеку для редиректа
def add_news(request):
if request.method == 'POST':
form = NewsForm(request.POST)
if form.is_valid(): # Проверяем: прошла ли форма валидацию
news = News.objects.create(**form.cleaned_data) # Сохраняем новость
return redirect(news) # Производим редирект на страницу только-что созданной новости
else:
form = NewsForm()
return render(request, 'news/add_news.html', {'form': form})
Для вывода формы в шаблоне можно использовать следующие теги:
тег | описание |
---|---|
{{ form.as_p }} | каждый элемент таблицы размещается в теге <p> |
{{ form.as_ul }} | каждый элемент таблицы размещается в теге <ul> |
{{ form.as_table }} | каждый элемент таблицы размещается в столбцах таблицы |
Также не забываем добавить CSRF токен {% csrf_token %}
для защиты от CSRF уязвимости.
В ручном режиме форму можно выводить при помощи тегов
тег | описание |
---|---|
{{ form.title.id_for_label }} | Для отображения указателя на поле ввода |
{{ form.content }} | Для отображения поля ввода |
{{ form.content.errors }} | Для отображения текста ошибок валидации |
Также перед формой указываем {{ form.mom_field.errors }}
для отображения ошибок скрытых полей.
Для того, чтобы добавить класс к выводимым элементам, необходимо при описании модели формы добавить параметр widget
к соответсвующим полям:
class NewsForm(forms.Form):
title = forms.CharField(max_length=150, label='Название', widget=forms.TextInput(attrs={"class": "form-control"}))
content = forms.CharField(required=False, label='Текст', widget=forms.Textarea(attrs={"class": "form-control", "rows":5}))
is_published = forms.BooleanField(initial=True, label='Опубликованно')
category = forms.ModelChoiceField(empty_label='Выберите категорию', queryset=Category.objects.all(), label='Категория', widget=forms.Select(attrs={"class": "form-control"}))
Форма связанная с моделью
Если мы хотим сделать так, чтобы наша форма была связана с существующей моделью, то необходимо в файле forms.py
создать следующйи класс:
class NewsForm(forms.ModelForm):
class Meta:
model = News
fields = '__all__'
Значение fields = '__all__'
указывает на то что мы берем все поля модели для построения формы. Но лучше описать яно поля. Лучше вызывать поля явно:
fields = ['title', 'content', 'is_published', 'category']
Для оформления необходимо добавить словарь widgets
в котором мы опишем дизайн кажого элемента формы
class NewsForm(forms.ModelForm):
class Meta:
model = News
fields = ['title', 'content', 'is_published', 'category']
widgets = {
'title': forms.TextInput(attrs={"class": "form-control"}),
'content': forms.Textarea(attrs={"class": "form-control", "rows":5}),
'category': forms.Select(attrs={"class": "form-control"})
}
Также в файле views.py
для сохранения формы можно использовать news = form.save()
вместо news = News.objects.create(**form.cleaned_data)
Кастомные валидаторы
Валидатор – это метод класса формы с именем clean_название_поля
.
Для примера сделаем валидатор для поля title
. Сделаем так чтобы оно не могло начинаться с цифры.
Для этого в файле forms.py
- Подключим библиотеки:
import re from django.core.exceptions import ValidationError
- Добавим к классу формы необходимую функцию:
def clean_title(self): title = self.cleaned_data['title'] if re.match(r'\d', title): raise ValidationError('Название не должно начинаться с цифры') return title