simple - request.files django
Limite el tamaño del archivo de carga con Django y visualice la página de error (2)
Uso Django y me gustaría mostrar una página de error si la carga de un archivo excede el tamaño permitido sin cargar todo el contenido. Para esto, se utilizó un controlador de carga personalizado.
Por un lado, el controlador de carga comprueba la longitud total del contenido en el encabezado POST, además, se realiza un seguimiento de los fragmentos cargados y se suma su tamaño.
Lamentablemente, no sé cómo activar la generación de una página de error.
Mi primera idea fue devolver contenido POST y ARCHIVO vacío y detectar esto en la vista, pero esto no funciona.
from django.core.files.uploadhandler import FileUploadHandler, StopUpload
from django.http import QueryDict
from django.utils.datastructures import MultiValueDict
class QuotaUploadHandler(FileUploadHandler):
"""
This test upload handler terminates the connection if more than a quota
(5MB) is uploaded.
"""
QUOTA = 5 * 2**20 # 5 MB
def __init__(self, request=None):
super(QuotaUploadHandler, self).__init__(request)
self.total_upload = 0
def handle_raw_input(self, input_data, META, content_length, boundary, encoding=None):
tmp_post = QueryDict('''', mutable=True)
tmp_files = MultiValueDict()
if content_length > self.QUOTA:
META["ERROR"] = "File is larger than maximum."
return tmp_post, tmp_files
def receive_data_chunk(self, raw_data, start):
self.total_upload += len(raw_data)
if self.total_upload >= self.QUOTA:
raise StopUpload(connection_reset=True)
return raw_data
def file_complete(self, file_size):
return None
class CustomUploadError(Exception):
pass
¿Alguien puede ayudar?
Actualizar:
Otra solución que revisé fue algo como esto en la vista:
def main(request):
request.upload_handlers.insert(0, QuotaUploadHandler())
content_length = request.META["CONTENT_LENGTH"]
if content_length is not "" and int(content_length) > 5 * 1024 * 1024:
print "Upload to large."
raise Http404
return csrf_protected_main(request)
Comprobé el resultado con una captura wireshark: en este caso, la respuesta del servidor se sirve al cliente, pero el servidor Django restablece el socket TCP (presumiblemente porque todavía está recibiendo entrada).
POST / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.24) Gecko/20111107 Ubuntu/10.10 (maverick) Firefox/3.6.24
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://localhost:8080/
Cookie: csrftoken=078fa2166ff190b148ac9045b3c408d7
Content-Type: multipart/form-data; boundary=---------------------------37071231519976700161208143859
Content-Length: 20971913
-----------------------------37071231519976700161208143859
Content-Disposition: form-data; name="testfile"; filename="test.test"
Content-Type: application/octet-stream
....
[36864 bytes missing in capture file] .......
HTTP/1.0 404 NOT FOUND
Date: Sat, 10 Dec 2011 19:57:37 GMT
Server: WSGIServer/0.1 Python/2.6.6
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
...
[ongoing]
También traté de detener la carga con un código de respuesta HTTP 413 (archivo a gran tamaño), pero tampoco funcionó.
Tengo un campo como este:
class MyFileField(FileField):
def clean(self, data):
max_size = settings.MAX_SIZE_UPLOAD
if data and max_size and len(data) > max_size:
raise ValidationError(_(''File too large. Max size restricted to %s bytes'') % max_size)
return super(MyFileField, self).clean(data)
Si el archivo tiene un tamaño superior a MAX_SIZE_UPLOAD, existe un error en el formulario
como han descrito otros comentaristas, si comprueba la longitud del contenido en la capa de Django, entonces ya ha terminado de cargar todo el archivo, que podría no ser demasiado bueno. si realmente desea detenerlo en el nivel del servidor de aplicaciones, algunos servidores web tienen una directiva que puede usar para informar a los clientes que han excedido los límites de tamaño de carga.
por ejemplo, el LimitRequestBody de Apache se puede usar para especificar la cantidad máxima de bytes permitidos para un cuerpo de solicitud. Yo uso esto en el httpd.conf de mi apache (para hacerlo ''global'') pero también puedes usar el LimitRequestBody en el nivel. en mi http.conf:
# limit requests to 25MB
LimitRequestBody 26214400
cuando este límite es disparado por una solicitud, Apache devolverá un HTTP estándar específico utilizado para este propósito:
Error HTTP: 413 entidad de solicitud demasiado grande
dependiendo de cómo esté configurada su aplicación (¿usa JS en el cliente para realizar esa solicitud?), entonces puede manejar el error en el lado del cliente si se devuelve este error en particular.
HTH.