Nice programing

Django 파일 업로드 크기 제한

nicepro 2020. 12. 9. 21:47
반응형

Django 파일 업로드 크기 제한


내 django 앱에 사용자가 파일을 업로드 할 수있는 양식이 있습니다.
사용자가 내 제한보다 큰 파일을 업로드하면 양식이 유효하지 않고 오류가 발생하도록 업로드 된 파일 크기에 제한을 어떻게 설정할 수 있습니까?


이 코드가 도움이 될 수 있습니다.

# Add to your settings file
CONTENT_TYPES = ['image', 'video']
# 2.5MB - 2621440
# 5MB - 5242880
# 10MB - 10485760
# 20MB - 20971520
# 50MB - 5242880
# 100MB 104857600
# 250MB - 214958080
# 500MB - 429916160
MAX_UPLOAD_SIZE = "5242880"

#Add to a form containing a FileField and change the field names accordingly.
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
def clean_content(self):
    content = self.cleaned_data['content']
    content_type = content.content_type.split('/')[0]
    if content_type in settings.CONTENT_TYPES:
        if content._size > settings.MAX_UPLOAD_SIZE:
            raise forms.ValidationError(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(settings.MAX_UPLOAD_SIZE), filesizeformat(content._size)))
    else:
        raise forms.ValidationError(_('File type is not supported'))
    return content

출처 : Django Snippets-파일 콘텐츠 유형 및 크기로 유효성 검사


이 스 니펫 formatChecker를 사용할 수 있습니다. 그것이하는 일은

  • 업로드 할 수있는 파일 형식을 지정할 수 있습니다.

  • 업로드 할 파일의 파일 크기 제한을 설정할 수 있습니다.

먼저. 특정 파일 형식을 허용하려는 FileField가있는 모델이있는 앱 내부에 formatChecker.py라는 파일을 만듭니다.

이것은 formatChecker.py입니다.

from django.db.models import FileField
from django.forms import forms
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _

class ContentTypeRestrictedFileField(FileField):
    """
    Same as FileField, but you can specify:
        * content_types - list containing allowed content_types. Example: ['application/pdf', 'image/jpeg']
        * max_upload_size - a number indicating the maximum file size allowed for upload.
            2.5MB - 2621440
            5MB - 5242880
            10MB - 10485760
            20MB - 20971520
            50MB - 5242880
            100MB 104857600
            250MB - 214958080
            500MB - 429916160
    """
    def __init__(self, *args, **kwargs):
        self.content_types = kwargs.pop("content_types")
        self.max_upload_size = kwargs.pop("max_upload_size")

        super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs)

    def clean(self, *args, **kwargs):
        data = super(ContentTypeRestrictedFileField, self).clean(*args, **kwargs)

        file = data.file
        try:
            content_type = file.content_type
            if content_type in self.content_types:
                if file._size > self.max_upload_size:
                    raise forms.ValidationError(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(self.max_upload_size), filesizeformat(file._size)))
            else:
                raise forms.ValidationError(_('Filetype not supported.'))
        except AttributeError:
            pass

        return data

둘째. models.py에 다음을 추가하십시오.

from formatChecker import ContentTypeRestrictedFileField

그런 다음 'FileField'를 사용하는 대신이 'ContentTypeRestrictedFileField'를 사용하십시오.

예:

class Stuff(models.Model):
    title = models.CharField(max_length=245)
    handout = ContentTypeRestrictedFileField(upload_to='uploads/', content_types=['video/x-msvideo', 'application/pdf', 'video/mp4', 'audio/mpeg', ],max_upload_size=5242880,blank=True, null=True)

'max_upload_size'의 값을 원하는 파일 크기 제한으로 변경할 수 있습니다. 'content_types'목록의 값을 수락하려는 파일 형식으로 변경할 수도 있습니다.


다른 솔루션은 유효성 검사기를 사용하고 있습니다.

from django.core.exceptions import ValidationError

