У меня есть форма в моем django приложении, где пользователи могут загрузить файлы.
Как я могу установить предел к загруженному размеру файла так, чтобы, если пользователь загружает файл, больше, чем мой предел, форма не была допустима, и это бросит ошибку?
Другое изящное решение с блоками проверки допустимости, которое не делает твердого кода макс. размер файла, при помощи основанного на классе блока проверки допустимости:
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
Затем Вам нужна форма, которая и делает проверку в сервере и преобразование перед сохранением от 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
Это не вынуждает пользователей быть зарегистрированными, но я опустил это, так как этот ответ является уже слишком длинным.
Можно расширить 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
В моем случае django ограничивают размер файла загрузки. Добавьте, что следующие настройки удалят ограничение.
# allow upload big file
DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 15 # 15M
FILE_UPLOAD_MAX_MEMORY_SIZE = DATA_UPLOAD_MAX_MEMORY_SIZE