原生JavaScript实现Django表单AJAX提交:无法传FormData及判断请求类型
Hey there! Let’s work through those two roadblocks you’re hitting with native JavaScript AJAX and Django—they’re super common when moving away from jQuery, so I’ve got step-by-step fixes for both.
1. Sending FormData to Django Successfully
The main issues here are missing CSRF token handling and incorrect request headers (which jQuery handles automatically). Here’s how to fix it:
Frontend Native JS Code
const registerForm = document.getElementById('register-form'); registerForm.addEventListener('submit', (e) => { e.preventDefault(); // Prevent default form submission // Create FormData from the form element const formData = new FormData(registerForm); // Initialize XMLHttpRequest const xhr = new XMLHttpRequest(); xhr.open('POST', '/register/', true); // Add Django's required CSRF token (critical for security) const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value; xhr.setRequestHeader('X-CSRFToken', csrfToken); // DO NOT manually set Content-Type! Let the browser handle it automatically // This ensures FormData is encoded correctly as multipart/form-data // Handle response xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { const response = JSON.parse(xhr.responseText); console.log('Registration success:', response); // Add your success UI updates here } else { const errorResponse = JSON.parse(xhr.responseText); console.error('Registration failed:', errorResponse); // Add your error handling UI here } }; // Send the FormData xhr.send(formData); });
Backend Django View Adjustment
If your form includes file uploads, make sure to pass request.FILES to the form constructor. For regular text fields, request.POST works fine, but including request.FILES is safe either way:
def register(request): if request.method == "POST": # Include request.FILES if your form has file fields form = RegisterForm(request.POST, request.FILES) if form.is_valid(): # We'll handle the AJAX check next # ... save form data here ...
2. Detecting AJAX Requests in Django
Django’s request.is_ajax() was deprecated in version 3.1, and it relied on a header that jQuery automatically adds—but native JS doesn’t. Here’s how to fix this:
Step 1: Add the AJAX Identifier Header in JS
Add this line right after setting the CSRF token in your JavaScript:
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
Step 2: Replace request.is_ajax() with Manual Header Check
Update your view to check for the header we just added:
def register(request): if request.method == "POST": form = RegisterForm(request.POST, request.FILES) if form.is_valid(): # Manually check if the request is AJAX is_ajax_request = request.headers.get('X-Requested-With') == 'XMLHttpRequest' if is_ajax_request: # Handle AJAX submission: return JSON response form.save() # Save the valid form data return JsonResponse({'status': 'success', 'message': 'Registered!'}) else: # Handle regular form submission: redirect or render page form.save() return redirect('dashboard') else: # Handle invalid form is_ajax_request = request.headers.get('X-Requested-With') == 'XMLHttpRequest' if is_ajax_request: # Return errors as JSON for AJAX return JsonResponse({'status': 'error', 'errors': form.errors}, status=400) else: # Re-render form with errors for regular submission return render(request, 'register.html', {'form': form}) else: # GET request: show empty form form = RegisterForm() return render(request, 'register.html', {'form': form})
Key Takeaways
- Always include the CSRF token in your native JS AJAX requests—Django blocks requests without it.
- Never manually set
Content-Typewhen sendingFormData; let the browser handle encoding. - Replace the deprecated
request.is_ajax()with a check for theX-Requested-Withheader, which you need to add manually in your JS.
内容的提问来源于stack exchange,提问作者Ricky Singh

