I'm trying to add a very simple file upload modal form in my Django app.
But, when I click the submit button, the form shows me an error message: "this field is required".
Everything renders correctly:
Now... I forgot to add cache: false, contentType: false, processData: false
to the $.ajax()
call, but, when I add them, I get the following error: Forbidden (CSRF token missing or incorrect.)
. So... I don't know how to proceed!
I've already wrote (successfully) a modal form which helps me add notes (related) to my lead
object (using this reference), and I'm trying to reproduce exactly the same process for a file upload modal dialog... but it doesn't work :(
Any help will be really appreciated.
By the way: I'm testing this using Chrome (no IE will be used!)
Here is my code:
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)
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)
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'}),
}
I use this partial template to create a modal form:
<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>
This is the page where I create the modal form:
{% 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 %}
$(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;
});
});
Instead of form.serialize()
try sending it with js formData()
it should work.
Here is an example:
$("#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;
});