From 3681d329be96caebb85ffcab1b7a4ffd4a136662 Mon Sep 17 00:00:00 2001 From: Ahmed ElBahnihi Date: Mon, 11 Jan 2021 08:37:27 +0200 Subject: [PATCH 1/2] add max_file_size & show loading when file upload --- djvue/static/vue/js/script.js | 88 +++++++++++++------ djvue/templates/vue/default/file.html | 8 +- .../templates/vue/default/file_multiple.html | 8 +- djvue/templates/vue/starter.html | 3 + example/serializers.py | 4 +- 5 files changed, 82 insertions(+), 29 deletions(-) diff --git a/djvue/static/vue/js/script.js b/djvue/static/vue/js/script.js index cafd430..408e357 100644 --- a/djvue/static/vue/js/script.js +++ b/djvue/static/vue/js/script.js @@ -9,11 +9,17 @@ let djVueMixin = { options: {}, nonFieldErrors: [], actionURL: null, + uploadInProgress: {}, form: {}, files: {}, fileUploadURL: uploadURL } }, + computed: { + canSubmit: function() { + return !this.submitInProgress && !Object.values(this.uploadInProgress).some(e => e === true) + } + }, mounted() { axios.options(this.actionURL).then((response) => { this.options = response.data.actions.POST @@ -116,10 +122,40 @@ let djVueMixin = { } }) }, - uploadFile(event, url, multiple=false) { + uploadFile(event, url, max_file_size, multiple=false) { let formData = new FormData() // save vue instance for being able to reference it later. const vm = this + file_size = event.target.files[0].size + uploaded_files = [] + if(this.files["files"]){ + this.files["files"].forEach(key=> { + uploaded_files.push(key.filename) + }) + } + if(uploaded_files.includes(event.target.files[0].name)){ + this.$refs.form.setErrors({ + files: [duplicate_file_msg] + }); + return + } + let max_file_size_mb = Boolean(max_file_size) ? parseFloat(max_file_size) : 15; + if (file_size > 1024 * 1024 * max_file_size_mb) { + if(multiple){ + this.$refs.form.setErrors({ + files: [file_size_msg] + }); + } + else{ + this.$refs.form.setErrors({ + file: [file_size_msg] + }); + } + return; + } + + Vue.set(vm.uploadInProgress, event.target.name, true) + // clear the errors this.$refs.form.setErrors({[event.target.name]: []}) @@ -128,32 +164,34 @@ let djVueMixin = { formData.append("file", event.target.files[0]) axios - .post(uploadURL, formData, { - headers: { - "Content-Type": "multipart/form-data", - }, - }) - .then(({ data }) => { - // save details on the form data which will be sent to the server - if (multiple) { - let current_files = [] - if (event.target.name in vm.files) { - current_files = vm.files[event.target.name] - } - current_files.push(data); - Vue.set(vm.files, event.target.name, current_files) - - } else { - Vue.set(vm.files, event.target.name, data) - vm.$emit('uploadedFile', event) + .post(uploadURL, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }) + .then(({ data }) => { + // save details on the form data which will be sent to the server + if (multiple) { + let current_files = [] + if (event.target.name in vm.files) { + current_files = vm.files[event.target.name] } + current_files.push(data); + Vue.set(vm.files, event.target.name, current_files) - }) - .catch((error) => { - // remove the file from the input - event.target.value = null - vm.error(error) - }) + } else { + Vue.set(vm.files, event.target.name, data) + + } + + }) + .catch((error) => { + // remove the file from the input + event.target.value = null + vm.error(error) + }).finally(() => { + Vue.set(vm.uploadInProgress, event.target.name, false) + }) }, }, } diff --git a/djvue/templates/vue/default/file.html b/djvue/templates/vue/default/file.html index 966765b..95d3482 100644 --- a/djvue/templates/vue/default/file.html +++ b/djvue/templates/vue/default/file.html @@ -1,3 +1,5 @@ +{% load i18n %} + {( error )} + + {% trans 'Uploading...' %} + {% if field.help_text %} {{ field.help_text|safe }} diff --git a/djvue/templates/vue/default/file_multiple.html b/djvue/templates/vue/default/file_multiple.html index 35c08fc..c9ba214 100644 --- a/djvue/templates/vue/default/file_multiple.html +++ b/djvue/templates/vue/default/file_multiple.html @@ -1,3 +1,5 @@ +{% load i18n %} + {( error )} + + {% trans 'Uploading...' %} +
  • {( file.filename )}
  • diff --git a/djvue/templates/vue/starter.html b/djvue/templates/vue/starter.html index 26ce920..8c4eac1 100644 --- a/djvue/templates/vue/starter.html +++ b/djvue/templates/vue/starter.html @@ -25,5 +25,8 @@ axios.defaults.xsrfCookieName = 'csrftoken' axios.defaults.xsrfHeaderName = "X-CSRFTOKEN" + let file_size_msg = "{% trans 'File size should be less than 15 MB' %}" + let duplicate_file_msg = "{% trans 'This file is already uploaded' %}" + diff --git a/example/serializers.py b/example/serializers.py index c6d08da..f14e783 100644 --- a/example/serializers.py +++ b/example/serializers.py @@ -51,9 +51,9 @@ class ProfileSerializer(serializers.ModelSerializer): style={"input_type": "password", "rules": "password:@password2"}, ) password2 = serializers.CharField(write_only=True, style={"input_type": "password"}) - multiple_file = ListFileField(required=True) + multiple_file = ListFileField(required=True, style={"max_file_size": 100}) multiple_pdf = ListFileField(style={"upload_url": reverse_lazy("example:pdf_upload")}) - file = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload")}) + file = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload"), "max_file_size": 15}) # cv = FileField(required=True, style={"upload_url": reverse_lazy("example:pdf_upload")}) # file = FileField(required=True) working_place = WorkSerializer(write_only=True) From 628e363297c676865aab28e83f04906d933540c0 Mon Sep 17 00:00:00 2001 From: Ahmed ElBahnihi Date: Mon, 11 Jan 2021 12:45:49 +0200 Subject: [PATCH 2/2] correct file_size_msg to reflect max_file_size --- djvue/static/vue/js/script.js | 4 ++-- djvue/templates/vue/starter.html | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/djvue/static/vue/js/script.js b/djvue/static/vue/js/script.js index 408e357..024d568 100644 --- a/djvue/static/vue/js/script.js +++ b/djvue/static/vue/js/script.js @@ -143,12 +143,12 @@ let djVueMixin = { if (file_size > 1024 * 1024 * max_file_size_mb) { if(multiple){ this.$refs.form.setErrors({ - files: [file_size_msg] + [event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit] }); } else{ this.$refs.form.setErrors({ - file: [file_size_msg] + [event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit] }); } return; diff --git a/djvue/templates/vue/starter.html b/djvue/templates/vue/starter.html index 8c4eac1..6290afe 100644 --- a/djvue/templates/vue/starter.html +++ b/djvue/templates/vue/starter.html @@ -25,7 +25,8 @@ axios.defaults.xsrfCookieName = 'csrftoken' axios.defaults.xsrfHeaderName = "X-CSRFTOKEN" - let file_size_msg = "{% trans 'File size should be less than 15 MB' %}" + let file_size_msg = "{% trans 'File size should be less than' %}" + let file_size_unit = "{% trans 'Mega Byte' %}" let duplicate_file_msg = "{% trans 'This file is already uploaded' %}"