Contact Us
24/7
Python BlogDjango BlogSearch for Kubernetes Big DataSearch for Kubernetes AWS BlogCloud Services

Blog

<< ALL BLOG POSTS

Making your Django templates AJAX-y

|
February 27, 2018

Your users don't like to wait. So it's best to load all or portions of a page with Javascript without having to do a traditional click-wait-entire page reload.

What is AJAX?

AJAX stands for Asynchronous Javascript And XML. It's not a separate language, but uses JS to create an XMLHttpRequest that calls the site's backend. This function can make changes in the database as a POST, or it could GET data that the JS would then use to update the page without having to refresh. Below are examples of each, and they require:

POST only

One of our current projects is a survey app that stores the user's answers as they fill out the survey. After they click on an answer, the data is immediately saved in the database.

JS (using jQuery):

// note: this line only works in the template
save_answer_link = "{% url 'survey:save_answer' %}";

$("#survey-page input[type='radio']").click(function(){
    save_answer($(this).parents(".question"));
});

function save_answer(question) {
    $.post(save_answer_link, {
        'csrfmiddlewaretoken': $("input[name='csrfmiddlewaretoken']").val(),
        'question_pk': $(question).find("input[name^='question-']").val(),
        'answer': $(question).find(".answer-result").val(),
        'na': $(question).find(".notapplicable").is(":checked") ? 1 : 0
    });
};

Notice the POST url is save_answer, set in urls.py:

url(
    regex=r'^save_answer',
    view=views.save_answer,
    name='save_answer'
),

In the view class, take the data passed from the Javascript, and save it as a UserAnswer object (a custom model):

def save_answer(request):
    question_pk = request.POST.get('question_pk')
    question = Question.objects.get(pk=question_pk)
    answer = request.POST.get('answer') or None
    not_applicable = int(request.POST.get('na'))
    else:
    try:
        ans = get_object_or_404(
            UserAnswer, question=question, user=request.user)
    except:
        ans = UserAnswer(user=request.user, question=question)
    ans.not_applicable = not_applicable
    ans.answer = None if not_applicable else answer
    ans.save()
    # Return a response. An empty dictionary is still a 200
    return HttpResponse(json.dumps([{}]), content_type='application/json')

GET

Another of our projects features a form with a series of dropdowns for a student to choose a major. The options available in each dropdown depend on the previous answers, based on what majors are available at the selected campus and department. No data needs to be saved in the database yet, but we need to access the database to get the values for each dropdown.

The example below is for when the user selects a department. The list of majors then updates to only show the majors available within that department and campus.

JS (jQuery):

// note: this line only works in the template
majors_link= "{% url 'majors_per_campus' %}";

$('#program-listing').on("change", 'select[name=department]', function(){
    pgm = '#' + $(this).parents(".program-info").attr("id");
    url = majors_link + '?campus='+ $(pgm + ' select[name=campus]').val() + '&department='+ $(this).val();
    // 'data' is what is returned from the view class
    $.getJSON(url, function(data) {
        options = ""
        $.each(data, function () {
            options += "<option value='" + this.id + "'>" + this.value + "</option>";
        });
        blank_option = "<option value=''>--Select--</option>"
        $(pgm + ' select[name=major]').find('option').remove().end().append($(blank_option + options));
    })
});

urls.py:

url(
    r'^majors_per_campus',
    view.get_majors_for_campus,
    name='majors_per_campus'
),

Python view class:

def get_majors_for_campus(request):
    """Check the department to get a set of all majors
       available in the selected department
    """
    campus = request.GET.get('campus')
    department = request.GET.get('department')

    if not (campus and department):
        return HttpResponse(json.dumps([{}]), content_type='application/json')
    majors = Major.objects.filter(campus=campus, department=department)
    major_choices = [dict(id=m.pk, value=m.title) for m in majors]
    return HttpResponse(
        json.dumps(major_choices),
        content_type='application/json',
    )
How can we assist you in reaching your objectives?
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.