Skip to content

add max_file_size & show loading when file upload #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 63 additions & 25 deletions djvue/static/vue/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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({
[event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit]
});
}
else{
this.$refs.form.setErrors({
[event.target.name]: [file_size_msg + " " + max_file_size_mb + " " + file_size_unit]
});
}
return;
}

Vue.set(vm.uploadInProgress, event.target.name, true)

// clear the errors
this.$refs.form.setErrors({[event.target.name]: []})

Expand All @@ -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)
})
},
},
}
8 changes: 7 additions & 1 deletion djvue/templates/vue/default/file.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% load i18n %}

<validation-provider name="{{ field.name }}"
{% if style.rules %} rules="{{ style.rules }}" {% endif %}
v-slot="{ errors, valid, invalid, touched }"
Expand All @@ -10,13 +12,17 @@
<div class="col-sm-10">
<input name="{{ field.name }}"
type="file"
:disabled="uploadInProgress.{{ field.name }}"
{% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %}
{% if field.value is not None %}value="{{ field.value }}"{% endif %}
{% if field.required %}required{% endif %}
@change="uploadFile($event, '{{ style.upload_url }}')"
@change="uploadFile($event, '{{ style.upload_url }}', '{{ style.max_file_size }}')"
:class="{'is-invalid': touched && invalid, 'is-valid': touched && valid && form.{{ field.name }}}"
>
<span class="help-block text-danger" v-for="error in errors" :key="error">{( error )}</span>
<span v-if="uploadInProgress.{{ field.name }}">
{% trans 'Uploading...' %}
</span>

{% if field.help_text %}
<span class="help-block">{{ field.help_text|safe }}</span>
Expand Down
8 changes: 7 additions & 1 deletion djvue/templates/vue/default/file_multiple.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% load i18n %}

<validation-provider name="{{ field.name }}"
{% if style.rules %} rules="{{ style.rules }}" {% endif %}
v-slot="{ errors, valid, invalid, touched }"
Expand All @@ -10,13 +12,17 @@
<div class="col-sm-10">
<input name="{{ field.name }}"
type="file" multiple
:disabled="uploadInProgress.{{ field.name }}"
{% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %}
{% if field.value is not None %}value="{{ field.value }}"{% endif %}
{% if field.required %}required{% endif %}
@change="uploadFile($event, '{{ style.upload_url }}', true)"
@change="uploadFile($event, '{{ style.upload_url }}', '{{ style.max_file_size }}', true)"
:class="{'is-invalid': touched && invalid, 'is-valid': touched && valid && form.{{ field.name }}}"
>
<span class="help-block text-danger" v-for="error in errors" :key="error">{( error )}</span>
<span class="help-block" v-if="uploadInProgress.{{ field.name }}">
{% trans 'Uploading...' %}
</span>

<ul>
<li v-for="file in files.{{ field.name }}"> {( file.filename )}</li>
Expand Down
4 changes: 4 additions & 0 deletions djvue/templates/vue/starter.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"

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' %}"

</script>
<script src="{% static 'vue/js/script.js' %}"></script>
4 changes: 2 additions & 2 deletions example/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down