def file_size(value): # add this to some file where you can import it from
    limit = 2 * 1024 * 1024
    if value.size > limit:
        raise ValidationError('File too large. Size should not exceed 2 MiB.')

그런 다음 파일 필드가있는 양식에 다음과 같은 내용이 있습니다.

image = forms.FileField(required=False, validators=[file_size])

나는 django 폼이 파일이 완전히 업로드 된 후에 만 ​​파일을받는다고 믿습니다. 그래서 누군가 2Gb 파일을 업로드하면 웹 서버에서 크기를 즉시 확인하는 것이 훨씬 좋습니다.

자세한 내용은이 메일 스레드 를 참조하십시오.


이 스레드에 포함 된 스 니펫에 대한 짧은 메모 :

이 스 니펫을 살펴보세요 : http://www.djangosnippets.org/snippets/1303/

매우 유용했지만 몇 가지 사소한 실수가 포함되어 있습니다. 보다 강력한 코드는 다음과 같습니다.

# Add to your settings file
CONTENT_TYPES = ['image', 'video']
# 2.5MB - 2621440
# 5MB - 5242880
# 10MB - 10485760
# 20MB - 20971520
# 50MB - 5242880
# 100MB - 104857600
# 250MB - 214958080
# 500MB - 429916160
MAX_UPLOAD_SIZE = "5242880"

#Add to a form containing a FileField and change the field names accordingly.
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
def clean_content(self):
    if content != None:
        content = self.cleaned_data['content']
        content_type = content.content_type.split('/')[0]
        if content_type in settings.CONTENT_TYPES:
            if content._size > int(settings.MAX_UPLOAD_SIZE):
                raise forms.ValidationError(_(u'Please keep filesize under %s. Current filesize %s') % (filesizeformat(settings.MAX_UPLOAD_SIZE), filesizeformat(content._size)))
        else:
            raise forms.ValidationError(_(u'File type is not supported'))
        return content

몇 가지 개선 사항이 있습니다.

우선 파일 필드가 비어 있는지 (없음) 감지합니다. 그렇지 않으면 Django는 웹 브라우저에서 예외를 캐스팅합니다.

다음은 설정 값이 문자열이기 때문에 int (settings.MAX_UPLOAD_SIZE)의 타입 캐스팅입니다. 숫자와 비교하는 데 문자열을 사용할 수 없습니다.

마지막으로 ValidationError 함수의 유니 코드 'u'접두사입니다.

이 스 니펫에 감사드립니다!


누군가 FileField@angelo 솔루션 의 형태 변형을 찾고 있다면 여기에 있습니다.

from django import forms
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError

class RestrictedFileField(forms.FileField):
    """
    Same as FileField, but you can specify:
    * content_types - list containing allowed content_types. Example: ['application/pdf', 'image/jpeg']
    * max_upload_size - a number indicating the maximum file size allowed for upload.
        2.5MB - 2621440
        5MB - 5242880
        10MB - 10485760
        20MB - 20971520
        50MB - 5242880
        100MB - 104857600
        250MB - 214958080
        500MB - 429916160
"""

    def __init__(self, *args, **kwargs):
        self.content_types = kwargs.pop("content_types")
        self.max_upload_size = kwargs.pop("max_upload_size")

        super(RestrictedFileField, self).__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        file = super(RestrictedFileField, self).clean(data, initial)

        try:
            content_type = file.content_type
            if content_type in self.content_types:
                if file._size > self.max_upload_size:
                    raise ValidationError(_('Please keep filesize under %s. Current filesize %s') % (
                        filesizeformat(self.max_upload_size), filesizeformat(file._size)))
            else:
                raise ValidationError(_('Filetype not supported.'))
        except AttributeError:
            pass

        return data

그런 다음 다음과 같이 양식을 만듭니다.

class ImageUploadForm(forms.Form):
    """Image upload form."""
    db_image = RestrictedFileField(content_types=['image/png', 'image/jpeg'],
                                   max_upload_size=5242880)

