You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django+AJAX异步上传图片遇问题:请求未识别为AJAX且视图无响应

Django+AJAX图片上传无刷新处理问题

我尝试用Django结合AJAX实现图片上传至服务器处理,完成后无需刷新页面获取响应,但点击提交按钮后出现错误:

The view docs.views.generate didn't return an HttpResponse object. It returned None instead.

排查发现is_ajax值为false,且前端的form_data未添加任何数据。现有疑问:

  1. Django 3.1+版本中,如何正确判断请求为AJAX请求?
  2. 有没有简便方法将服务器返回的文本展示在页面指定位置?

现有代码

models.py

class Snip(models.Model):
    # some fields
    snip = models.FileField(upload_to="snips/")
    latex = models.TextField(default = '')

forms.py

from .models import Snip
from django import forms

class SnipForm(forms.ModelForm):
    class Meta:
        model = Snip
        fields = ['snip']

HTML

<form id="snipForm" method="POST" enctype="multipart/form-data">
<input type="hidden" name="csrfmiddlewaretoken" value="...">
<div class="row align-items-center">
<div class="col-12">
<label for="id_snip">Snip:</label>
<input type="file" name="snip" required="" id="id_snip" class="btn-success p-2 rounded">
<input type="submit" name="upload" id="upload" class="btn btn-secondary">
</div>
</div>
</form>

JavaScript/AJAX

var upload_btn = document.getElementById("upload")

upload_btn.addEventListener('click', function () {
  var form_data = new FormData();
  var ins = document.getElementById('id_snip').files.length;

  if(ins == 0) return console.log("No snip!!!")
    form_data.append("file[]", snip.files[0]);
    csrf_token = $('input[name="csrfmiddlewaretoken"]').val();
    form_data.append("csrfmiddlewaretoken", csrf_token);
    headers = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'};
    console.log(form_data);
    console.log(headers);

    $.ajaxSetup({
  beforeSend: function(xhr) {
      xhr.setRequestHeader('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
  }
});

    $.ajax({
      type: 'POST',
      url: 'https://localhost:8000/docs/',
      dataType: "json",
      ContentType: "application/json",
      cache: false,
      processData: false,
      headers: headers,
      data: form_data,

      success: function (response) {
        console.log("SUCCESSSSSSSSS")
      },
      error: function (response) {
        console.log("NOPEEEEEE")
      }
  });
});

views.py

from django.shortcuts import render
from django.contrib.auth.models import User
from .models import Snip
from .forms import SnipForm
from django.http import JsonResponse
from django.core import serializers

def generate(request):
    is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
    if is_ajax and request.method == "POST":
        file = request.FILES['snip']
        processed_image = "Some text from OCR"
        return JsonResponse({'text':'Yay, I got text from OCR'})

    if request.method == 'GET':
        Users = User.objects.all()
        form = SnipForm()
        user_list = []
        for user in Users:
            if user.get_full_name():
                user_list.append(user.get_full_name())
        return render(request, "new.html", {'Users': user_list, 'form': form})

更新内容

尝试添加$.ajaxSetup设置请求头,但Django错误页面仍未找到HTTP_X_REQUESTED_WITH的META信息,且form_data依旧为空,控制台输出:

FormData {}
{HTTP_X_REQUESTED_WITH: 'XMLHttpRequest'}

错误问题仍未解决。


解决方案

1. 修复AJAX请求问题(解决is_ajax为false、form_data为空)

  • 阻止表单默认提交行为:点击按钮时添加event.preventDefault(),避免表单默认刷新提交打断AJAX请求:
    upload_btn.addEventListener('click', function (event) {
      event.preventDefault(); // 新增这行
      // 后续代码不变
    });
    
  • 修正文件字段名:后端取request.FILES['snip'],所以FormData的键名要和表单字段一致,且snip变量未定义,需替换为DOM元素:
    // 替换原来的form_data.append("file[]", snip.files[0]);
    var fileInput = document.getElementById('id_snip');
    form_data.append("snip", fileInput.files[0]);
    
  • 修正AJAX的Content-Type配置:FormData会自动生成正确的Content-Type(带boundary),手动设为json会导致后端无法解析文件,需改为:
    $.ajax({
      // ...其他配置
      contentType: false, // 替换原来的ContentType: "application/json"
      // ...其他配置
    });
    
  • 修正请求头设置:JS中设置请求头时用X-Requested-With,Django会自动转为HTTP_X_REQUESTED_WITH存入META:
    $.ajaxSetup({
      beforeSend: function(xhr) {
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      }
    });
    

2. 展示处理后的文本

  • 在HTML中添加一个结果展示区域:
    <!-- 放在form标签下方 -->
    <div id="ocr-result" class="mt-3"></div>
    
  • 在AJAX的success回调中插入响应文本:
    success: function (response) {
      document.getElementById('ocr-result').textContent = response.text;
      console.log("SUCCESSSSSSSSS")
    },
    

3. 完善后端视图(避免返回None)

在视图末尾添加默认返回,处理非AJAX的POST请求:

def generate(request):
    is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
    if is_ajax and request.method == "POST":
        try:
            file = request.FILES['snip']
            # 替换为你的OCR处理逻辑
            processed_text = "Some text from OCR"
            return JsonResponse({'text': processed_text})
        except KeyError:
            return JsonResponse({'error': '未上传文件'}, status=400)

    if request.method == 'GET':
        Users = User.objects.all()
        form = SnipForm()
        user_list = [user.get_full_name() for user in Users if user.get_full_name()]
        return render(request, "new.html", {'Users': user_list, 'form': form})
    
    # 处理非AJAX的POST请求
    return render(request, "new.html", {'form': SnipForm(), 'Users': []})

内容的提问来源于stack exchange,提问作者Wincij

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:42:08