4

In my Django project I have modal with form where superuser can create new user.

I want to show ValidationError which I set in forms.py file when superuser by mistake write existing email or passwords are not similar.

Right not when superuser submit form which has mistakes as I described above browser raise error:

SyntaxError: JSON.parse: unexpected character at line 3 column 1 of the JSON data

Uncaught TypeError: a.replace is not a function
    at Function.htmlPrefilter (jquery.min.js:3)
    at qa (jquery.min.js:3)
    at Ja (jquery.min.js:3)
    at r.fn.init.append (jquery.min.js:3)
    at r.fn.init.<anonymous> (jquery.min.js:3)
    at T (jquery.min.js:3)
    at r.fn.init.html (jquery.min.js:3)
    at Object.error (crud.js:45)
    at i (jquery.min.js:2)
    at Object.fireWith [as rejectWith] (jquery.min.js:2)

QUESTION: How to show error messages correctly when data is not valid?

forms.py:

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

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

    def clean_password2(self):
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError(_("Enter the same password as above, for verification."))
        return password2

views.py:

class UserCreateView(CreateView):
    template_name = 'users/create_user.html'
    form_class = UserCreateForm

    def get(self, request, *args, **kwargs):
        data = dict()
        user_create_form = UserCreateForm()
        context = {'user_create_form': user_create_form}
        data['html_user_create_form'] = render_to_string(
            'users/create_user.html', context, request=request
        )
        return JsonResponse(data)

    def form_valid(self, form):
        form.save()
        data = dict()
        data['form_is_valid'] = True
        context = {'profiles': Profile.objects.all(),}
        data['html_users'] = render_to_string('users/users.html', context)
        return JsonResponse(data)

JS:

$(function ($) {
    $("#userModalBox").on("submit", ".userCreateForm", function () {
        var form = $(this);
        var dataForm = new FormData(form.get(0));
        $.ajax({
            url: form.attr("action"),
            data: dataForm,
            type: form.attr("method"),
            dataType: 'json',
            success: function (data) {
                if (data.form_is_valid) {
                    $("#loader").show("slow");
                    setTimeout(function() {
                        $("#loader").hide("slow");
                        $("#users").html(data.html_users);
                        $("#users").sortable("refresh");
                        $("#users").sortable("option", "disabled", $("#users .list-group-item").length == 1);
                        $("#userModalBox").modal("hide");
                        $("#userMessageCreate").fadeIn("slow");
                        setTimeout(function() {$("#userMessageCreate").fadeOut("slow");}, 2000);
                        $('#searchUsers').val('');
                    }, 2500);
                }
                else {
                    $("#userModalBox .modal-content").html(data.html_user_create_form);
                }
            },
            error: function (xhr, ajaxOptions, thrownError) {
                $("#userError").fadeIn("slow")
                $("#userError span.error-description").html(thrownError);
                setTimeout(function() {$("#userError").fadeOut("slow");}, 10000);
            },
            cache: false,
            contentType: false,
            processData: false
        });
        return false;
    });
}(jQuery));

templates:

{# START: AJAX ERROR #}
<div class="alert alert-danger alert-dismissible text-center" role="alert" id="userError">
     <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
    <strong>&nbsp;{% trans "ERROR" %}:</strong><br><span class="error-description"></span>
</div>
{# END: AJAX ERROR #}


{# START: DJANGO ERROR #}
{% 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 %}
{# END: DJANGO ERROR #}

EDIT PART:

views.py:

def form_invalid(self, form):
        data = dict()
        data['form_is_valid'] = False
        data['form_errors'] = form.errors
        print form.errors
        return JsonResponse(data)

JS:

if (data.form_is_valid) {
   // Some code             
}
else {
   $("#userModalBox .modal-content").html(data.html_user_create_form);
   $('#userModalBox .error-description').html(data.form_errors); <-- DONT WORK???
}
4
  • 3
    Think about the flow here; what is responsible for returning errors when the form is not valid? What format will that response be? (Hint: you've defined form_valid for the case that the form is valid...) Commented Nov 2, 2017 at 13:02
  • You can see the response data by logging it. Commented Nov 2, 2017 at 13:04
  • @DanielRoseman I am confused. Maybe some examples? I add to my post template, can you check it? Commented Nov 2, 2017 at 13:12
  • @NurzhanNogerbek check my answer for more clarification, it explains how we will be returning those form errors in ajax. Commented Nov 2, 2017 at 17:31

2 Answers 2

3

If you want to return form errors in your AJAX response,

Override form_invalid like this:

def form_invalid(self, form):
    error_dict= {'status':'form-invalid','form-errors':form.errors}
    return HttpResponse(json.dumps(error_dict),content_type="application/json")

form.errors: gets the form validation errors if password1 != password2. In your ajax success response("form valid and invalid will always return a response, error function will work only if the code breaks in form valid")

In your AJAX:

if (data.status=="form-invalid") {
    Whatever you want to do e.g. 
    $('.class-name').html(data.form-errors)
}

data.status checks if the json-dict returned in response has status="form-errors", then append those errors in a div or anywhere you want.

Note: Ajax error function only works if there is no response to a request. Form valid and invalid will always return a response and will come in ajax success function unless a break/error in code(will return no response).

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for your answer. Can you check last part (EDIT PART) of my post please? Its the code which I use right now based on your code. print form.errors shows me in terminal error messages but in template I dont have them. Where I did mistake again?
I notice from browser console that data.form_errors return me JSON {password2: Array(1)}, not html.
In the same time print form.errors return me HTML: <ul class="errorlist"><li>password2<ul class="errorlist"><li>Enter the same password as above, for verification.</li></ul></li></ul>
@NurzhanNogerbek , as i believe you want to show user an error if the two passwords entered are not same. If that is the case, the simplest way to do is return only one parameter from form_invalid() i.e data['form_is_valid]=False. In your JS "else" condition kindly try this: $('#userModalBox .error-description').html("Password entered are not same"); and kindly check if the name of classes and ids are correct. Let me know if this works. You can also try .append() or .text() method if above solution doesn't work
Thank you for your answer! =)
|
3

form_valid is only called if the form is valid, hence the name.

So in the case that your form is valid you are returning a JSON response, as your JS code expects. However, if the form is not valid, Django will call form_invalid instead; and since you have not overridden that method, it will continue to return a pure HTML response.

2 Comments

Well, as you said I added form_invalid method. Check my post again pls. How to show error messages which I set in forms.py file? Do you have ideas?
What happens now? Note that your JS code is expecting an object with form_is_valid and html_user_create_form keys, which you're not providing.

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.