首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >限制用户可以上载的文件数量

限制用户可以上载的文件数量
EN

Stack Overflow用户
提问于 2020-07-11 13:10:38
回答 3查看 813关注 0票数 8

我有一个多文件上传,并希望限制用户到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尝试:

代码语言:javascript
运行
复制
@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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
<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

代码语言:javascript
运行
复制
$(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

代码语言:javascript
运行
复制
class StudentUploadedFileForm(forms.ModelForm):
    student_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

view.py

代码语言:javascript
运行
复制
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)

谢谢。

EN

回答 3

Stack Overflow用户

发布于 2020-07-18 02:58:35

我尝试过使用PyPi包,它可以完美地工作。我将在这里冒险,并假设您愿意编辑包代码来修复由于兼容性问题而遇到的任何错误,因为大多数很长时间没有更新的包可能会遇到这些错误。

为了解决限制用户上传文件数量的问题,django-multiuploader包将会有很大的帮助,而且诚实地说,它会做比你要求的更多的事情。是的,它使用JQuery表单来上传多个文件。

怎么用?

安装和使用前步骤

安装

代码语言:javascript
运行
复制
pip install django-multiuploader
python3 manage.py syncdb
python3 manage.py migrate multiuploader

settings.py文件中:

代码语言:javascript
运行
复制
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

票数 1
EN

Stack Overflow用户

发布于 2020-07-19 15:51:41

我猜你可以在Django中使用multi file upload还没有普及到社区。摘录:

如果您想使用一个表单字段上传多个文件,请设置字段的控件的multiple属性:

代码语言:javascript
运行
复制
# forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

您的表单和视图结构也是精心设计的,从表单中排除字段,然后通过HTML表单在模型实例上设置注入的值。但是,使用显示的代码,模型实例将永远不会存在,因为表单没有主键字段。不管怎样--专注于需要解决的问题...

在表单中,request.FILES现在是一个数组:

代码语言:javascript
运行
复制
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请求),使验证和用户体验变得非常复杂:

  • 第一个文件可以在第二个之后完成,那么如果计数大于3,您将拒绝哪一个。
  • 前端验证是可破解的,因此您不能依赖它,但后端验证被划分为多个请求,从用户的角度来看,这是一个操作。
  • 但由于文件到达顺序混乱,一些成功,一些失败,您如何向用户提供反馈?
  • 如果1,3和4到达,但用户更关心1,2,3-用户必须采取多项措施来纠正这种情况。

一个post请求:

  • 没有乱序到达您可以使用“一切失败或一切成功”的方法,这种方法对最终用户是透明的,并且很容易correct.
  • It's文件数组顺序可能是用户首选的顺序,因此即使您允许部分成功,您也可能会做正确的事情。
票数 1
EN

Stack Overflow用户

发布于 2020-07-14 12:46:17

所以它的要点是您正在使用jQuery .each通过AJAX上传图像。对Django视图的每个POST请求都是一个文件上传,但可能同时有多个请求。

试试这个:

forms.py:

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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 ...
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62845434

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档