2011-05-04 14 views
21

Estoy intentando hacer 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.Almacenamiento de imágenes y miniaturas en s3 en django

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) + Sorl Thumbnail: Suggestions for optimisation

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

El problema es que la página que muestra la imagen sigue siendo 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: débil truco parece haber conseguido que funcione, pero me gustaría saber cómo hacer esto correctamente:

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

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

estoy trabajando con 2 puntos de vista:

Añadir vista: en este punto de vista me envíe el formulario para crear el modelo con la imagen en ella. La imagen se carga en s3.En una señal de post_save, llamo get_thumbnail() para generar la miniatura antes de que sea necesario:

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

visualización de la vista: En este punto de vista puedo mostrar la miniatura generada en la vista de complemento:

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

Sin la patch:

Añadir vista: 3 crea entradas en la tabla kvstore, accede a la caché de 10 veces (6 juegos, 4 Gets), pestaña de la barra de herramientas de depuración de registro dice que "el establecimiento de conexión HTTP" 12 veces

visualización de la vista: aún sólo 3 entradas en la tabla kvstore, a 1 obtenemos de caché, pero la barra de herramientas de depuración dice "el establecimiento de conexión HTTP" 3 veces aún

con sólo el cambio en la línea 122:

Añadir vista : igual que el anterior, excepto el registro sólo dice "el establecimiento de conexión HTTP" 2 veces visualización de la vista: igual que el anterior, excepto el registro sólo dice "el establecimiento de conexión HTTP" 1 vez

también añadiendo el cambio en la línea 118:

AGREGAR VER: igual que arriba, pero ahora estamos hasta 2 "de establecer una conexión HTTP" mensajes visualización de la vista: igual que el anterior, sin mensajes de registro en absoluto

ACTUALIZACIÓN: Parece que storage._setup() se llama dos veces, y storage.url() es llamado una vez. Basado en el tiempo, yo diría que cada uno hace que las conexiones a s3:

1304711315.4 
_setup 
1304711317.84 
1304711317.84 
_setup 
1304711320.3 
1304711320.39 
_url 
1304711323.66 

Esto parece reflejarse por la tala de boto, que dice: "el establecimiento de conexión HTTP" 3 veces.

+1

Tengo el mismo problema, por favor mantenganme actualizado –

+0

¿Alguna actualización sobre esto? Además, ¿qué estás usando como tu S3_UPLOAD_URL en ese parche? – shadfc

+0

Sé que es bastante viejo, pero estoy experimentando la misma lentitud, solo curiosidad si hay una actualización para esto? –

Respuesta

7

Como el autor de sorl thumbnail estoy realmente interesado en resolver esto si no está funcionando 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 de realizar. 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 tener THUMBNAIL_DEBUG activado y de que tiene el almacén de valores clave configurado correctamente.

+0

Gracias por su respuesta y la gran pieza de software. Parecía haber 2 series de llamadas de almacenamiento, cada una de las cuales tomaba aproximadamente 2 segundos (mi servidor de desarrollo está lejos del centro de datos s3). Cada una de esas líneas que agregué aborda una de esas series de llamadas. Voy a analizar esto un poco más de cerca y comentar de nuevo. – asciitaxi

+0

He actualizado la pregunta con información. – asciitaxi

2

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

https://code.djangoproject.com/ticket/8307 se abrió para tratar esto, pero los desarrolladores de Django se cerraron como un arreglo no deseado 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.

A continuación se muestra mi código modificado a partir del parche adjunto a ese ticket. 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 
+0

Hola, ¿qué es 'get_image_dimensions' (sin el subrayado inicial)? –

+1

Esa es una función en django.core.files.images. https://github.com/django/django/blob/86f4459f9e3c035ec96578617605e93234bf2700/django/core/files/images.py#L32 – shadfc

0

Después de mirar el billete @shadfc Django, me Reimplementado la monkeypatch 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, basta con añadir una IGNORE_IMAGE_DIMENSIONS = True a su clase de almacenamiento y no serán tocados para obtener dimensiones de la imagen. Probable:

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

todavía tengo que investigar dónde se utilizan los números, para saber si sencilla regresar (0, 0) puede dar lugar a ningún problema, pero sin fallo criado por ahora.

+0

Por cierto, este problema ataca también a las miniaturas. – alanjds

Cuestiones relacionadas