Link Search Menu Expand Document

Работа с формами

В 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

  1. Подключим библиотеки:
     import re
     from django.core.exceptions import ValidationError
    
  2. Добавим к классу формы необходимую функцию:
     def clean_title(self):
         title = self.cleaned_data['title']
         if re.match(r'\d', title):
             raise ValidationError('Название не должно начинаться с цифры')
         return title