JSON Fundamentals
JSON (JavaScript Object Notation) is a language-agnostic, lightweight data interchange format. It uses plain text to represent structured data and is widely adopted due to its simplicity, readability, and native compatibility with JavaScript.
Valid JSON examples:
["alpha", "beta", "gamma"]
{ "id": 101, "status": "active" }
{ "authors": ["Alice", "Bob"] }
[ { "title": "Intro to JS" }, { "title": "Advanced APIs" } ]
Invalid JSON — these violate syntax rules:
{ id: 101, 'status': 'active' } // keys and strings must use double quotes
[1, 2, 0xFF] // no hexadecimal literals
{ "value": undefined } // undefined is not allowed
{ "timestamp": new Date() } // functions, dates, and undefined are prohibited
Converting Between Objects and Strings
Use JSON.parse() to convert a JSON string into a JavaScript object:
const userObj = JSON.parse('{"name":"Alex","role":"admin"}');
// → { name: "Alex", role: "admin" }
JSON.parse('{name:"Alex"}'); // SyntaxError: keys require double quotes
Use JSON.stringify() to serialize a JavaScript value into a JSON string:
const payload = JSON.stringify({ name: "Alex", permissions: ["read", "write"] });
// → '{"name":"Alex","permissions":["read","write"]}'
JSON vs XML
Compared to XML, JSON offers conciseness and native parsing support. For example, representing country regions:
XML equivalent (verbose):
<?xml version="1.0"?>
<region>
<country>Canada</country>
<provinces>
<province><name>Ontario</name><cities><city>Toronto</city><city>Ottawa</city></cities></province>
<province><name>Quebec</name><cities><city>Montreal</city><city>Quebec City</city></cities></province>
</provinces>
</region>
JSON equivalent (compact and hierarchical):
{
"country": "Canada",
"provinces": [
{
"name": "Ontario",
"cities": ["Toronto", "Ottawa"]
},
{
"name": "Quebec",
"cities": ["Montreal", "Quebec City"]
}
]
}
The JSON version reduces redundancy, eliminates closing tags, and aligns naturally with object-oriented data structures.
Core AJAX Workflow
AJAX enables asynchronous communication between the browser and server without full page reloads. It supports multiple data formats — JSON being the most common today (despite the "X" in AJAX originally standing for XML).
Example: Add two numbers via AJAX:
HTML snippet:
<input type="number" id="numA" placeholder="First number">
<span> + </span>
<input type="number" id="numB" placeholder="Second number">
<span> = </span>
<input type="number" id="result" readonly>
<button id="computeBtn">Calculate</button>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('#computeBtn').on('click', function () {
const a = $('#numA').val();
const b = $('#numB').val();
$.ajax({
url: '/api/sum/',
method: 'GET',
data: { a, b },
success(response) {
$('#result').val(response.total);
},
error() {
alert('Calculation failed.');
}
});
});
</script>
Django view (views.py):
def compute_sum(request):
try:
a = int(request.GET.get('a', 0))
b = int(request.GET.get('b', 0))
return JsonResponse({'total': a + b})
except ValueError:
return JsonResponse({'error': 'Invalid input'}, status=400)
URL config (urls.py):
urlpatterns += [
path('api/sum/', views.compute_sum),
]
Handling CSRF Protection
When using POST requests in Django, include the CSRF token. Two reliable approaches:
Option 1 — Inline token from hidden field:
$.ajax({
url: '/submit-form/',
method: 'POST',
data: {
'username': 'jane',
'email': 'jane@example.com',
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val()
}
});
Option 2 — Global header setup (recommended):
function getCookie(name) {
const pairs = document.cookie.split('; ');
for (let pair of pairs) {
if (pair.startsWith(name + '=')) {
return decodeURIComponent(pair.substring(name.length + 1));
}
}
return null;
}
const token = getCookie('csrftoken');
$.ajaxSetup({
beforeSend(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type) && !settings.crossDomain) {
xhr.setRequestHeader('X-CSRFToken', token);
}
}
});
Uploading Files with AJAX
To upload files asynchronously, use FormData and disable jQuery’s default serialization:
$('#uploadBtn').on('click', function () {
const formData = new FormData();
formData.append('document', $('#fileInput')[0].files[0]);
formData.append('description', $('#desc').val());
$.ajax({
url: '/upload/document/',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success(data) {
console.log('Upload complete:', data);
}
});
});
Backend (Django) receives the file via request.FILES:
def handle_upload(request):
if request.method == 'POST' and request.FILES.get('document'):
uploaded_file = request.FILES['document']
# Save or process file...
return JsonResponse({'message': 'Uploaded successfully'})
return JsonResponse({'error': 'No file provided'}, status=400)
Real-Time Validation Example
Check username availability on blur:
<input type="text" id="usernameField" placeholder="Enter username">
<span id="availabilityStatus"></span>
<script>
$('#usernameField').on('blur', function () {
const username = $(this).val().trim();
if (!username) return;
$.get('/check-username/', { username }, function (resp) {
const $status = $('#availabilityStatus');
if (resp.available) {
$status.text('✓ Available').css('color', 'green');
} else {
$status.text('✗ Already taken').css('color', 'red');
}
});
});
</script>
Server-Side Serialization
Django’s serializers module simplifies model-to-JSON conversion:
from django.core import serializers
from django.http import HttpResponse
def list_books_api(request):
books = Book.objects.filter(published=True)[:20]
json_data = serializers.serialize('json', books)
return HttpResponse(json_data, content_type='application/json')
For finer control, use Python’s json module with custom logic:
import json
from django.http import JsonResponse
def book_summary(request):
books = Book.objects.values('id', 'title', 'author__name', 'published_date')[:15]
return JsonResponse(list(books), safe=False)
Enhancing UX with SweetAlert2
Replace native alert()/confirm() with styled, promise-based modals:
<button class="btn-delete" data-id="42">Delete Record</button>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
$('.btn-delete').on('click', async function () {
const recordId = $(this).data('id');
const result = await Swal.fire({
title: 'Confirm deletion?',
text: 'This action cannot be undone.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Yes, delete it',
cancelButtonText: 'Cancel'
});
if (result.isConfirmed) {
try {
const response = await $.post('/api/delete/', { id: recordId });
if (response.success) {
Swal.fire('Deleted!', 'Record removed successfully.', 'success');
$(this).closest('tr').remove();
}
} catch (err) {
Swal.fire('Error', 'Failed to delete record.', 'error');
}
}
});
</script>
This implementation improves interactivity, accessibility, and visual consistency across user actions.