Django:使用 AJAX 上传文件:表单显示文件输入字段为空(或 CSRF 令牌丢失或不正确)

Django: Uploading files with AJAX: Form says that the file input field is empty (or CSRF token missing or incorrect)

我正在尝试在我的 Django 应用程序中添加一个非常简单的文件上传模式表单。

但是,当我单击提交按钮时,表单显示一条错误消息:“此字段为必填项”。

一切都正确呈现:

现在...我忘记将 cache: false, contentType: false, processData: false 添加到 $.ajax() 调用中,但是,当我添加它们时,出现以下错误:Forbidden (CSRF token missing or incorrect.) 。所以...我不知道如何进行!

我已经(成功地)编写了一个模态表单,它可以帮助我向我的 lead 对象(使用 this 引用)添加注释(相关),并且我正在尝试准确地重现文件上传模式对话框的相同过程......但它不起作用:(

任何帮助将不胜感激。

顺便说一句:我正在使用 Chrome 对此进行测试(不会使用 IE!)



这是我的代码:

models.py

def lead_dir_path(instance, filename):
    """
    Files will be saved to: MEDIA_ROOT/leads/<int:pk>/<filename>
    where <int:pk> is lead's primary key, and <filename> is just that.

    Filename will be set to an UUID value.
    """
    ext = filename.split('.')[-1]
    filename = '%s.%s' % (uuid.uuid4(), ext)
    return 'leads/%s/%s' % (instance.lead.pk, filename)


class ArchivosAdjuntosLead(models.Model):
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE)
    descripcion = models.CharField(max_length=100)
    archivo = models.FileField(upload_to=lead_dir_path)

views.py

def agregar_adjunto_json(request, pk):
    """
    Adds a file to lead with id=pk
    """
    context = {}
    data = {}

    lead = get_object_or_404(Lead, pk=pk)
    context['lead'] = lead

    if request.method == 'POST':
        form = AdjuntarArchivoLeadForm_v2(request.POST, request.FILES)
        if form.is_valid():
            form.save();
            data['form_is_valid'] = True
        else:
            data['form_is_valid'] = False
    else:
        form = AdjuntarArchivoLeadForm_v2()
        form.initial = {'lead': lead}
    context['form'] = form

    data['html_form'] = render_to_string(
        template_folder + 'partial_templates/partial_adjuntar_archivo.html',
        context,
        request = request,
    )
    return JsonResponse(data)

forms.py

class AdjuntarArchivoLeadForm_v2(forms.ModelForm):
    class Meta():
        model = ArchivosAdjuntosLead
        fields = ['lead', 'descripcion', 'archivo']

        widgets = {
          'lead': forms.TextInput(attrs={'class':'form-control', 'style':'display:none;'}),
          'descripcion': forms.TextInput(attrs={'class':'form-control'}),
          'archivo': forms.FileInput(attrs={'class':'form-control'}),
        }

partial_adjuntar_archivo.html

我使用这个部分模板创建模态表单:

<form method="POST" enctype="multipart/form-data"
      action="{% url 'leads:agregar_adjunto_v2' pk=lead.pk %}"
      id="js_adjuntar_archivo_form">
  {% csrf_token %}

  <div class="modal-header">
    <h4 class="modal-title">Adjuntar archivo</h4>
  </div>

  <div class="modal-body">

    {{ form.as_p }}

    <div class="modal-footer">
      <button type="submit" class="btn btn-primary col-4">Adjuntar archivo</button>
      <button type="button" class="btn btn-secondary col-4" data-dismiss="modal">Cancelar</button>
    </div>
  </div>
</form>

my_lead_page.html

这是我创建模态表单的页面:

{% extends "leads/base.html" %}

{% load static %}

{% block contenido %}

<!-- Lots and lots of info -->
<button type="button" class="btn btn-sm btn-primary col-2" id="btn_agregar_adjunto">
  Agregar archivo adjunto
</button>
{% endblock %}

{% block other_scripts %}
<script type="text/javascript" src="{% static 'js/leads/archivos_adjuntos.js'%}"></script>

{% endblock %}

archivos_adjuntos.js

$(function() {
  $("#btn_agregar_adjunto").click(function() {
    $.ajax({
      url: 'adjuntar_archivo/',
      type: 'get',
      dataType: 'json',
      beforeSend: function() {
        $("#modal-form").modal("show");
      },
      success: function(data) {
        $("#modal-form .modal-content").html(data.html_form);
      }
    });
  });

  $("#modal-form").on("submit", "#js_adjuntar_archivo_form", function() {
    var form = $(this);
    $.ajax({
      url: form.attr("action"),
      data: form.serialize(),
      type: form.attr("method"),
      dataType: 'json',
      cache: false,
      contentType: false,
      processData: false, 
      success: function(data) {
        if(data.form_is_valid) {
          alert("Archivo adjuntado");
        } else {
          $("#modal-form .modal-content").html(data.html_form);
        }
      }
    });
    return false;
  });
  
});

而不是 form.serialize() 尝试用 js 发送它 formData() 它应该可以工作。

这是一个例子:

$("#modal-form").on("submit", "#js_adjuntar_archivo_form", function() {
    $that = this;
    var form = new FormData($(this)[0]);

    $.ajax({
        url:$that.attr("action"),
        type:$that.attr("method"),
        data:form,
        processData: false,
        contentType: false,

        // rest of the code'''

    });
    return false;
});