template tag serve img imagenes imagen fondo con django amazon-s3 boto sorl-thumbnail django-storage

tag - Almacenamiento de imágenes y miniaturas en s3 en django



media url django (3)

Estoy intentando que mis imágenes se vean y almacenen en s3 usando django-storage, boto y sorl-thumbnail. Lo tengo funcionando, pero es muy lento, incluso con imágenes pequeñas. No me importa que sea lento cuando guardo el formulario y cargo las imágenes en s3, pero me gustaría que muestre la imagen rápidamente después de eso.

La respuesta a esta pregunta SO explica que la miniatura no se creará hasta el primer acceso, pero que puede usar get_thumbnail () para crearla de antemano.

Django + S3 (boto) + miniatura de Sorl: sugerencias para la optimización

Estoy haciendo eso, y ahora parece que todas las entradas en la tabla thumbnail_kvstore se crean al cargar la imagen, en lugar de cuando se muestra.

El problema es que la página que muestra la imagen todavía es muy lenta. Al mirar el panel de registro en la barra de herramientas de depuración, parece que todavía hay mucha comunicación con s3. Parece que después de que la imagen y las miniaturas se cargan y almacenan en caché, la página debe procesarse rápidamente sin comunicarse con s3.

¿Qué estoy haciendo mal? ¡Gracias!

Actualización : el truco débil parece haber funcionado, pero me encantaría saber cómo hacerlo correctamente:

https://github.com/asciitaxi/sorl-thumbnail/commit/545cce3f5e719a91dd9cc21d78bb973b2211bbbf

Actualización : más información para @sorl

Estoy trabajando con 2 vistas:

AGREGAR VISTA: En esta vista, envío el formulario para crear el modelo con la imagen en él. La imagen se carga en s3. En una señal post_save, invoco get_thumbnail () para generar la miniatura antes de que sea necesaria:

im = get_thumbnail(instance.image, ''360x360'')

VISTA EN PANTALLA: en esta vista, muestro la miniatura generada en la vista de agregar:

{% thumbnail object.image "360x360" as im %} <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}"> {% endthumbnail %}

Sin el parche:

AGREGAR VISTA: crea 3 entradas en la tabla kvstore, accede a la memoria caché 10 veces (6 conjuntos, 4 obtiene), la pestaña de inicio de sesión de la barra de herramientas de depuración dice "establecer conexión HTTP" 12 veces

VISUALIZACIÓN DE PANTALLA: solo quedan 3 entradas en la tabla kvstore, solo 1 obtiene de la memoria caché, pero la barra de herramientas de depuración dice "establecer conexión HTTP" 3 veces todavía

Con solo el cambio en la línea 122:

AGREGAR VISTA: lo mismo que arriba, excepto que el registro solo dice "establecer conexión HTTP" 2 veces VISTA EN PANTALLA: igual que arriba, excepto que el registro solo dice "establecer conexión HTTP" 1 vez

También agregando el cambio en la línea 118:

AGREGAR VISTA: igual que arriba, pero ahora estamos abajo a 2 mensajes "establecer conexión HTTP" VISTA EN PANTALLA: igual que arriba, sin mensajes de registro en absoluto

ACTUALIZACIÓN : Parece que se llama dos veces a storage._setup () y se llama a storage.url () una vez. De acuerdo con el calendario, yo diría que cada uno hace conexiones con s3:

1304711315.4 _setup 1304711317.84 1304711317.84 _setup 1304711320.3 1304711320.39 _url 1304711323.66

Esto parece reflejarse en el registro de boto, que dice "establecer conexión HTTP" 3 veces.


Como autor de sorl thumbnail, estoy realmente interesado en resolver esto si no funciona como pretendía. Si el valor de clave sotre está lleno, actualmente se almacenará: nombre, almacenamiento y tamaño. He asumido que la URL se basa en el nombre y, por lo tanto, no debe causar ninguna llamada de almacenamiento. En cuanto a los almacenes de django, https://github.com/e-loue/django-storages/blob/master/storages/backends/s3boto.py#L214 parece una suposición segura. En su parche, ha parchado el método de lectura por algún motivo. Al crear una miniatura, se extrae una instancia de ImageFile del caché (si no la crea), por supuesto, puede llamar a read para leer el archivo, pero el uso previsto es .url, que llama a url en el almacenamiento con el nombre en caché que debe ser una opcion de acceso sin almacenamiento ¿Podría tratar de aislar su problema para determinar exactamente en qué parte de su código tiene lugar este acceso de almacenamiento?

También asegúrese de que tiene THUMBNAIL_DEBUG activado y que tiene el almacén de valores clave configurado correctamente.


Después de mirar el boleto de django de @shadfc, reimplementé el monopatch de la siguiente manera:

from django.core.files.images import ImageFile def _get_image_dimensions(self): if not hasattr(self, ''_dimensions_cache''): if getattr(self.storage, ''IGNORE_IMAGE_DIMENSIONS'', False): self._dimensions_cache = (0, 0) else: close = self.closed self.open() self._dimensions_cache = get_image_dimensions(self, close=close) return self._dimensions_cache ImageFile._get_image_dimensions = _get_image_dimensions

Para usarlo, simplemente agregue IGNORE_IMAGE_DIMENSIONS = True a su clase de almacenamiento y no se tocará para obtener las dimensiones de la imagen. Probable:

from storages.backends.s3boto import S3BotoStorage S3BotoStorage.IGNORE_IMAGE_DIMENSIONS = True

Todavía necesito investigar dónde se usan los números, para saber si el simple retorno (0, 0) puede ocasionar algún problema, pero no se ha detectado ningún error por el momento.


No estoy seguro de si su problema es el mismo que el mío, pero descubrí que al acceder a la propiedad width o height de un Django ImageField normal leería el archivo del back-end de almacenamiento, lo cargaría en PIL y devolvería las dimensiones desde allí. Esto es especialmente costoso con un backend remoto como el que estamos usando, y tenemos páginas muy pesadas en medios.

Se abrió https://code.djangoproject.com/ticket/8307 para abordar esto, pero los desarrolladores de Django se cerraron como wontfix porque quieren que las propiedades de ancho y alto siempre devuelvan los valores verdaderos. Así que solo paneo par _get_image_dimensions () para usar esos campos, lo que evita una gran cantidad de mensajes del boto y mejora los tiempos de carga de mi página.

Debajo está mi código modificado del parche adjunto a ese boleto. Puse esto en un lugar que se ejecuta temprano, como un models.py.

from django.core.files.images import ImageFile, get_image_dimensions def _get_image_dimensions(self): from numbers import Number if not hasattr(self, ''_dimensions_cache''): close = self.closed if self.field.width_field and self.field.height_field: width = getattr(self.instance, self.field.width_field) height = getattr(self.instance, self.field.height_field) #check if the fields have proper values if isinstance(width, Number) and isinstance(height, Number): self._dimensions_cache = (width, height) else: self.open() self._dimensions_cache = get_image_dimensions(self, close=close) else: self.open() self._dimensions_cache = get_image_dimensions(self, close=close) return self._dimensions_cache ImageFile._get_image_dimensions = _get_image_dimensions