Spec-Zone.ru › Django 1.8

Обработка форм с использованием представлений на основе классов

Обработка форм обычно проходит по 3 путям:

  • Изначальный GET-запрос (пустая или заполненная форма)
  • POST-запрос с невалидными данными (как правило, повторное отображение формы с ошибками)
  • POST-запрос с валидными данными (обработка данных и, как правило, перенаправление)

Реализация этого самостоятельно часто приводит к большому количеству повторяющегося кода (см. Использование формы в представлении). Чтобы избежать этого, Django предоставляет набор универсальных представлений на основе классов для обработки форм.

Базовые формы

Предположим простую форму обратной связи:

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass

Представление можно создать, используя FormView:

from myapp.forms import ContactForm
from django.views.generic.edit import FormView

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        form.send_email()
        return super(ContactView, self).form_valid(form)

Примечания:

  • FormView наследует TemplateResponseMixin, поэтому template_name можно использовать здесь.
  • По умолчанию реализация form_valid() просто перенаправляет на success_url.

Формы моделей

Универсальные представления действительно хорошо работают с моделями. Эти универсальные представления автоматически создадут ModelForm, если они смогут определить, какую модель использовать:

  • Если задан атрибут model, будет использоваться этот класс модели.
  • Если get_object() возвращает объект, будет использоваться класс этого объекта.
  • Если задан атрибут queryset, будет использоваться модель для этого набора данных.

Представления с формами моделей предоставляют реализацию form_valid(), которая автоматически сохраняет модель. Вы можете переопределить это, если у вас есть особые требования; см. примеры ниже.

Вам даже не нужно предоставлять success_url для CreateView или UpdateView - они будут использовать get_absolute_url() для объекта модели, если он доступен.

Если вы хотите использовать пользовательскую ModelForm (например, для добавления дополнительной валидации), просто установите form_class в вашем представлении.

Примечание

При указании пользовательского класса формы необходимо всё ещё указывать модель, даже если form_class может быть ModelForm.

Сначала нам нужно добавить get_absolute_url() в наш Author класс:

from django.core.urlresolvers import reverse
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=200)

    def get_absolute_url(self):
        return reverse('author-detail', kwargs={'pk': self.pk})

Затем мы можем использовать CreateView и аналогичные, чтобы выполнить фактическую работу. Обратите внимание, что мы здесь просто настраиваем универсальные представления на основе классов; нам не нужно писать свой собственный логику:

from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

class AuthorUpdate(UpdateView):
    model = Author
    fields = ['name']

class AuthorDelete(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')

Примечание

Здесь нужно использовать reverse_lazy(), а не просто reverse, так как URL не загружаются при импорте файла.

Атрибут fields работает так же, как атрибут fields во внутреннем Meta классе ModelForm. Если вы не определите класс формы другим способом, атрибут обязателен, и представление вызовет исключение ImproperlyConfigured, если он не задан.

Если вы укажете и fields, и form_class атрибуты, будет выброшено исключение ImproperlyConfigured.

Исключение атрибута fields ранее разрешалось и приводило к форме со всеми полями модели.

Ранее, если были указаны и fields, и form_class, fields игнорировалось незаметно.

Наконец, мы подключаем эти новые представления к URLconf:

from django.conf.urls import url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete

urlpatterns = [
    # ...
    url(r'author/add/$', AuthorCreate.as_view(), name='author-add'),
    url(r'author/(?P<pk>[0-9]+)/$', AuthorUpdate.as_view(), name='author-update'),
    url(r'author/(?P<pk>[0-9]+)/delete/$', AuthorDelete.as_view(), name='author-delete'),
]

Примечание

Эти представления наследуют SingleObjectTemplateResponseMixin, который использует template_name_suffix для построения template_name на основе модели.

В этом примере:

  • CreateView и UpdateView используют myapp/author_form.html
  • DeleteView использует myapp/author_confirm_delete.html

Если вы хотите иметь отдельные шаблоны для CreateView и UpdateView, вы можете задать либо template_name, либо template_name_suffix в вашем классе представления.

Модели и request.user

Для отслеживания пользователя, создавшего объект с помощью CreateView, вы можете использовать пользовательскую ModelForm для этого. Сначала добавьте отношение внешнего ключа к модели:

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

class Author(models.Model):
    name = models.CharField(max_length=200)
    created_by = models.ForeignKey(User)

    # ...

В представлении убедитесь, что вы не включаете created_by в список полей для редактирования, и переопределите form_valid(), чтобы добавить пользователя:

from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super(AuthorCreate, self).form_valid(form)

Обратите внимание, что вам необходимо отформатировать этот вид с помощью login_required(), или, как альтернативу, обработать неавторизованных пользователей в form_valid().

Пример AJAX

Вот простой пример, показывающий, как вы можете реализовать форму, которая работает как с запросами AJAX, так и с обычными POST-запросами формы:

from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author

class AjaxableResponseMixin(object):
    """
    Mixin to add AJAX support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """
    def form_invalid(self, form):
        response = super(AjaxableResponseMixin, self).form_invalid(form)
        if self.request.is_ajax():
            return JsonResponse(form.errors, status=400)
        else:
            return response

    def form_valid(self, form):
        # We make sure to call the parent's form_valid() method because
        # it might do some processing (in the case of CreateView, it will
        # call form.save() for example).
        response = super(AjaxableResponseMixin, self).form_valid(form)
        if self.request.is_ajax():
            data = {
                'pk': self.object.pk,
            }
            return JsonResponse(data)
        else:
            return response

class AuthorCreate(AjaxableResponseMixin, CreateView):
    model = Author
    fields = ['name']

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.8/topics/class-based-views/generic-editing/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API