7

ich ein Django-Projekt geerbt haben bis S3 und wir haben Bilder S3 bewegtDjango: Bildgröße ändern und laden

Eines der Modelle ist ein typisches Benutzerprofil

class Profile(UUIDBase): 

    first_name = models.CharField(_("First Name"), max_length=20) 
    last_name = models.CharField(_("Last Name"), max_length=20, null=True) 
    profile_image = models.ImageField(
     _("Profile Image"), 
     upload_to=profile_image_name, 
     max_length=254, 
     blank=True, 
     null=True 
    ) 
    profile_image_thumb = models.ImageField(
     _("Profile Image Thumbnail"), 
     upload_to=profile_image_name, 
     max_length=254, 
     blank=True, 
     null=True 
    ) 
    ... other fields 

Wo profile_image_name eine Funktion ist :

def profile_image_name(instance, filename): 
    if filename: 
     target_dir = 'uploads/profile_img/' 
     _, ext = filename.rsplit('.', 1) 
     filename = str(instance.uid) + '.' + ext 
     return '/'.join([target_dir, filename]) 

ich habe ein Stück Code, das funktioniert:

@shared_task 
def resize_image(image_path, dim_x, append_str='_resized', **kwargs): 
    ''' 
    resize any image_obj while maintaining aspect ratio 
    ''' 
    orig = storage.open(image_path, 'r') 
    im = Image.open(orig, mode='r') 
    new_y = (float(dim_x) * float(im.height))/float(im.width) 
    new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS) 
    img_path, img_name = path.split(image_path) 
    file_name, img_ext = img_name.rsplit('.', 1) 
    new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext) 
    try: 
     new_f = storage.open(new_img_path, 'w') 
    except IOError as e: 
     logger.critical("Caught IOError in {}, {}".format(__file__, e)) 
     ravenclient.captureException() 
     return None 
    try: 
     new_im.save(new_f) 
    except IOError as e: 
     logger.critical("Caught IOError in {}, {}".format(__file__, e)) 
     ravenclient.captureException() 
     return None 
    except Exception as e: 
     logger.critical("Caught unhandled exception in {}. {}".format(
     __file__, e) 
     ) 
     ravenclient.captureException() 
     return None 
    im.close() 
    new_im.close() 
    new_f.close() 
    return new_img_path 

, die aus einem post_save Signalbehandlungsroutine aufgerufen wird:

@receiver(post_save, sender=Profile, dispatch_uid='resize_profile_image') 
def resize_profile_image(sender, instance=None, created=False, **kwargs): 
    if created: 
     if instance.profile_image: 
      width, height = image_dimensions(instance.profile_image.name) 
      print(width, height) 
      if width > MAX_WIDTH: 
       result = resize_image.delay(instance.profile_image.name, MAX_WIDTH) 
       instance.profile_image.name = result.get() 
      if width > THUMB_WIDTH: 
       result = resize_image.delay(
        instance.profile_image.name, 
        THUMB_WIDTH, 
        append_str='_thumb' 
       ) 
       instance.profile_image_thumb.name = result.get() 
      try: 
       instance.save() 
      except Exception as e: 
       log.critical("Unhandled exception in {}, {}".format(__name__, e)) 
       ravenclient.captureException() 

Die Absicht ist, die hochgeladenen Bilder zu nehmen und sie 1) auf die maximale Breite verkleinern, dass ein Mobilgerät anzeigen kann, und 2) in einen 50-Pixel-Thumbnail für Verwenden Sie in der mobilen App.

Wenn ich auf S3 schaue, sehe ich meine skalierten Bilder oder Thumbnails nicht. Doch die Unit-Tests (die gründlich sind) geben keine Fehler.

Wenn ich die Bildgrößen:

def image_dimensions(image_path): 
    f = storage.open(image_path, 'r') 
    im = Image.open(f, 'r') 
    height = im.height 
    width = im.width 
    im.close() 
    f.close() 
    return (width, height) 

Es gibt kein Problem des Imagefield Objekt zugreifen. Ich bekomme keinen Fehler, wenn ich default_storage verwende, um das profile_image der Instanz zu öffnen. Die PIL-Methode

new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS) gibt eine neue Instanz der Klasse 'PIL.Image.Image' zurück.

In der Tat (verzeihen Sie meine Ausführlichkeit)

Dies ist ein Fehler nicht erhöhen:

>>> u = User(email="[email protected]", password="sdfbskjfskjfskjdf") 
>>> u.save() 
>>> p = Profile(user=u, profile_image=create_image_file()) 
>>> p.save() 
>>> from django.core.files.storage import default_storage as storage 
>>> orig = storage.open(p.profile_image.name, 'r') 
>>> orig 
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19.jpg> 
>>> im = Image.open(orig, mode='r') 
>>> im 
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=5000x5000 at 0x10B8F1FD0> 
>>> im.__class__ 
<class 'PIL.JpegImagePlugin.JpegImageFile'> 
>>> dim_x = 500 
>>> new_y = (float(dim_x) * float(im.height))/float(im.width) 
>>> new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS) 
>>> new_im.__class__ 
<class 'PIL.Image.Image'> 
>>> img_path, img_name = path.split(p.profile_image.name) 
>>> file_name, img_ext = img_name.rsplit('.', 1) 
>>> append_str='_resized' 
>>> new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext) 
>>> new_f = storage.open(new_img_path, 'w') 
>>> new_f 
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19_resized.jpg> 
>>> new_im.save(new_f) #### This does NOT create an S3 file!!!! 
>>> im.close() 
>>> new_im.close() 
>>> new_f.close() 

>>> p.save() lädt das neue Profil-Bild zu S3. Ich habe >>> new_im.save(new_f) erwartet, um die Image-Datei in S3 zu schreiben. Aber das tut es nicht.

Jeder Einblick oder Hilfe wird sehr geschätzt und danke, dass Sie sich die Zeit genommen haben, dieses Problem zu betrachten.

Bearbeiten ...

Meine Einstellungen:

AWS_STORAGE_BUCKET_NAME = 'testthis' 
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME 
MEDIAFILES_LOCATION = 'media' 
MEDIA_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, MEDIAFILES_LOCATION) 
DEFAULT_FILE_STORAGE = 'custom_storages.MediaStorage' 

Wo custom_storage.py ist

from django.conf import settings 
from storages.backends.s3boto import S3BotoStorage 

class MediaStorage(S3BotoStorage): 
    location = settings.MEDIAFILES_LOCATION 
    bucket_name = settings.AWS_STORAGE_BUCKET_NAME 
+0

haben ein neues Problem: Attribute: 'S3BotoStorageFile' Objekt hat kein Attribut 'starts' geändert: orig = default_storage.open (image_path, 'r') im = Image.open (orig) Jetzt bekomme ich den Fehler Task common.image_lib.resize_image [48340adf-f3aa-4227-ba24-1917d4e703ef] ausgelöst unerwartet: AttributeError ('' S3BotoStorageFile 'Objekt hat kein Attribut 'starts'“,) – fiacre

+0

ich den Code mit PNG-Dateien getestet, und es funktioniert: >>> new_im.save (new_f, 'PNG') Eigentlich eine neue Datei auf S3 erzeugt Aber das entsprechende funktioniert nicht mit JPEG! Könnte dies ein PIL-Fehler sein? – fiacre

Antwort

0

Das Problem PIL JPEG-Bibliothek verwandt zu sein scheint:

>>> u = User(email="[email protected]", password="sdfbskjfskjfskjdf") 
>>> u.save() 
>>> p = Profile(user=u, profile_image=create_image_file()) 
>>> p.save() 
>>> from django.core.files.storage import default_storage as storage 
>>> orig = storage.open(p.profile_image.name, 'r') 
>>> orig 
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19.png> 
>>> im = Image.open(orig, mode='r') 
>>> im.__class__ 
<class 'PIL.PngImagePlugin.PngImageFile'> 
>>> dim_x = 500 
>>> new_y = (float(dim_x) * float(im.height))/float(im.width) 
>>> new_im = im.resize((dim_x, int(new_y)), Image.ANTIALIAS) 
>>> new_im.__class__ 
<class 'PIL.Image.Image'> 
>>> img_path, img_name = path.split(p.profile_image.name) 
>>> file_name, img_ext = img_name.rsplit('.', 1) 
>>> append_str='_resized' 
>>> new_img_path = path.join(img_path, file_name + append_str + '.' + img_ext) 
>>> new_f = storage.open(new_img_path, 'w') 
>>> new_f 
<S3BotoStorageFile: uploads/profile_img/b0fd4f00-cce6-4dd3-b514-4c46a801ab19_resized.png> 
>>> new_im.save(new_f) #### This does create a file on S3! 
>>> im.close() 
>>> new_im.close() 
>>> new_f.close()