Как использовать прозрачный флажок для ajax загрузки файлов с помощью modelform django
Я совсем новичок в django и ajax, поэтому прошу простить меня, если в моей работе есть какая-то большая ошибка или некрасивый код. Итак, я работаю над приложением, где пользователь должен загружать различные документы в modelForm (связанную с другой моделью 1:1). Пользователь, вероятно, не будет загружать все документы сразу. Я использую ajax, чтобы иметь индикатор выполнения для пользователя. Пока что загрузка работает нормально, замена документа на другой тоже работает, но у меня возникла проблема, когда дело доходит до использования прозрачного флажка, который django предоставляет, когда документ уже загружен. Используя submit и стандартный Post, флажок работает нормально. При использовании ajax он не работает.
models.py (не буду выкладывать все, так как там более 25 FileFields)
class MandatVenteUpload(models.Model):
mandat= models.OneToOneField('mandat_vente.MandatVente', on_delete=models.CASCADE, primary_key=True)
acte_propriete = models.FileField(upload_to=content_file_name, max_length=60 ,null=True, blank=True)
carte_identite= models.FileField(upload_to=content_file_name, max_length=60 ,null=True, blank=True)
diagnostic_amiante= models.FileField(upload_to=content_file_name, max_length=60 ,null=True, blank=True)
diagnostic_assainissement= models.FileField(upload_to=content_file_name, max_length=60 ,null=True, blank=True)
diagnostic_electricite= models.FileField(upload_to=content_file_name, max_length=60 ,null=True, blank=True)
[...]
views.py (использование исключения, так как если документ еще не загружен, то модель не существует)
@login_required
def mandat_vente_upload_view(request, num_mandat_upload):
mandat_upload=get_object_or_404(MandatVente, id = num_mandat_upload)
if mandat_upload.createur == request.user or request.user.is_staff:
try:
form_upload = MandatVenteUpload.objects.get(mandat=mandat_upload.id)
form=MandatVenteUploadForm(mandat_upload, request.POST or None, request.FILES or None, instance=form_upload)
if request.is_ajax() or request.method == 'POST':
if form.is_valid():
print(request.POST)
print(request.FILES)
form.save()
return JsonResponse({'message': 'hell yeah'})
return render(request, 'mandat_vente/upload_mandat.html', context={'form' : form})
except MandatVenteUpload.DoesNotExist:
print("ici")
form = MandatVenteUploadForm(mandat_upload)
if request.is_ajax() or request.method == 'POST':
form=MandatVenteUploadForm(mandat_upload, request.POST or None, request.FILES or None)
if form.is_valid():
print("exception")
form.save()
return JsonResponse({'message': 'hell yeah'})
return render(request, 'mandat_vente/upload_mandat.html', context={'form' : form})
else:
return HttpResponse('Vous ne pouvez pas charger de documents pour ce mandat.')
upload_mandat.html
{% extends 'template_base.html' %}
{% block titre %} <title>Upload documents</title>
<script src="/static/main.js" defer></script>
{% endblock %}
{% block contenu %}
<div class="container">
<div class="row justify-content-center">
<div class="col-6 mt-4">
<h1>Upload documents liés au mandat</h1>
<hr class="my-4">
<form id="upload-form" action="" method="POST" enctype="multipart/form-data" class="upload-docs-div">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-primary">Envoyer</button>
</form>
</div>
</div>
</div>
<div id="progress-box" class="not-visible">progress</div>
<div id="cancel-box" class="not-visible">
<button id="cancel-btn" class="btn btn-danger">Annuler</button>
</div>
{% endblock %}
main.js (вырезание списка fd.append с другими документами)
const progressBox = document.getElementById('progress-box')
const cancelBox = document.getElementById('cancel-box')
const cancelBtn = document.getElementById('cancel-btn')
const csrf = document.getElementsByName('csrfmiddlewaretoken')
document.getElementById("upload-form").addEventListener("submit", function(submit){
submit.preventDefault()
progressBox.classList.remove('not-visible')
cancelBox.classList.remove('not-visible')
const fd = new FormData()
fd.append('csrfmiddlewaretoken', csrf[0].value)
fd.append("acte_propriete", document.getElementById("id_acte_propriete").files[0])
fd.append("carte_identite", document.getElementById("id_carte_identite").files[0])
fd.append("diagnostic_amiante", document.getElementById("id_diagnostic_amiante").files[0])
fd.append("diagnostic_assainissement", document.getElementById("id_diagnostic_assainissement").files[0])
fd.append("diagnostic_electricite", document.getElementById("id_diagnostic_electricite").files[0])
[...]
$.ajax({
type:'POST',
url: uploadForm.action,
enctype: 'multipart/form-data',
data: fd,
beforeSend: function(){
},
xhr: function(){
const xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener('progress', e=>{
// console.log(e)
if(e.lengthComputable){
const percent = e.loaded / e.total * 100
console.log(percent)
progressBox.innerHTML = `<div class="progress">
<div class="progress-bar" role="progressbar" style="width: ${percent}%" aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<p>${percent.toFixed(1)}%`
}
})
cancelBtn.addEventListener('click', ()=>{
xhr.abort()
progressBox.innerHTML=""
cancelBox.classList.add('not-visible')
})
return xhr
},
success: function(response){
console.log(response)
cancelBox.classList.add('not-visible')
},
error: function(error){
console.log(error)
},
cache: false,
contentType: false,
processData: false,
})
})
Когда я перехожу на форму, где я ранее загрузил два документа, и ставлю два флажка, чтобы очистить файлы, вот результаты печати request.POST и request.FILES:
использование submit без ajax: (вырезая часть, мы видим, что QueryDict имеет некоторые "id_document"_clear со значениями "on")
<QueryDict: {'csrfmiddlewaretoken': ['sXsUcg59BinrfOhBT56G33BltdETPflLSYTnM0XWOETevBTQpNkZhA42T8EisVha'], 'acte_propriete-clear': ['on'], 'acte_propriete': [''], 'carte_identite': [''], 'diagnostic_amiante-clear': ['on'], 'diagnostic_amiante': [''], 'diagnostic_assainissement': [''], 'diagnostic_electricite': [''], [...]>
<MultiValueDict: {}>
использование ajax: (QueryDict имеет все на 'Undefined')
><QueryDict: {'csrfmiddlewaretoken': ['UeUDIIIRxXxl1VWr3PRN5igRLTdC5vbskfl6isAEKj38hIyGzx56jPJybOd1Ib7R'], 'acte_propriete': ['undefined'], 'carte_identite': ['undefined'], 'diagnostic_amiante': ['undefined'], 'diagnostic_assainissement': ['undefined'], 'diagnostic_electricite': ['undefined'], [...]>
<MultiValueDict: {}>
Как бы вы сделали так, чтобы это работало?