서버 측

파일이 너무 커서 여부를 확인 중 내가 가장 좋아하는 방법 서버 측 이다 olarewaju의 대답은 ifedapo 유효성 검사기를 사용하여.

고객 입장에서

서버 측 유효성 검사 만 갖는 문제는 업로드가 완료된 후에 만 ​​유효성 검사가 발생한다는 것입니다. 대용량 파일을 업로드하고 오래 기다렸다가 나중에 파일이 너무 크다는 알림 만받는다고 상상해보십시오. 브라우저가 파일이 너무 크다는 것을 미리 알려 주면 더 좋지 않을까요?

글쎄, HTML5 파일 API를 사용하여 클라이언트 측에 방법이 있습니다 !

다음은 필수 Javascript입니다 (JQuery에 따라 다름).

$("form").submit(function() {
  if (window.File && window.FileReader && window.FileList && window.Blob) {
    var file = $('#id_file')[0].files[0];

    if (file && file.size > 2 * 1024 * 1024) {
      alert("File " + file.name + " of type " + file.type + " is too big");
      return false;
    }
  }
});

물론 악의적 인 입력과 Javascript를 사용하지 않는 사용자로부터 보호하려면 서버 측 유효성 검사가 여전히 필요합니다.


최대 파일 크기를 하드 코딩하지 않는 유효성 검사기를 사용하는 또 다른 우아한 솔루션은 클래스 기반 유효성 검사기를 사용하는 것입니다.

from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator
from django.utils.translation import ugettext as _

class MaxSizeValidator(MaxValueValidator):
message = _('The file exceed the maximum size of %(limit_value)s MB.')

def __call__(self, value):
    # get the file size as cleaned value
    cleaned = self.clean(value.size)
    params = {'limit_value': self.limit_value, 'show_value': cleaned, 'value': value}
    if self.compare(cleaned, self.limit_value * 1024 * 1024): # convert limit_value from MB to Bytes
        raise ValidationError(self.message, code=self.code, params=params)

그런 다음 모델에서 예를 들면 다음과 같습니다.

image = models.ImageField(verbose_name='Image', upload_to='images/', validators=[MaxSizeValidator(1)])

편집 : 여기 의 소스 코드는 MaxValueValidator이 작품에 대한 자세한 내용은.


이 문제에 대해 다양한 솔루션을 제공해 주신 모든 분들께 감사드립니다. (a) 제출하기 전에 JavaScript에서 파일 길이 유효성 검사를 수행하고, (b)에서 서버 내 유효성 검사의 두 번째 줄을 수행하고 forms.py, (c) 최종 사용자 메시지를 포함한 모든 하드 코딩 된 비트를 유지 하려는 추가 요구 사항이있었습니다. forms.py내 원하는 (D), views.py작은 파일 관련 가능한 코드, 및 (d)이 내가에만 로그인 한 사용자에게 역할을 즉시 할 때 삭제를 작은 파일을 때문에 내 데이터베이스에 파일 정보를 업로드로이 Meal모델을 항목이 삭제됩니다 (즉, / media /에 놓는 것만으로는 충분하지 않습니다).

먼저 모델 :

class Meal(models.Model) :
    title = models.CharField(max_length=200)
    text = models.TextField()

    # Picture (you need content type to serve it properly)
    picture = models.BinaryField(null=True, editable=True)
    content_type = models.CharField(max_length=256, null=True, help_text='The MIMEType of the file')

    # Shows up in the admin list
    def __str__(self):
        return self.title

Then you need a form that both does the in-server validation and the pre-save conversion from InMemoryUploadedFile to bytes and grabbing the Content-Type for later serving.

