Ajax
Django
web development
JavaScript
integration

How do I integrate Ajax with Django applications?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Ajax (Asynchronous JavaScript and XML) lets a Django page send and receive data from the server without a full page reload. The integration involves three parts: a Django view that returns JSON instead of HTML, a URL route pointing to that view, and JavaScript on the frontend that calls the URL and updates the page with the response. Django's built-in JsonResponse and CSRF protection work directly with Ajax — no extra packages needed.

Basic Ajax GET Request

Django View

python
1# views.py
2from django.http import JsonResponse
3
4def search_users(request):
5    query = request.GET.get('q', '')
6    users = list(
7        User.objects.filter(username__icontains=query)
8        .values('id', 'username', 'email')[:10]
9    )
10    return JsonResponse({'users': users})

URL Configuration

python
1# urls.py
2from django.urls import path
3from . import views
4
5urlpatterns = [
6    path('api/search-users/', views.search_users, name='search_users'),
7]

JavaScript (Fetch API)

html
1<!-- template.html -->
2<input type="text" id="search-input" placeholder="Search users...">
3<div id="results"></div>
4
5<script>
6const input = document.getElementById('search-input');
7const results = document.getElementById('results');
8
9input.addEventListener('input', async function() {
10    const response = await fetch(`/api/search-users/?q=${encodeURIComponent(this.value)}`);
11    const data = await response.json();
12
13    results.innerHTML = data.users
14        .map(u => `<div>${u.username} (${u.email})</div>`)
15        .join('');
16});
17</script>

Ajax POST with CSRF Token

Django requires a CSRF token for POST requests. Include it in the Ajax header:

Django View

python
1# views.py
2from django.http import JsonResponse
3from django.views.decorators.http import require_POST
4import json
5
6@require_POST
7def add_comment(request):
8    data = json.loads(request.body)
9    comment = Comment.objects.create(
10        post_id=data['post_id'],
11        text=data['text'],
12        author=request.user,
13    )
14    return JsonResponse({
15        'id': comment.id,
16        'text': comment.text,
17        'author': comment.author.username,
18        'created': comment.created_at.isoformat(),
19    })

JavaScript with CSRF

html
1<script>
2// Get CSRF token from the cookie
3function getCookie(name) {
4    let value = `; ${document.cookie}`;
5    let parts = value.split(`; ${name}=`);
6    if (parts.length === 2) return parts.pop().split(';').shift();
7}
8
9async function addComment(postId, text) {
10    const response = await fetch('/api/add-comment/', {
11        method: 'POST',
12        headers: {
13            'Content-Type': 'application/json',
14            'X-CSRFToken': getCookie('csrftoken'),
15        },
16        body: JSON.stringify({ post_id: postId, text: text }),
17    });
18    const data = await response.json();
19    return data;
20}
21</script>

The {% csrf_token %} template tag must appear somewhere on the page (usually in a form) for the cookie to be set, or use the @ensure_csrf_cookie decorator on the page view.

Using jQuery (Alternative)

html
1<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
2<script>
3// jQuery sets the CSRF header automatically with this setup
4$.ajaxSetup({
5    beforeSend: function(xhr, settings) {
6        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
7            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
8        }
9    }
10});
11
12// GET request
13$.get('/api/search-users/', { q: 'alice' }, function(data) {
14    console.log(data.users);
15});
16
17// POST request
18$.ajax({
19    url: '/api/add-comment/',
20    type: 'POST',
21    contentType: 'application/json',
22    data: JSON.stringify({ post_id: 1, text: 'Great post!' }),
23    success: function(data) {
24        console.log('Comment added:', data);
25    },
26    error: function(xhr) {
27        console.error('Error:', xhr.responseJSON);
28    }
29});
30</script>

Django Form Submission via Ajax

Submit a Django form without page reload:

python
1# views.py
2from django.http import JsonResponse
3
4def contact_form(request):
5    if request.method == 'POST':
6        form = ContactForm(request.POST)
7        if form.is_valid():
8            form.save()
9            return JsonResponse({'success': True})
10        return JsonResponse({'success': False, 'errors': form.errors}, status=400)
11    return render(request, 'contact.html', {'form': ContactForm()})
html
1<!-- contact.html -->
2<form id="contact-form">
3    {% csrf_token %}
4    {{ form.as_p }}
5    <button type="submit">Send</button>
6</form>
7<div id="message"></div>
8
9<script>
10document.getElementById('contact-form').addEventListener('submit', async function(e) {
11    e.preventDefault();
12    const formData = new FormData(this);
13
14    const response = await fetch(this.action || window.location.href, {
15        method: 'POST',
16        headers: { 'X-CSRFToken': formData.get('csrfmiddlewaretoken') },
17        body: formData,
18    });
19    const data = await response.json();
20
21    if (data.success) {
22        document.getElementById('message').textContent = 'Sent!';
23        this.reset();
24    } else {
25        document.getElementById('message').textContent = JSON.stringify(data.errors);
26    }
27});
28</script>

Detecting Ajax Requests in Django

python
1def my_view(request):
2    # Check if the request is Ajax
3    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
4        # Return JSON for Ajax
5        return JsonResponse({'data': 'value'})
6
7    # Return HTML for normal requests
8    return render(request, 'page.html')

Note: The Fetch API does not set X-Requested-With by default. Either add it manually or check Accept: application/json instead:

python
1def my_view(request):
2    if 'application/json' in request.headers.get('Accept', ''):
3        return JsonResponse({'data': 'value'})
4    return render(request, 'page.html')

Error Handling

python
1# views.py
2from django.http import JsonResponse
3import json
4
5def api_view(request):
6    try:
7        data = json.loads(request.body)
8        result = process(data)
9        return JsonResponse({'result': result})
10    except json.JSONDecodeError:
11        return JsonResponse({'error': 'Invalid JSON'}, status=400)
12    except Exception as e:
13        return JsonResponse({'error': str(e)}, status=500)
javascript
1// Frontend error handling
2async function apiCall(url, data) {
3    try {
4        const response = await fetch(url, {
5            method: 'POST',
6            headers: {
7                'Content-Type': 'application/json',
8                'X-CSRFToken': getCookie('csrftoken'),
9            },
10            body: JSON.stringify(data),
11        });
12
13        if (!response.ok) {
14            const error = await response.json();
15            throw new Error(error.error || `HTTP ${response.status}`);
16        }
17
18        return await response.json();
19    } catch (err) {
20        console.error('API error:', err.message);
21        throw err;
22    }
23}

Common Pitfalls

  • 403 Forbidden (CSRF): POST requests without the X-CSRFToken header are rejected. Always include the CSRF token from the cookie or the {% csrf_token %} hidden input.
  • request.POST is empty for JSON: Django only populates request.POST for form-encoded data. For Content-Type: application/json, use json.loads(request.body) instead.
  • @csrf_exempt temptation: Disabling CSRF for Ajax views creates a security vulnerability. Use the CSRF token header instead.
  • Missing Content-Type header: If you send JSON without Content-Type: application/json, Django may try to parse it as form data. Always set the content type header explicitly.
  • Serializing querysets: JsonResponse(queryset) fails. Convert querysets to lists first: list(qs.values('id', 'name')) or use Django REST Framework serializers.

Summary

  • Return JsonResponse from Django views for Ajax endpoints
  • Include the CSRF token via X-CSRFToken header for POST/PUT/DELETE requests
  • Use json.loads(request.body) to parse JSON POST data (not request.POST)
  • Use the native Fetch API or jQuery's $.ajax() on the frontend
  • Handle errors on both sides — return proper HTTP status codes from Django and catch them in JavaScript
  • For complex APIs, consider Django REST Framework for serialization, authentication, and routing

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.