我有一个多文件上传,并希望限制用户到3个上传每个。我的问题是,我需要知道user
已经在数据库中创建了多少文件,以及它们当前正在上传多少文件(它们可以一次上传多个文件,并且可以多次上传)。
我尝试了很多方法,包括:
创建一个validator (验证器收到的是实际添加的文件,而不是model
,所以我无法访问model
来获取调用if StudentUploadedFile.objects.filter(student_lesson_data=data.id).count() >= 4:
的id
)。
在clean(self):
中做验证(clean
一次只通过一个实例,直到清理完所有文件后数据库才会更新,所以我可以计算数据库中已经存在的文件,但不能计算当前上传了多少文件)。
使用pre-save
方法(如果DB是在传递给我的pre-save
方法的每个文件之间更新的,那么它是有效的,但是只有在所有上传的文件都通过了我的pre-save
方法之后,DB才会更新)。
我的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')
编辑:
models.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)
views.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)
template.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>")
}
}
});
});
更新: forms.py
class StudentUploadedFileForm(forms.ModelForm):
student_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
view.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)
谢谢。
发布于 2020-07-17 18:58:35
我尝试过使用PyPi包,它可以完美地工作。我将在这里冒险,并假设您愿意编辑包代码来修复由于兼容性问题而遇到的任何错误,因为大多数很长时间没有更新的包可能会遇到这些错误。
为了解决限制用户上传文件数量的问题,django-multiuploader
包将会有很大的帮助,而且诚实地说,它会做比你要求的更多的事情。是的,它使用JQuery表单来上传多个文件。
怎么用?
安装和使用前步骤
安装
pip install django-multiuploader
python3 manage.py syncdb
python3 manage.py migrate multiuploader
在settings.py
文件中:
MULTIUPLOADER_FILES_FOLDER = ‘multiuploader’ # - media location where to store files
MULTIUPLOADER_FILE_EXPIRATION_TIME = 3600 # - time, when the file is expired (and it can be cleaned with clean_files command).
MULTIUPLOADER_FORMS_SETTINGS =
{
'default': {
'FILE_TYPES' : ["txt","zip","jpg","jpeg","flv","png"],
'CONTENT_TYPES' : [
'image/jpeg',
'image/png',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.presentation',
'text/plain',
'text/rtf',
],
'MAX_FILE_SIZE': 10485760,
'MAX_FILE_NUMBER':5,
'AUTO_UPLOAD': True,
},
'images':{
'FILE_TYPES' : ['jpg', 'jpeg', 'png', 'gif', 'svg', 'bmp', 'tiff', 'ico' ],
'CONTENT_TYPES' : [
'image/gif',
'image/jpeg',
'image/pjpeg',
'image/png',
'image/svg+xml',
'image/tiff',
'image/vnd.microsoft.icon',
'image/vnd.wap.wbmp',
],
'MAX_FILE_SIZE': 10485760,
'MAX_FILE_NUMBER':5,
'AUTO_UPLOAD': True,
},
'video':{
'FILE_TYPES' : ['flv', 'mpg', 'mpeg', 'mp4' ,'avi', 'mkv', 'ogg', 'wmv', 'mov', 'webm' ],
'CONTENT_TYPES' : [
'video/mpeg',
'video/mp4',
'video/ogg',
'video/quicktime',
'video/webm',
'video/x-ms-wmv',
'video/x-flv',
],
'MAX_FILE_SIZE': 10485760,
'MAX_FILE_NUMBER':5,
'AUTO_UPLOAD': True,
},
'audio':{
'FILE_TYPES' : ['mp3', 'mp4', 'ogg', 'wma', 'wax', 'wav', 'webm' ],
'CONTENT_TYPES' : [
'audio/basic',
'audio/L24',
'audio/mp4',
'audio/mpeg',
'audio/ogg',
'audio/vorbis',
'audio/x-ms-wma',
'audio/x-ms-wax',
'audio/vnd.rn-realaudio',
'audio/vnd.wave',
'audio/webm'
],
'MAX_FILE_SIZE': 10485760,
'MAX_FILE_NUMBER':5,
'AUTO_UPLOAD': True,
}}
注意那个MAX_FILE_NUMBER
,他们就是你问题的答案。安装后请查看源代码,如果需要,可以尝试自己实现它。这可能会很有趣。
有关更多说明,请参阅:django-multiuploader package on pypi
发布于 2020-07-19 07:51:41
我猜你可以在Django中使用multi file upload还没有普及到社区。摘录:
如果您想使用一个表单字段上传多个文件,请设置字段的控件的multiple属性:
# forms.py
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
您的表单和视图结构也是精心设计的,从表单中排除字段,然后通过HTML表单在模型实例上设置注入的值。但是,使用显示的代码,模型实例将永远不会存在,因为表单没有主键字段。不管怎样--专注于需要解决的问题...
在表单中,request.FILES现在是一个数组:
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
...
处理评论:从美学的角度来看,你可以做很多with styling...
然而,上传异步(单独的POST请求),使验证和用户体验变得非常复杂:
一个post请求:
发布于 2020-07-14 04:46:17
所以它的要点是您正在使用jQuery .each
通过AJAX上传图像。对Django视图的每个POST请求都是一个文件上传,但可能同时有多个请求。
试试这个:
forms.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_data
views.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 ...
https://stackoverflow.com/questions/62845434
复制相似问题