2

I have been trying for weeks to see how I return validation errors defined in my forms.py and pass it to Ajax, I saw a couple of solutions online and thier Django versions are either too old or the Django and JS codes are too complicated. I want someone to help me out using code samples to demonstrate how this is achievable. I want both error messages coming from Django to displayed in my webpage as well as success message. Below is what I have done so far.

forms.py

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

class UserCreateForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email')

    def clean_email(self):
        email = self.cleaned_data['email']
        if User.objects.filter(email=email).exists():
            raise forms.ValidationError("Email already exists.")
        return email

    def clean(self):
        cleaned_data = super().clean()
        email = cleaned_data.get('email')
        vmail = cleaned_data.get('vemail')

        if email != vmail:
            raise forms.ValidationError('Your first email and second email must match')
        elif not email.endswith('@alabiansolutions.com'):
            raise forms.ValidationError('Please we need alabiansolution email')

views.py

from django.shortcuts import render
from django.views.generic import ListView, View, CreateView
from ajax_app.forms import UserCreateForm
from django.urls import reverse_lazy 

# Create your views here.
def user_create_view(request):
    if request.method == 'POST':
        user_form = UserCreateForm(request.POST)
        if user_form.is_valid():
            user_form.save()
    else:
        user_form = UserCreateForm()
    return render(request, 'ajax_app/index.html', {'user_create_form':user_form})

urls.py

from django.contrib import admin
from django.urls import path
from ajax_app import views 

urlpatterns = [
    path('',  views.user_create_view, name='user_create_view'),
]

index.html

{% if user_create_form.non_field_errors %}
  <div class="well well-error">
    {% for error in user_create_form.non_field_errors %}
      <ul class="list-unstyled">
        <li class="text-danger">
          <i class="fa fa-exclamation-circle" aria-hidden="true"></i>
            <strong>&nbsp;{{ error|escape }}</strong>
          </li>
        </ul>
    {% endfor %}
  </div>
{% endif %}
        <h3>Add Data</h3>
       <form id="addUser" action="{% url 'user_create_view' %}" method="POST">
        <table>
            {{ user_create_form.as_table}}
        </table>
        {% csrf_token %}
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>

script.js

// Create Django Ajax Call
$("form#addUser").submit(function() {
        var form = $("#addUser");
        // Create Ajax Call
        $.ajax({
            url: form.attr("action"),
            data: form.serialize(),
            dataType: 'json',
            success: function (data) {
                // I don't know next step
            }
        });

    $('form#addUser').trigger("reset");
    return false;
});

2 Answers 2

1

Form Validation cannot be shown to ajax directly. However you can raise the HTTP error instead of validation error and then, can show it in the ajax error function. Here is the example:-

Approach 1:

# Return this instead of validation error
return HttpResponse('Error text', status=HTTP_404_NOT_FOUND)

# Ajax error method which will come after success method
error: function(jqXHR, exception) 
    alert(jqXHR.responseText);
}

Approach 2:

# Return Json Resposne instead of validationerror
return JsonResponse({'error': True, 'message': 'text'})

#Ajax success function
success: function(data) {
   if (data.hasOwnProperty('error')) {
        if (data.error==true) {
          alert(data.message);
        }
      }
  }, 
Sign up to request clarification or add additional context in comments.

Comments

1

urls.py

from django.contrib import admin
from django.urls import path
from ajax_app import views 

urlpatterns = [
    path('',  views.index, name='index'),
    path('ajax_form/',  views.ajax_submit, name='ajax_submit'),
]

forms.py

from django.utils.translation import ugettext_lazy as _
from django import forms


class MyForm(forms.Form):

    name = forms.CharField(
        label=_('Name'),
        max_length=255,
        required=True,
        widget=forms.TextInput(
            attrs={'class': 'form-control', 'name': 'name', }
        )
    )

    email = forms.EmailField(
        label=_('Email'),
        max_length=255,
        required=True,
        widget=forms.EmailInput(
            attrs={'class': 'form-control', 'name': 'email', }
        )
    )

    def clean_email(self):

        email = self.cleaned_data['email']
        # Validation Example
        if email != '[email protected]':
            raise forms.ValidationError("Email already exists.")

        return email

view.py

from django.shortcuts import render
from django.http import QueryDict
from .forms import *


def index(request):
    """
    Show Inital Form
    :param request:
    :return:
    """
    form = MyForm()

    return render(request, 'ajax_app/index.html', {'form': form})


def ajax_submit(request):
    """
    Ajax call
    :param request:
    :return:
    """
    if request.method == 'POST':

        form_data = QueryDict(request.POST['form'].encode('ASCII'))

        form = MyForm(form_data)
        if form.is_valid():
            name = form.cleaned_data.get('name', None)
            # Do some here

    return render(request, 'ajax_app/form.html', {'form': form})

form.html

<div class="form-group {% if form.name.errors %}has-error{% endif %}">
  {{ form.name.label_tag }}
  {{ form.name }}
  {% if form.name.help_text %}
    <span class="help-block">{{ form.name.help_text }}</span>
  {% endif %}
  {% for error in form.name.errors %}
    <span class="help-block">{{ error }}</span>
  {% endfor %}
</div> <!-- form-group -->

<div class="form-group {% if form.email.errors %}has-error{% endif %}">
  {{ form.email.label_tag }}
  {{ form.email }}
  {% if form.email.help_text %}
    <span class="help-block">{{ form.email.help_text }}</span>
  {% endif %}
  {% for error in form.email.errors %}
    <span class="help-block">{{ error }}</span>
  {% endfor %}
</div> <!-- form-group -->

or

<table>
    {{ form.as_table}}
</table>

index.html

...
<h3>Add Data</h3>
<form id="addUser" action="{% url 'ajax_submit' %}" method="POST">
  {% csrf_token %}
  <div class="form-container">
    {% include "ajax_app/form.html" %}
  </div>

  <button type="submit" class="btn btn-primary">Submit</button>
</form>
...

Ajax

This script must be executed after loading jquery

$("form#addUser").submit(function(e) {
  e.preventDefault(); // <--

  var csrftoken = jQuery('[name=csrfmiddlewaretoken]').val();
  var form = $("#addUser");

  $.ajax({
    method: form.attr("method"),
    url: form.attr("action"),
    data: {
        csrfmiddlewaretoken: csrftoken,
        form: form.serialize()
    },
    dataType: 'Html',
    success: function (data) {
        $('.form-container').html(data);  // <--
    }
});

2 Comments

Thanks @Jacek B Budzynski for help it still did not work, When I checked my console I was seeing "Failed to load resource: the server responded with a status of 500 (Internal Server Error)"
@ifeke.ibe I have modified my post and I have put an example of how I implement this behavior in my projects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.