Здравствуйте! В продолжении серии статей про Class Based Views (далее CBV) переходим к разделу, посвященному редактированию объектов. В данной статье мы рассмотрим четыре класса с говорящими названиями: FormView, CreateView, UpdateView, DeleteView.
Часть 1, часть 2, часть 3, часть 4
Для ряда действий, будь то регистрация или авторизация на сайте, публикация новости, комментария или добавление товара в магазине, невозможно обойтись без форм. В качестве универсального инструмента создания форм в Django выступает класс FormView. В самом просто случае для создания работоспособной формы достаточно лишь передать ему лишь ссылку на класс, описывающий необходимую форму:
или передать нужные данные непосредственно экземпляру класса FormView в нашем urlconf:
Note: Пример синтетический и, разумеется, в таком виде использовать для страницы регистрации не получится.
Класс формы, который необходимо обработать, возвращается методом get_form_class. По умолчанию данный метод возвращает атрибут form_class, которому мы присваивали класс нашей формы в примере выше. Мы можем переопределить данный метод, если нам требуется более сложная логика в определении класса формы.
Метод get_success_url возвращает url ссылку, на которую будет осуществляться переход после успешной обработки формы. По умолчанию данный метод возвращает атрибут success_url.
Для указания полям формы значений по умолчанию мы можем передать их непосредственно в атрибут initial, представляющий из себя словарь, ключи которого должны иметь имена требуемых полей формы. Значение данного атрибута возвращается по умолчанию методом get_initial.
Часто возникает необходимость передать в форму определенные данные, например объект пользователя или заранее определенный список разделов. Для данного действия подходит метод get_form_kwargs. При переопределении данного метода необходимо соблюдать осторожность и не переписать случайно данные, передаваемые в форму по умолчанию. Среди них:
Чтобы избежать потери этих данных м�� должны сначала получить словарь из родительского класса, затем добавить в него требуемые данные:
Для получения класса нашей формы мы можем использовать метод get_form, который по умолчанию возвращает класс формы, указанный через метод form_class, с переданным ему словарем метода get_form_kwargs:
При обработке формы, в случае успеха, Django вызывает метод form_valid нашего отображения. По умолчанию данный метод осуществляет редирект по ссылке, возвращаемой методом get_success_url.
В случае, когда форме переданы некорректные данные вызывается метод form_invalid, который по умолчанию возвращает пользователя обратно на страницу формы, передавая ей объект со списком ошибок валидации.
Теперь рассмотрим разные сферы применения форм более подробно.
С помощью примера выше мы можем с легкостью создать новый объект статьи, однако в Django есть средства, позволяющие создать объект с еще большей легкостью, это класс CreateView. Для применения данного класса, передаваемая ему форма должна наследоваться от ModelForm:
Теперь мы можем передать объект данной формы в наше отображение. Пример отображения почти аналогичен предыдущему:
Если необходимо провести более сложные действия перед сохранением модели (проставить внешние ключи, добавить дополнительную информацию), то более подходящим способом это сделать будет следующий пример (спасибо пользователю marazmiki):
Note: Определение метода form_valid может быть излишне, так как CreateView наследует ModelFormMixin, который сохраняет экземпляр объекта из формы автоматически.
Для обработки ошибок также используется метод form_invalid, функциональность которого аналогична оной класса FormView.
Основное отличие класса UpdateView от CreateView, это передача экземпляра изменяемого объекта атрибуту object данного класса, в остальном данные классы идентичны. Для редактирования нам достаточно передать в url первичный ключ или slug изменяемого объекта:
Описание формы и модели для класса CreateView выглядит аналогичным образом.
Логика отображения для удаления объекта несколько отличается от рассмотренных предыдущих классов в данной статье. Удаление объекта, в целях безопасности, доступно лишь после передачи post или delete запроса. В случае get запроса будет отображена страница с подтверждением удаления объекта. В самом минималистичном варианте она может представлять из себя форму с кнопкой отправки и csrf токеном:
Отображение может выглядеть следующим образом:
Разумеется если вам потребуются соответсвующие проверки на наличие авторизации у пользователей или соответствующих прав, то вы можете сделать это используя декораторы для метода dispatch или добавить свою логику проверки:
В данной статье мы рассмотрели работу с формами и управлением объектами, если у вас возникнут какие-либо вопросы, то я или другие читатели, надеюсь, смогут на них ответить. Также прошу сообщить обо всех найденных ошибках или неточностях и предложения по добавлению информации в статью, если я что-то пропустил. Спасибо, что прочитали статью и желаю счастливых выходных =)
Часть 1, часть 2, часть 3, часть 4
Создание и обработка формы с помощью CBV
Для ряда действий, будь то регистрация или авторизация на сайте, публикация новости, комментария или добавление товара в магазине, невозможно обойтись без форм. В качестве универсального инструмента создания форм в Django выступает класс FormView. В самом просто случае для создания работоспособной формы достаточно лишь передать ему лишь ссылку на класс, описывающий необходимую форму:
from django.views.generic.edit import FormView class RegisterForm(FormView): form_class = Register success_url = '/thanks/'
или передать нужные данные непосредственно экземпляру класса FormView в нашем urlconf:
url(r'^register/$', FormView.as_view(form_class=Register, success_url='/thanks/')
Note: Пример синтетический и, разумеется, в таком виде использовать для страницы регистрации не получится.
Класс формы, который необходимо обработать, возвращается методом get_form_class. По умолчанию данный метод возвращает атрибут form_class, которому мы присваивали класс нашей формы в примере выше. Мы можем переопределить данный метод, если нам требуется более сложная логика в определении класса формы.
Метод get_success_url возвращает url ссылку, на которую будет осуществляться переход после успешной обработки формы. По умолчанию данный метод возвращает атрибут success_url.
Для указания полям формы значений по умолчанию мы можем передать их непосредственно в атрибут initial, представляющий из себя словарь, ключи которого должны иметь имена требуемых полей формы. Значение данного атрибута возвращается по умолчанию методом get_initial.
Часто возникает необходимость передать в форму определенные данные, например объект пользователя или заранее определенный список разделов. Для данного действия подходит метод get_form_kwargs. При переопределении данного метода необходимо соблюдать осторожность и не переписать случайно данные, передаваемые в форму по умолчанию. Среди них:
def get_form_kwargs(self): """ Возвращает словарь аргументов для экземпляра формы """ kwargs = {'initial': self.get_initial()} if self.request.method in ('POST', 'PUT'): kwargs.update({ 'data': self.request.POST, 'files': self.request.FILES, }) return kwargs
Чтобы избежать потери этих данных м�� должны сначала получить словарь из родительского класса, затем добавить в него требуемые данные:
class ProductForm(FormView): def get_form_kwargs(self): kwargs = super(ProductForm, self).get_form_kwargs() kwargs.update({ 'sections': Section.objects.filter(is_active=True) }) return kwargs
Для получения класса нашей формы мы можем использовать метод get_form, который по умолчанию возвращает класс формы, указанный через метод form_class, с переданным ему словарем метода get_form_kwargs:
def get_form(self, form_class): return form_class(**self.get_form_kwargs())
При обработке формы, в случае успеха, Django вызывает метод form_valid нашего отображения. По умолчанию данный метод осуществляет редирект по ссылке, возвращаемой методом get_success_url.
В случае, когда форме переданы некорректные данные вызывается метод form_invalid, который по умолчанию возвращает пользователя обратно на страницу формы, передавая ей объект со списком ошибок валидации.
class CreatePost(FormView): form_class = PostForm template_name = 'create_post.html' success_url = '/success/' @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): super(CreatePost, self).dispatch(request, *args, **kwargs) def form_valid(self, form): Post.objects.create(**form.cleaned_data) return redirect(self.get_success_url())
Теперь рассмотрим разные сферы применения форм более подробно.
Создание нового экземпляра объекта
С помощью примера выше мы можем с легкостью создать новый объект статьи, однако в Django есть средства, позволяющие создать объект с еще большей легкостью, это класс CreateView. Для применения данного класса, передаваемая ему форма должна наследоваться от ModelForm:
from django import forms class NewsForm(forms.ModelForm): class Meta(object): model = News exclude = ('status',)
Теперь мы можем передать объект данной формы в наше отображение. Пример отображения почти аналогичен предыдущему:
from django.views.generic.edit import CreateView class CreateNews(CreateView): form_class = NewsForm template_name = 'create_news.html' succes_url = '/success/' def form_valid(self, form): Post.objects.create(**form.cleaned_data) return redirect(self.get_success_url())
Если необходимо провести более сложные действия перед сохранением модели (проставить внешние ключи, добавить дополнительную информацию), то более подходящим способом это сделать будет следующий пример (спасибо пользователю marazmiki):
def form_valid(self, form): # Мы используем ModelForm, а его метод save() возвращает инстанс # модели, связанный с формой. Аргумент commit=False говорит о том, что # записывать модель в базу рановато. instance = form.save(commit=False) # Теперь, когда у нас есть несохранённая модель, можно ей чего-нибудь # накрутить. Например, заполнить внешний ключ на auth.User. У нас же # блог, а не анонимный имижборд, правда? instance.user = request.user # А теперь можно сохранить в базу instance.save() return redirect(self.get_success_url())
Note: Определение метода form_valid может быть излишне, так как CreateView наследует ModelFormMixin, который сохраняет экземпляр объекта из формы автоматически.
Для обработки ошибок также используется метод form_invalid, функциональность которого аналогична оной класса FormView.
Обновление экземпляра объекта
Основное отличие класса UpdateView от CreateView, это передача экземпляра изменяемого объекта атрибуту object данного класса, в остальном данные классы идентичны. Для редактирования нам достаточно передать в url первичный ключ или slug изменяемого объекта:
# Маршрут в urlconf url(r'^item/(?P<pk>\d+)/edit/$', ItemUpdate.as_view()),
# Отображение в views.py from django.views.generic.edit import UpdateView class ItemUpdate(UpdateView): form_class = ItemForm model = Item template_name = 'create_item.html' success_url = '/success/'
# Форма form django import forms class NewsForm(forms.ModelForm): class Meta(object): model = Item exclude = ('status',)
# Модель from django.db import models class Item(models.Model): name = models.CharField(max_length=32, verbose_name=u'Название') description = models.TextField(verbose_name=u'Описание') status = models.BooleanField(default=True) def __unicode__(self): return self.name
Описание формы и модели для класса CreateView выглядит аналогичным образом.
Удаление экземпляра объекта
Логика отображения для удаления объекта несколько отличается от рассмотренных предыдущих классов в данной статье. Удаление объекта, в целях безопасности, доступно лишь после передачи post или delete запроса. В случае get запроса будет отображена страница с подтверждением удаления объекта. В самом минималистичном варианте она может представлять из себя форму с кнопкой отправки и csrf токеном:
<!-- item_confirm_delete.html --> <form action="" method="post"> {% csrf_token %} <button>Удалить</button> </form>
Отображение может выглядеть следующим образом:
from django.views.generic.edit import DeleteView class ItemDelete(DeleteView): model = Item template_name = 'item_confirm_delete.html' success_url = '/success/'
Разумеется если вам потребуются соответсвующие проверки на наличие авторизации у пользователей или соответствующих прав, то вы можете сделать это используя декораторы для метода dispatch или добавить свою логику проверки:
from django.views.generic.edit import DeleteView class ItemDelete(DeleteView): model = Item template_name = 'item_confirm_delete.html' success_url = '/success/' @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): super(ItemDelete, self).dispatch(request, *args, **kwargs)
В данной статье мы рассмотрели работу с формами и управлением объектами, если у вас возникнут какие-либо вопросы, то я или другие читатели, надеюсь, смогут на них ответить. Также прошу сообщить обо всех найденных ошибках или неточностях и предложения по добавлению информации в статью, если я что-то пропустил. Спасибо, что прочитали статью и желаю счастливых выходных =)
