Originally published at melvinkoh.me.
Create a form to interact with these endpoints and perform validation and preprocessing before calling REST service.
We will start with creating a Form:
# forms.pyfrom django import forms
class MyForm(forms.Form): student_id = forms.CharField(max_length=10, required=True) student_name = forms.CharField(max_length=255, required=True)
def clean_student_id(self): # Pre-process student_id return re.sub('\D', '', self.cleaned_date.get('student_id'))
Next, we create a simple template and view to render this form.
# in templates/my_form.html# Add these into your body<form action=""> {% crsf_token %} {{ my_form.as_p }} <input type="button" id="btn-submit_my_form"></form>
In your views.py:
# I'm using class-based view here
# Skip importsclass MyFormView(TemplateView): template_name = 'my_form.html'
def get_context_data(self, **kwargs): context = super(MyFormView, self).get_context_data(**kwargs) context['my_form'] = MyForm() return context
After mapping your url to MyFormView, you should be able to view your form.
We want to submit our form asynchronously, AJAX is the only solution. Let’s add some script in your my_form.html. I will be using jQuery syntax, make you have the jQuery library imported.
<script> $('#request-verification').on('click', function(event){ event.preventDefault(); $.ajax({ url : "{% url 'ajax:my_form' %}", // the endpoint type : "POST", // http method data : { student_id : $('#id_student_id').val(), student_name : $('#id_student_name').val()}
success : function(json, textMsg, xhr) { alert('AJAX called successfully') },
error : function(xhr,errmsg,err) { alert('Opps! Something's wrong'!) } }); });</script>
The callback above first prevent the default event being triggered by defining event.preventDefault(). In data attribute, we collect a dictionary of form inputs. Replace the URL to your respective URL name.
If the AJAX call successfully, we prompt an alert says that ‘AJAX called successfully’, whereas alert user with another message if error occurs.
We do not want to sacrifice CSRF protection in Django, django recognize your incoming request with it’s CSRF protection token in your request header. If you run your code above, you will get a CSRF validation error.
To deal with it, add this snippet of code into your template script tags (I prefer creating a separate .js file and import into my template):
# This snippet is provided in Django official documentation function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
The code above will pre-process your AJAX request by adding a X-CSRFToken header before sending your request. Till now, your front-end is good to go. What about backend? Let us dive into our AJAX endpoint.
# Your ajax endpoint view, I am using function-based view.
@require_http_methods(['POST'])def my_form_ajax_endpoint(request): # Process your data here.
Of course, at this point, you should be able to create an async call using AJAX. However, what I want is not simply this, I want to process my POST data with Django Form built-ins. Let our MyForm form class do the dirty work for us. We will only process it if the data are valid.
# Your ajax endpoint view, I am using function-based view.
@require_http_methods(['POST'])def my_form_ajax_endpoint(request): # Process your data here. form = MyForm(request.POST) if form.is_valid(): # We process further here.. # I will talk about calling another REST service from here in Part 2 return JsonResponse({"message":"form is submitted"}, status=201)
return JsonResponse({"error":"invalid input"}, status=400)
As of this point, async call using AJAX with CSRF preserved can be done in a breeze.
Your clap will definitely drive me further. Give me a clap if you like this post.