class CreateForm(forms.ModelForm):
    max_upload_limit = 2 * 1024 * 1024
    max_upload_limit_text = str(max_upload_limit) # A more natural size would be nice
    upload_field_name = 'picture'
    # Call this 'picture' so it gets copied from the form to the in-memory model
    picture = forms.FileField(required=False, label='File to Upload <= '+max_upload_limit_text)

    class Meta:
        model = Meal
        fields = ['title', 'text', 'picture']

    def clean(self) :  # Reject if the file is too large
        cleaned_data = super().clean()
        pic = cleaned_data.get('picture')
        if pic is None : return
        if len(pic) > self.max_upload_limit:
            self.add_error('picture', "File must be < "+self.max_upload_limit_text+" bytes")

    def save(self, commit=True) : # Convert uploaded files to bytes
        instance = super(CreateForm, self).save(commit=False)
        f = instance.picture   # Make a copy
        if isinstance(f, InMemoryUploadedFile):
            bytearr = f.read();
            instance.content_type = f.content_type
            instance.picture = bytearr  # Overwrite with the actual image data

        if commit:
            instance.save()
        return instance

In the template, add this code (adapted from a previous answer):

<script>
$("#upload_form").submit(function() {
  if (window.File && window.FileReader && window.FileList && window.Blob) {
      var file = $('#id_{{ form.upload_field_name }}')[0].files[0];
      if (file && file.size > {{ form.max_upload_limit }} ) {
          alert("File " + file.name + " of type " + file.type + " must be < {{ form.max_upload_limit_text }}");
      return false;
    }
  }
});
</script>

Here is the view code that handles both Create and Update:

class MealFormView(LoginRequiredMixin, View):
    template = 'meal_form.html'
    success_url = reverse_lazy('meals')
    def get(self, request, pk=None) :
        if not pk :
            form = CreateForm()
        else:
            meal = get_object_or_404(Meal, id=pk, owner=self.request.user)
            form = CreateForm(instance=meal)
        ctx = { 'form': form }
        return render(request, self.template, ctx)

    def post(self, request, pk=None) :
        if not pk:
            form = CreateForm(request.POST, request.FILES or None)
        else:
            meal = get_object_or_404(Meal, id=pk, owner=self.request.user)
            form = CreateForm(request.POST, request.FILES or None, instance=meal)

        if not form.is_valid() :
            ctx = {'form' : form}
            return render(request, self.template, ctx)

        form.save()
        return redirect(self.success_url)

This is a very simple view that makes sure that request.FILES is passed in during the creation of the instance. You could almost use the generic CreateView if it would (a) use my form and (b) pass request.files when making the model instance.

Just to complete the effort, I have the following simple view to stream the file:

def stream_file(request, pk) :
    meal = get_object_or_404(Meal, id=pk)
    response = HttpResponse()
    response['Content-Type'] = meal.content_type
    response['Content-Length'] = len(meal.picture)
    response.write(meal.picture)
    return response

This does not force users to be logged in, but I omitted that since this answer is already too long.


from django.forms.utils import ErrorList

class Mymodelform(forms.ModelForm):
    class Meta:
        model = Mymodel
        fields = '__all__'

    def clean(self):image = self.cleaned_data.get('image')
        # 5MB - 5242880
        if org_image._size > 5242880:            
            self._errors["image"] = ErrorList([u"Image too heavy."])

You can extend Django's MaxValueValidator and overwrite it's clean() to return the file size:

from django.core.validators import MaxValueValidator
from django.utils.deconstruct import deconstructible
from django.utils.translation import ugettext_lazy as _


@deconstructible
class MaxKibFileSizeValidator(MaxValueValidator):
    message = _('File size %(show_value)d KiB exceeds maximum file size of %(limit_value)d KiB.')

    def clean(self, filefield) -> float:
        return filefield.file.size / 1024


In my case, django limit the upload file size. Add the following settings will remove restriction.

# allow upload big file
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 15  # 15M
FILE_UPLOAD_MAX_MEMORY_SIZE = DATA_UPLOAD_MAX_MEMORY_SIZE

참고URL : https://stackoverflow.com/questions/2472422/django-file-upload-size-limit

반응형