Предел размера загрузки Django File

У меня есть форма в моем django приложении, где пользователи могут загрузить файлы.
Как я могу установить предел к загруженному размеру файла так, чтобы, если пользователь загружает файл, больше, чем мой предел, форма не была допустима, и это бросит ошибку?

58
задан 18 March 2010 в 21:34

4 ответа

Другое изящное решение с блоками проверки допустимости, которое не делает твердого кода макс. размер файла, при помощи основанного на классе блока проверки допустимости:

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 для получения дополнительной информации об этом, работает.

3
ответ дан 1 November 2019 в 13:05

Я хочу благодарить всех людей, которые предоставили всевозможные решения этой проблемы. У меня были дополнительные требования, где я хотел (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

Затем Вам нужна форма, которая и делает проверку в сервере и преобразование перед сохранением от InMemoryUploadedFile до [1 110] и захват Content-Type для более позднего обслуживания.

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

В шаблоне, добавьте этот код (адаптированный из предыдущего ответа):

<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>

Вот код представления, который обрабатывает, и Создайте и Обновление:

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)

Это - очень простое представление, которое удостоверяется тот запрос. ФАЙЛЫ передаются в во время создания экземпляра. Вы могли почти [1 112] использовать универсальный CreateView, если он будет (a) использовало бы мою форму и (b) передало бы request.files при создании образцового экземпляра.

Только для завершения усилия у меня есть следующее простое представление для потоковой передачи файла:

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

Это не вынуждает пользователей быть зарегистрированными, но я опустил это, так как этот ответ является уже слишком длинным.

2
ответ дан 1 November 2019 в 13:05

Можно расширить Django MaxValueValidator и перезаписать, это clean() для возврата размера файла:

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

0
ответ дан 1 November 2019 в 13:05

В моем случае django ограничивают размер файла загрузки. Добавьте, что следующие настройки удалят ограничение.

# allow upload big file
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 15  # 15M
FILE_UPLOAD_MAX_MEMORY_SIZE = DATA_UPLOAD_MAX_MEMORY_SIZE
0
ответ дан 1 November 2019 в 13:05

Другие вопросы по тегам:

Похожие вопросы: