Tengo una carga de varios archivos y quiero limitar los usuarios a 3 cargas cada uno. Mi problema es que necesito saber cuántos archivos ya ha creado un user en la base de datos y cuántos están cargando actualmente (pueden cargar varios archivos a la vez y pueden cargar varias veces).
He intentado muchas cosas, incluyendo:
Creación de un validador (al validador se le pasó el archivo real que se agregó, no un model , por lo que no pude acceder al model para obtener su id para llamar if StudentUploadedFile.objects.filter(student_lesson_data=data.id).count() >= 4: ).
Haciendo la validación en clean(self): ( clean solo se pasó una instancia a la vez y la base de datos no se actualiza hasta que se limpian todos los archivos, por lo que pude contar los archivos que ya están en la base de datos pero no pude contar cuántos eran que se está cargando actualmente).
Usar un método pre-save (si la base de datos se actualiza entre cada archivo que se pasa a mi método pre-save , funcionaría, pero la base de datos solo se actualiza después de que todos los archivos que se cargan hayan pasado por mi método pre-save ).
Mi intento post-save :
@receiver(pre_save, sender=StudentUploadedFile) def upload_file_pre_save(sender, instance, **kwargs): if StudentUploadedFile.objects.filter(student_lesson_data=instance.data.id).count() >= 4: raise ValidationError('Sorry, you cannot upload more than three files')editar:
modelos.py
class StudentUploadedFile(models.Model): student_lesson_data = models.ForeignKey(StudentLessonData, related_name='student_uploaded_file', on_delete=models.CASCADE) student_file = models.FileField(upload_to='module_student_files/', default=None)vistas.py
class StudentUploadView(View): def get(self, request): files_list = StudentUploadedFile.objects.all() return render(self.request, 'users/modules.html', {'student_files': files_list}) def post(self, request, *args, **kwargs): form = StudentUploadedFileForm(self.request.POST, self.request.FILES) form.instance.student_lesson_data_id = self.request.POST['student_lesson_data_id'] if form.is_valid(): uploaded_file = form.save() # pass uploaded_file data and username so new file can be added to students file list using ajax # lesson_id is used to output newly added file to corresponding newly_added_files div data = {'is_valid': True, 'username': request.user.username, 'file_id': uploaded_file.id, 'file_name': uploaded_file.filename(), 'lesson_id': uploaded_file.student_lesson_data_id, 'file_path': str(uploaded_file.student_file)} else: data = {'is_valid': False} return JsonResponse(data)plantilla.py
<form id='student_uploaded_file{{ item.instance.id }}'> {% csrf_token %} <a href="{% url 'download_student_uploaded_file' username=request.user.username file_path=item.instance.student_file %}" target='_blank'>{{ item.instance.filename }}</a> <a href="{% url 'delete_student_uploaded_file' username=request.user.username file_id=item.instance.id %}" class='delete' id='{{ item.instance.id }}'>Delete</a> </form>js
$(function () { // open file explorer window $(".js-upload-photos").on('click', function(){ // concatenates the id from the button pressed onto the end of fileupload class to call correct input element $("#fileupload" + this.id).click(); }); $('.fileupload_input').each(function() { $(this).fileupload({ dataType: 'json', done: function(e, data) { // process response from server // add newly added files to students uploaded files list if (data.result.is_valid) { $("#newly_added_files" + data.result.lesson_id).prepend("<form id='student_uploaded_file" + data.result.file_id + "'><a href='/student_hub/" + data.result.username + "/download_student_uploaded_file/" + data.result.file_path + "' target='_blank'>" + data.result.file_name + "</a><a href='/student_hub/" + data.result.username + "/delete_student_uploaded_file/" + data.result.file_id + "/' class='delete' id=" + data.result.file_id + ">Delete</a></form>") } } }); });ACTUALIZAR: formularios.py
class StudentUploadedFileForm(forms.ModelForm): student_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))ver.py
class StudentUploadView(View): model = StudentUploadedFile max_files_per_lesson = 3 def post(self, request, *args, **kwargs): lesson_data_id = request.POST['student_lesson_data_id'] current_files_count = self.model.objects.filter( student_lesson_data_id=lesson_data_id ).count() avail = self.max_files_per_lesson - current_files_count file_list = request.FILES.getlist('student_file') print(len(file_list)) if avail - len(file_list) < 0: return JsonResponse(data={ 'is_valid': False, 'reason': f'Too many files: you can only upload {avail}.' }) else: for f in file_list: print(f) data = {'test': True} return JsonResponse(data)Gracias.
Entonces, la esencia es que está usando jQuery .each para cargar imágenes a través de AJAX. Cada solicitud POST a su vista de Django es una carga de un solo archivo, pero puede haber varias solicitudes al mismo tiempo.
Prueba esto:
formularios.py:
class StudentUploadedFileForm(forms.ModelForm): class Meta: model = StudentUploadedFile fields = ('student_file', ) def __init__(self, *args, **kwargs): """Accept a 'student_lesson_data' parameter.""" self._student_lesson_data = kwargs.pop('student_lesson_data', None) super(StudentUploadedFileForm, self).__init__(*args, **kwargs) def clean(self): """ Ensure that the total number of student_uploaded_file instances that are linked to the student_lesson_data parameter are within limits.""" cleaned_data = super().clean() filecount = self._student_lesson_data.student_uploaded_file.count() if filecount >= 3: raise forms.ValidationError("Sorry, you cannot upload more than three files") return cleaned_datavistas.py:
class StudentUploadView(View): def get(self, request): # stuff ... def post(self, request, *args, **kwargs): sld_id = request.POST.get('student_lesson_data_id', None) student_lesson_data = StudentLessonData.objects.get(id=sld_id) form = StudentUploadedFileForm( request.POST, request.FILES, student_lesson_data=student_lesson_data ) if form.is_valid(): uploaded_file = form.save() # other stuff ...Supongo que puede usar la carga de archivos múltiples en Django aún no se ha filtrado a la comunidad. Extracto:
Si desea cargar varios archivos usando un campo de formulario, configure el atributo HTML múltiple del widget del campo:
# forms.py from django import forms class FileFieldForm(forms.Form): file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))Su estructura de formulario y vista también es muy artificial, excluyendo campos de un formulario y luego configurando valores inyectados a través de un formulario HTML en la instancia del modelo. Sin embargo, con el código que se muestra, la instancia del modelo nunca existiría ya que el formulario no tiene un campo pk. De todos modos, para centrarnos en el problema que necesita solución...
En el formulario, request.FILES ahora es una matriz:
class StudentUploadView(View): model = StudentUploadedFile max_files_per_lesson = 3 def post(request, *args, **kwargs): lesson_data_id = request.POST['student_lesson_data_id'] current_files_count = self.model.objects.filter( student_lesson_data_id=lesson_data_id ).count() avail = self.max_files_per_lesson - current_files_count file_list = request.FILES.get_list('student_file') if avail - len(file_list) < 0: return JsonResponse(data={ 'is_valid': False, 'reason': f'Too many files: you can only upload {avail}.' }) else: # create one new instance of self.model for each file ...Abordar los comentarios: desde una perspectiva estética, se puede hacer mucho con el estilo ...
Sin embargo, la carga asíncrona (solicitudes POST separadas) complica mucho la validación y la experiencia del usuario:
Solicitud de una publicación: