Django — обработка ошибок в ajax-формах

    Hello everyone!

    Все мы знаем что Django — очень мощный и динамично развивающийся фреймворк для создания веб-приложений. Однако, несмотря на наступление эпохи Веб 2.0, в нём всё ещё нет встроенных механизмов для работы с AJAX, в частности отправки и проверки форм. Возможно django просто не хочет навязывать пользователю какой-то js-фреймворк и хочет оставаться гибкой в этом вопросе, но так или иначе при разработке часто требуются формы, работающие через ajax, без перезагрузок страниц.
    О создании таких форм и работе с ними и пойдёт речь в данной статье.

    Сразу оговорюсь, что идея не нова, и существует несколько библиотек, реализующих требуемую функциональность, например одна из них — http://www.dajaxproject.com/.
    Для тех же, кто предпочитает сам управлять взаимодействием клиента с сервером или тех, кто не хочет втягивать в проект дополнительную библиотеку и иметь дело с её багами, я расскажу как изобрести велосипед реализовать механизм самостоятельно и опишу различные способы решения проблемы.

    Форма


    Для примера возьмём простую форму регистрации пользователя на сайте:
    class RegisterForm(forms.Form):
        email = forms.EmailField()
        password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
        password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput)
    

    В реальной жизни вы, скорее всего, будете наследовать эту форму от модели данных, но для нашего примера это несущественно.

    Вывод формы


    Для отображения этой формы на странице у нас есть два варианта:
    • Сделать контейнер с display:none внутри всех страниц, с которых можно вызывать форму (или внутри родительского шаблона), затем с помощью JS создавать диалог из этого контейнера.
    • Подгружать форму через ajax с отдельного URL, и затем также создавать диалог.

    Преимущество первого варианта — в его скорости работы (не надо делать дополнительного запроса к серверу), зато во втором варианте можно использовать один и тот же view для обработки GET и POST запросов к форме (POST нам потребуется в обоих случаях), плюс мы делаем отдельный файл шаблона для вывода формы, что делает структуру кода более упорядоченной, хотя это конечно дело вкуса.
    Лично я внедряю что-то в шаблон страницы только если это простой диалог типа да/нет, а для форм всегда использую отдельные view.
    Поэтому остановимся здесь на отдельном представлении для формы, тогда код будет выглядеть следующим образом:
    • view:
      def register(request):
          form = RegisterForm()
          return direct_to_template(request, "register.html", extra_context={'form': form })
      

    • template:
      {% load i18n %}
      <form id="register_form" method="post" action="{% url register %}">
          {% csrf_token %}
          <ul>
              {{ form.as_ul }}
              <li><span id="register">{% trans "Register" %}</span></li>
          </ul>
      </form>
      

    Обработка формы


    Переходим к обработке формы. Здесь необходимо учесть, что ajax-обработчик должен как-то понимать, была ли форма успешно проверена или в ней присутствуют ошибки. Логичным решением здесь, на мой взгляд, будет использование JSON. В ответе сервера будет содержаться 2 параметра, первый из которых — булевый, будет сообщать об успешности или неудаче проверки формы. Со вторым параметром опять же есть различные варианты:
    • В случае успешной проверки формы этот параметр может быть пустым, так как форма логина скорее всего перенаправляет пользователя на необходимый url после входа и нам неважно что там, либо это может быть строка, которую необходимо отобразить в диалоге подтверждения.
    • В случае когда в форме присутствуют ошибки снова возможно 2 способа отображения:
      1. Первый способ состоит в том, чтобы заново отрендерить форму с ошибками через шаблон и весь html-ответ поместить в json-переменную, которая затем заменяет содержимое всей формы.
      2. Второй способ — создать массив ошибок для всех полей формы и разместить его в json-переменной, затем вывести ошибки для каждого поля в цикле.
    Второй вариант идейно мне нравится больше, так как отображает только то, что нужно, без замены всей формы. Здесь я покажу как реализовать оба способа. Код обработки формы на стороне клиента использует популярный JS-фреймворк jQuery и плагин к нему под названием jQuery Form Plugin.
    1. Первый способ:

      Финальная версия view:
      def register(request):
          if request.method == 'POST':
              form = RegisterForm(request.POST)
              if form.is_valid():
                  # Обработка
                  # ...
                  return HttpResponse(simplejson.dumps({'response': _("Email with a confirmation link has been sent"), 'result': 'success'}))
              else:
                  t = loader.get_template('register.html')
                  ctx = RequestContext(request, {'form': form})
                  response = t.render(ctx)
                  return HttpResponse(simplejson.dumps({'response': unicode(response), 'result': 'error'}))
          form = RegisterForm()
          return direct_to_template(request, "register.html", extra_context={'form': form })
      


      Обработка на стороне клиента, javascript:
      $(document).ready(function() {
          $('#register').live('click', function() {
              $('#register_form').ajaxSubmit({
                  success: function(data, statusText, xhr, $form) {
                      // Удаляем ошибки если были
                      $form.find('.error').remove();
                      if (data['result'] == 'success') {
                          // Делаем что-то полезное
                      }
                      else if (data['result'] == 'error') {
                          // Показываем ошибки
                          $form.replaceWith(data['response']);
                      }
                  },
                  dataType: 'json'
              });
          });
      }
      
    2. Второй способ:

      Финальная версия view:
      def register(request):
          if request.method == 'POST':
              form = RegisterForm(request.POST)
              if form.is_valid():
                  # Обработка
                  # ...
                  return HttpResponse(simplejson.dumps({'response': _("Email with a confirmation link has been sent"), 'result': 'success'}))
              else:
                  # Заполняем словарь response ошибками формы, ключ - название поля
                  response = {}
                  for k in form.errors:
                      # Теоретически у поля может быть несколько ошибок...
                      response[k] = form.errors[k][0]
                  return HttpResponse(simplejson.dumps({'response': response, 'result': 'error'}))
          form = RegisterForm()
          return direct_to_template(request, "register.html", extra_context={'form': form })
      


      Обработка на стороне клиента, javascript:
      function display_form_errors(errors, $form) {
          for (var k in errors) {
              $form.find('input[name=' + k + ']').after('<div class="error">' + errors[k] + '</div>');
          }
      }
      
      $(document).ready(function() {
          $('#register').live('click', function() {
              $('#register_form').ajaxSubmit({
                  success: function(data, statusText, xhr, $form) {
                      // Удаляем ошибки если были
                      $form.find('.error').remove();
                      if (data['result'] == 'success') {
                          // Делаем что-то полезное
                      }
                      else if (data['result'] == 'error') {
                          // Показываем ошибки
                          display_form_errors(data['response'], $form);
                      }
                  },
                  dataType: 'json'
              });
          });
      }
      
    Стоит также заметить, что при использовании второго способа и описанного ранее шаблона формы, ошибки будут отображаться с использованием элемента списка <ul>, для другого отображения необходимо сделать другой шаблон либо переопределить класс ошибок для формы.

    Вот и всё. Прилагаю скриншоты получившейся формы в различных состояниях:

    image

    Буду рад услышать комментарии и узнать другие способы работы с ajax-формами.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 38

      0
      А почему вы не проверяете запрос на ajax? Вдруг у пользователя отключен js, будете писать отдельный view?
        0
        Согласен, в общем случае нужно проверять, но здесь не стал делать чтобы не усложнять код.
        На самом деле именно в моём примере кода при отключенном JS сабмит формы вообще не произойдёт, но это легко исправляется заменой span на input.
        Плюс, если вы хотите чтобы форма умела обрабатывать ошибки про отключенном JS, нужно будет написать ещё один темплейт, расширяющий базовый, чтобы он был в стиле сайта.
          +1
          Кстати, я вот тут так делал и напоролся на проблему: в некоторых версиях оперы мини и в стандартном браузере на нокиях заголовок аякс-запроса не присоединяется, т.е. отправляется как обычный http-запрос (соответственно, вьюха просто возвращает конечную страницу или редирект). С тех пор на всякий случай привешиваю get-параметр ajax=y к строке адреса :(
          0
          Мне кажется вы забыли про ошибки, которые не привязаны к конкретному полю (form.non_field_error). В js они никак не обратаваются
            0
            Да, такие тоже есть, но при желании их можно добавить аналогичным образом.
            0
            это все хорошо но когда это аякс иногда валидация с сервера, даже при асинхронном запросе, работает мягко говоря мучительно, особенно если форма большая и сложная. мне в проекте пришлось дописывать еще клиент-сайд валидаторы, и только после валидности всех полей идет запрос аякса. хотелось бы видеть автоматическую генерацию таких вот правил, или хотя бы либу для прописывания их в формах а не отдельно, но пока это только мечты :)
              0
              Это интересная мысль кстати, за несколько минут поиска наткнулся вот на это
              http://code.google.com/p/django-ajax-forms/
              Может быть это то, что нужно?
                0
                но просто так он ведь не может «узнать» правила валидации, базовые, конечно, но ведь есть нюансы…
              0
              www.dajaxproject.com/fullform/ Не очень красиво это выглядит, но тоже работает. Однако ж, нарушает MVC.
                +1
                dajaxproject.com — писать на питоне, чтобы не писать на js? Я до сих пор не могу простить авторам джанги forms и widget, которые вообще никак не вписываются ни в mvt, ни в mvc — чтобы поменять css класс — надо лезть в forms.py, потом искать виджет, а если не повезет, то еще и в темплейт виджета.
                    +1
                    Так… Нужно разобраться, что это нам дает. Зачем формы стали описывать на Питоне? Ведь это же очень неудобно: html-атрибуты, тексты кнопок, подписи к полям — все приходится держать внутри view, а не в шаблоне.

                    Все перенести в шаблон и только подставлять данные полей — не получится. Бывают динамические формы, собрать которые в шаблоне будет очень тяжело. Например, набор полей или список опций может зависеть от каких-то параметров:

                    {% if action == 'gift' or action == 'change' %}
                        <dl>
                            <dt>
                                <label for="{{ prefix_id }}-conditions">{{ product_form.conditions.label }}</label>
                            </dt>
                            <dd>
                                {{ product_form.conditions }}
                                {{ product_form.conditions.errors }}
                            </dd>
                        </dl>
                    {% endif %}
                    

                    О боже! Логика в шаблоне!!!

                    Бывают сложные формы, в которых редактируется сразу несколько объектов, иерархически связанных друг с другом. Нужно делать «размножаемые» поля. Кстати, все эти готовые ajax-решения начинают нервно курить в углу на таких формах.

                    Еще есть поля management_form, которые в шаблонах не нуждаются.

                    Получается, проще все перенести в Питон.

                    С другой стороны, если форму нужно вывести каким-то нестандартным образом (например, в две колонки), в шаблоне придется отказаться от вывода всей формы целиком и работать с отдельными полями.


                    Насчет widget-tweaks

                    Я не очень понимаю, чем в общем случае вот этот код:

                    {{ form.title|add_class:"css_class_1 css_class_2" }}

                    лучше простого вывода поля в виде html:

                    <input class="css_class_1 css_class_2" name="title" id="{{ prefix_id }}-title" />
                    <label for="{{ prefix_id }}-title">{{ form.title.label }}</label>
                    


                    То есть, он лучше в том конкретном случае, когда вид формы совсем не статический и с ее формированием хорошо справляется чужой view, но очень нужно поменять какую-то мелочь (класс или атрибут добавить).
                      +2
                      Про рассуждения насчет логики в шаблонах. Если часть полей не нужна, или какие-то зависимости, то их и проверять не нужно/нужно по-другому на сервере, и это логика не только вывода формы, но и проверки. Ее все равно т.е., получается, в питоне писать. Это конечно же не логика шаблона.

                      Я не очень понимаю, чем в общем случае вот этот код:

                      {{ form.title|add_class:"css_class_1 css_class_2" }}


                      лучше простого вывода поля в виде html:

                      <input class="css_class_1 css_class_2" name="title" id="{{ prefix_id }}-title" />
                      <label for="{{ prefix_id }}-title">{{ form.title.label }}</label>
                      



                      Как чем лучше? Меньше писать, меньше дублирования, нет необходимости передавать префиксы и следить за тем, как формируется параметры у формы (например, в name=«title» не учтен возможный префикс формы).

                      Не бывает общих случаев на практике) Конечно, это инструмент, он для решения определенных задач (imho встречающихся часто, особенно если версткой шаблонов занимается верстальщик). ACCOUNT задачу обозначил, по-моему django-widget-tweaks ее более-менее решает.

                      Поменять класс или атрибут — это же при удачной front-end части не мелочь, а все, что необходимо для смены внешнего вида и поведения поля.

                      Возьмем, например, кусок с dl/dt/dd. Берем и выносим его в шаблон:

                      {# fields/as_dl.html #}
                      <dl>
                          <dt>
                              {{ field.label_tag }}}
                          </dt>
                          <dd>
                              {{ field }}
                              {{ field.errors }}
                          </dd>
                      </dl>
                      


                      Делаем это для всех других видов верстки полей, встречающихся в проекте. Если каждое поле верстается по-своему — это уже клиника все-таки, или проект очень маленький. Да и что тут сделаешь, если каждое поле верстается по-своему. Но обычно во всех формах примерно одно и то же ведь, если верстка вменяемая.

                      Дальше мы поля выводим:

                      <form action='.' method='POST'> {% csrf_token %}
                          {% include 'fields/as_dl.html' with field=product_form.title %}
                          {% include 'fields/as_dl.html' with field=product_form.conditions %}
                      </form>
                      


                      а потом хотим там заменить css-класс у одного из полей — по дизайну так нужно:

                      <form action='.' method='POST'> {% csrf_token %}
                          {% include 'fields/as_dl.html' with field=form.title %}
                          {% include 'fields/as_dl.html' with field=form.conditions|add_class:"foo" %}
                      </form>
                      


                      можно поля и в цикле вывести:

                      {% for field in product_form %}
                          {% include 'fields/as_dl.html' %}
                      {% endfor %}
                      


                      Можно и для форм сниппеты сделать под свой проект.

                      В случаях посложнее — откатываемся назад на обычные методы. По-моему всяко лучше, чем безусловно все копипастить. И обошлись тут стандартными средствами, ну + еще маленькой библиотечкой (которая, по сути, тоже стандартные средства и использует, просто позволяет в шаблоне решения об атрибутах виджета принимать, а не в объявлении формы на питоне).
                        0
                        django-widget-tweaks — хорошая штука, да.

                        Я просто не люблю все, что с html-формами связано. Мне все решения кажутся неудачными, т.к. всегда найдется такой случай, для которого конкретное решение подходит плохо. Ваши примеры выглядят красиво. Умеете успешно применить стандартные средства.
                          0
                          спасибо) А так ведь всегда — с чем угодно можно найти случай, для которого решение плохо подойдет. При этом хорошо, когда есть возможность убрать мешающий слой абстракции — а с выводом формам возможность есть, написать html да и все. В django ORM то же самое хорошо — если запрос составляется с трудом, можно QuerySet API не гнуть, а на raw откатиться.

                          Проблема еще в том, что супер-универсальные абстрактные java-style решения обычно сложными получаются.

                          В GSoC'11 есть довольно перспективный proposal от Gregor Müllegger о том, как сделать вывод форм в django поудобнее и погибче. Если есть что сказать по этому поводу — почитайте обсуждения и напишите туда свои мысли, сейчас самое время.
                            +1
                            а по-моему, суета) все это. нет ни какой радости от шаблонов, в которых 90% занимает логика. в таких случаях, dsl шаблонизатора ужасен и в разработке, и в отладке, и в поддержке. поэтому логика рисования форм изначально кодилась на python. чтобы понять, во что выльется сея безумная затея GSoC'11 достаточно посмотреть на шаблоны админки — code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/change_form.html. собственно html'я в методах рендера форм на самом деле чуть — в основном логика: code.djangoproject.com/browser/django/trunk/django/forms/widgets.py. поэтому, на следующий год кто-нибудь решит переписать обратно на python. :)

                            эти студенческие метания могут прекратиться только в том случае, когда у страницы появится нормальное объектное представление, которое обеспечит возможность описывать и твикать его как из шаблона, так и из кода на python (по типу www.livinglogic.de/Python/xist/xsc/index.html). плюс AST-представление, чтобы дать возможность компилировать шаблоны не только в python, но и другие языки (например в javascript для рендера страниц на клиенте). примеры есть github.com/mkerrin/pwt.jinja2js, или в том же xist.
                  0
                  Было бы неплохо, если бы вы выложили файлы как готовый проект из коробки, потому как подобные вещи очень помогают новичкам Джанги.
                    0
                    На самом деле я причесал эти файлы из реального проекта специально для статьи, но я попробую что-нибудь придумать.
                    0
                    Я ошибки в джанго-формах проверяю следующим образом:

                    делаю

                    И в методе-обработчике формы проверяю — если метод get, то просто отобразить данные, если post — то проверить, и, в случае валидности формы, показать. Иначе вывести ошибки.

                        def object_edit_or_add_post_save(self, request, entity_name, object_id=None):
                            self.check_the_entity(entity_name)
                            
                            if request.method == 'GET':
                                """ если GET, то запрашивается страница """
                                return self.object_edit_or_add(request, entity_name, object_id)
                            elif request.method == 'POST':
                                """ если POST, то передаются данные """
                                return self.object_save(request, entity_name, object_id)
                    
                    
                        def object_save(self, request, entity_name, object_id=None):
                            ...
                            if f.is_valid():
                                f.save()
                                return HttpResponseRedirect(self.root + entity_name)
                            else:
                                # ищем ошибки
                                for e, e_message in f.errors.items():
                                    field = f.fields[e]
                                    field.error = True
                                    field.error_message = e_message
                            ...
                    
                    


                    	<form name="edit" method="post" action="">
                    	{% csrf_token %} 
                    	...
                    	</form>
                    

                      0
                      Парсер съел теги. Я писал что делаю у формы action="" для ссылки страницы саму на себя.
                        0
                        Эм, раз форма постится на ту же страницу значит речь идёт о форме на отдельной странице всё-таки?
                          0
                          Да, именно так. Ну если на странице больше нет форм, которые надо проверять, и точно не появятся — то это как раз описанный мною случай.
                      +1
                      Да, спасибо за пост — статьи по джанго радуют.
                        0
                        Судя по скриншотам у вас форма отображается во всплывающем окне. Так вот ещё один способ реализации «AJAX» формы — показывать iframe с обыкновенной страницей обработки формы, естественно базовый шаблон для такой страницы нужно сделать минималистичным и ещё нужно как-то обрабатывать успешность регистрации — закрывать это окошко с iframe, как минимум.
                          0
                          Спасибо, а можете просветить насчёт iframe, у меня почему-то очень давно укоренился стереотип что iframe — это плохо, его нормально вообще использовать сейчас?
                            0
                            Раз вы думаете, что «iframe — это плохо», что бы это ни значило, то расскажите для начала, чем плох iframe и для кого он плох :)
                              0
                              Так я же не помню, вот и хочу узнать бред ли это или есть какие-то проблемы с использованием iframe.
                                0
                                Я считаю, что как быстрое решение для того, чтобы сварганить форму во всплывающем окошке iframe хорошее решение. Есть проблема с оформлением размеров блока, содержащего iframe — после отправки формы с ошибочными данными, мы получим ту же форму + ошибки т.е. высота нового содержимого будет выше чем высота пустой формы, если javascript-библиотека не умеет изменять размер окна в случае измененения содержимого iframe, то мы получим полосу прокрутки или надо изначально задавать высоту окна с запасом. Главное преимущество iframe-решения в том, что мы работаем с обычными джанговскими вьюшкой и формой.
                                  0
                                  Спасибо, теперь понятно
                              0
                              Даже если и «не нормально», то залить асинхронно файлы яваскриптом на сервер никак по другому нельзя, поэтому как минимум для этого придется его использовать.
                            0
                            Привет всем, в своем веб-приложении мне необходимо изменять и добавлять данные по еще пока не известной модели, как через ajax так и через обычную форму.
                            Естественно я использовал modelform'ы, и очень удобную разработку под название dojango. Dojango элементарно устанавливается и теперь наши django виджеты превращаются на выходе в виде dojo виджетов c той валидацией что мы определили в модели\форме.
                            Теперь осталось просто вывести форму в виде html — form.as_ul(), и ждать ответа.

                            Dojo виджеты нам обеспечат валидацию на стороне клиента, из нашей формы без грамма кода. А серверную валидацию надо обеспечить нам.

                            Вот мой код для вывода формы\валидации и оправки ошибок\и если нет ошибок то перенаправления на объект.
                            Боюсь что код не прапарсится, вот ссылка на него
                            def show_form(request,oper,id=None):
                            #print request.path
                            import newdisp.whs.models as models # Все модели берем, и доставать нужную будем через getattr
                            try:
                            f=getattr(models,oper+'_form') # Берем
                            except AttributeError,e: #Ловим неправильные название форм
                            raise Http404('Page not found') # как вариант возвращять json({'status':'error'})

                            if 'id' in request.POST: # Переменые в запросах приходят строками, делаем в int
                            id = int(request.POST['id'])

                            if id is None: #Если нет айди значит добавление
                            m=getattr(models,oper)() # Берем модель, и вызываем ее без параметров, что означает пустому экземпляру.
                            else: # Значит изменение
                            id=int(id) #еще раз
                            try:
                            m=getattr(models,oper).objects.get(pk=id) # Берем модель с данными которые будем изменять
                            except ObjectDoesNotExist,e:
                            raise Http404('Page not found')


                            if request.method == 'POST': # Если пост то обрабатываем данные, если гет то вывод html формы
                            post=request.POST.copy() # Копируем массив, ибо request — read only
                            if 'price' in post.keys(): # Заменяем замечательные русские запятые в float числах
                            post['price']=post['price'].replace(',','.')
                            if 'delivery' in post.keys():
                            post['delivery']=post['delivery'].replace(',','.')

                            form = f(post,instance=m) # Создаем форму и наполняем ее даными из модели

                            if form.is_valid(): # Если ошибок нет, то сохраняем и редиректив на ссылку
                            # где ей отдадут json данные модели
                            inst = form.save()
                            return HttpResponseRedirect('/whs/id/%s/%d' % (oper,inst.id))
                            else: # Если ошибки, вернуть json со статусом ошибки и сообщения ошибки
                            re={'status':'error','message':form.errors}
                            return HttpResponse(json(re),mimetype=«application/json»)
                            else:
                            form = f(instance=m) # вывод html формы
                            if request.is_ajax(): # Если jax то вернуть просто html, я оберну ее в форму на стороне клиента
                            return HttpResponse(form.as_ul(),mimetype=«text/html») #Если ajax срем говый вариантик

                            # Если обычный, то обрабатываем. Это надо сделать через шаблон.
                            re=u' '
                            re+=u''
                            re+=form.as_ul() # Вывести ее как список
                            #re+=u''
                            re+=u''
                            re+=u''
                            return HttpResponse(re,mimetype=«text/html»)

                            На стоне клиента надо написать код на dojo, чтобы забрать форму, пропарсить его dojo.parser, и создать xhtPost формы.
                            При попытке отправки формы, dojo проверит данные еще раз на соответсвие типам, и отправит данные.
                            Дальше их поймает django, проверит на логичность(например повторение уникальных значений) и сгенерирует текст ошибки на чистом русском языке, что мы и отправим обратно форме в виде json
                            Например:
                            {
                            status: «error»
                            -message: {
                            -number: [
                            «Накладная с таким № документа уже существует.»
                            ]
                            }
                            }
                            Осталось растолкать это по полям формы dojo.

                            if (result.status == 'error') {
                            for (var i in result.message) {
                            var input = dijit.byNode(dojo.query('.dijit [name="' + i + '"]', this.form.containerNode)[0].parentNode.parentNode);
                            input.state = 'Error';
                            input._setStateClass();
                            dijit.setWaiState(input, 'invalid', 'true');
                            input._maskValidSubsetError = true;
                            dijit.showTooltip(result.message[i], input.domNode, input.tooltipPosition);
                            }
                            }
                            else {
                            alert('СХОРАНЕНО');
                            //return result;
                            }
                            Вот клиентская валидация:

                            А вот уже ответ с сервера(заметьте сообщения создано автоматически и «из коробки» django)
                              0
                              Перепутаны местами варианты в описании по отношению к заявленным пунктам выше в случае описания двух вариантов отображения ошибок в форме.
                                0
                                Спасибо, исправил.
                                0
                                Всё это, конечно, здорово, но маленькую форму можно и без специальных извращений завернуть в ajax, а большую лучше честно отправлять на сервер без всякого ajax-а. Там и файлы могут быть, и ошибки проще так выводить, и всё равно на новую страницу редиректить после обработки действия, так зачем ajax?

                                Вот, что действительно было бы интересно, это валидация форм на клиенте javascript-ом, автоматически генерирующаяся по джанговой форме. Пусть и частичная.
                                  0
                                  А что значит маленькую форму завернуть в ajax без извращений? Вроде бы у меня вполне нормальный способ и подходит для любых форм. И редирект после обработки совсм необязателен, таким образом достигается бОльшая гибкость.
                                  Насчёт валидации форм на клиенте посмотрите комментарии выше, вот здесь например:
                                  http://habrahabr.ru/blogs/django/117876/#comment_3839476
                                    0
                                    Маленькая форма — та, которая выполняет стороннее действие не относящееся к основной цели страницы, форма подписки на рассылку на странице новости, например. Она обычно имеет кастомную вёрстку, может появлятся/прятаться и соответственно общий подход к показу ошибок к ней всё равно не подойдёт, лучше написать небольшую обработку специально для неё, чем пытаться общее решение подогнать.

                                    Если же это страница формы, то и отправляться форма должна по-нормальному и редирект на страницу успеха после поста формы обязателен.
                                      0
                                      Это всё понятно, кастомная вёрстка и т.д., но я так и не услышал как вы предлагаете её в аякс завернуть? разве не придётся делать так же через JSON?
                                        0
                                        Ну да, где ajax, там и JSON. Просто как удобный формат передачи. Но, во-первых, кастомная вёрстка, следовательно не подходит общий метод показа ошибок, плюс для простеньких форм, джанго форма тоже излишня, можно просто вьюху написать, так будет и короче и логичнее (ни к чему лишние сущности). И, таким образом, ничего не остаётся из вашей статьи.

                                        В случае большой формы или формы модели ваш подход смысл как раз имеет. Просто я считаю, что Ajax для отправки формы в таком случае использовать ни к чему. Ни для пользователя, ни для разработчика плюсов-то особых нет. Для разработчика как раз наоборот, лишние телодвижения.

                                Only users with full accounts can post comments. Log in, please.