0

I am getting an internal server error for one of my view functions in Django that takes an image file and saves it to one of my models. The view function works in development, but is giving me an internal server error in production. I tried to wrap the part of the code that is failing in a try/except block, but the exception that it logs just says '__exit__' I'm not really sure what this means, or what kind of exception it is. I tried looking up what that exception would mean, but couldn't find anything. Does it have something to do with opening the file, and having issues closing it ? The exact part of the view function that breaks is where it says ...

if name == 'one':
                trade_in.photo_one = file

View

def edit_photos(request):
    trade_in = account_trade_in(request)
    if not trade_in:
        return HttpResponse(json.dumps({'error': 'Something went wrong, unable to edit photos'}), content_type='application/json')

    if request.method == 'POST':
        try:
            file = request.FILES['file']

            name = request.POST['photo']

            if name == 'one':
                trade_in.photo_one = file
            elif name == 'two':
                trade_in.photo_two = file
            elif name == 'three':
                trade_in.photo_three = file
            elif name == 'four':
                trade_in.photo_four = file
            elif name == 'five':
                trade_in.photo_five = file
            elif name == 'six':
                trade_in.photo_six = file

            trade_in.save()
        except Exception as e:
            logging.error(e)
            return HttpResponse(json.dumps({'error': e}), content_type='application/json')

    json_trade_in = json.dumps(trade_in.get_json())

    return HttpResponse(json_trade_in, content_type='application/json')

Model

class TradeInDetails(models.Model):

    account = models.OneToOneField(Account)
    photo_one = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})
    photo_two = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})
    photo_three = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})
    photo_four = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})
    photo_five = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})
    photo_six = StdImageField(upload_to=UploadToClassNameDirUUID(), blank=True, null=True,
                                     variations={'thumbnail': (120, 120, True)})

    lender = models.CharField(max_length=255, null=True, blank=True)
    amount_owed = models.CharField(max_length=255, null=True, blank=True)
    year = models.CharField(max_length=255, null=True, blank=True)
    mileage = models.CharField(max_length=255, null=True, blank=True)
    make = models.ForeignKey('vehicle.VehicleMake', null=True, blank=True)
    model = models.ForeignKey('vehicle.VehicleModel', null=True, blank=True)

    class Meta:
        verbose_name = 'Trade In Photos'
        verbose_name_plural = 'Trade In Photos'

Full Stack Trace

  Traceback (most recent call last):
  File "/home/socialauto/social-auto-web/account/ajax_views.py", line 553, in edit_photos
    trade_in.save()
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/base.py", line 708, in save
    force_update=force_update, update_fields=update_fields)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/base.py", line 736, in save_base
    updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/base.py", line 798, in _save_table
    for f in non_pks]
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/base.py", line 798, in <listcomp>
    for f in non_pks]
  File "/usr/local/lib/python3.4/dist-packages/django/db/models/fields/files.py", line 311, in pre_save
    file.save(file.name, file, save=False)
  File "/home/socialauto/social-auto-web/third_party/stdimage/models.py", line 48, in save
    self.render_variations()
  File "/home/socialauto/social-auto-web/third_party/stdimage/models.py", line 58, in render_variations
    self.render_variation(self.name, variation, replace, self.storage)
  File "/home/socialauto/social-auto-web/third_party/stdimage/models.py", line 76, in render_variation
    with Image.open(f) as img:
AttributeError: __exit__

Standard Image Model Method Throwing Error

@classmethod
    def render_variation(cls, file_name, variation, replace=False,
                         storage=default_storage):
        """Render an image variation and saves it to the storage."""
        variation_name = cls.get_variation_name(file_name, variation['name'])
        if storage.exists(variation_name):
            if replace:
                storage.delete(variation_name)
                logger.info('File "{}" already exists and has been replaced.')
            else:
                logger.info('File "{}" already exists.')
                return variation_name

        resample = variation['resample']

        with storage.open(file_name) as f:
            with Image.open(f) as img:
                save_kargs = {}
                file_format = img.format

                if cls.is_smaller(img, variation):
                    factor = 1
                    while img.size[0] / factor \
                            > 2 * variation['width'] \
                            and img.size[1] * 2 / factor \
                            > 2 * variation['height']:
                        factor *= 2
                    if factor > 1:
                        img.thumbnail(
                            (int(img.size[0] / factor),
                             int(img.size[1] / factor)),
                            resample=resample
                        )

                    size = variation['width'], variation['height']
                    size = tuple(int(i) if i != float('inf') else i
                                 for i in size)

                    if file_format == 'JPEG':
                        # http://stackoverflow.com/a/21669827
                        img = img.convert('RGB')
                        save_kargs['optimize'] = True
                        save_kargs['quality'] = 'web_high'
                        if size[0] * size[1] > 10000:  # roughly <10kb
                            save_kargs['progressive'] = True

                    if variation['crop']:
                        img = ImageOps.fit(
                            img,
                            size,
                            method=resample
                        )
                    else:
                        img.thumbnail(
                            size,
                            resample=resample
                        )

                with BytesIO() as file_buffer:
                    img.save(file_buffer, file_format, **save_kargs)
                    f = ContentFile(file_buffer.getvalue())
                    storage.save(variation_name, f)
        return variation_name
TJB
  • 3,706
  • 9
  • 51
  • 102
  • Show the last say 20 lines of the log. Seems like that would be relevant. Also, the JSON dump of the exception if you can. – Mad Physicist Jun 02 '17 at 17:44
  • 1
    `__exit__` is the special method that context managers invoke when a `with` block is done, so this is a bit strange. – Mad Physicist Jun 02 '17 at 17:46
  • 2
    Sounds like you might be trying to use something as a context manager that isn't a context manager, and it's giving you an `AttributeError` with message `__exit__` that just prints as `__exit__` when you print it. – user2357112 Jun 02 '17 at 18:12
  • @MadPhysicist I updated the question with the error in the log, its not much, but that's all there is unfortunately. – TJB Jun 02 '17 at 18:27
  • 2
    Incidentally, you should perform logging for exceptions with [`logging.exception`](https://stackoverflow.com/questions/5191830/best-way-to-log-a-python-exception), or pass the `exc_info=True` argument to `logging.error`, so you get the stack trace in the logs. `logging.error(e)` is a terrible way to log exceptions. – user2357112 Jun 02 '17 at 18:30
  • Hmmm, very interesting. Let me get the full stack trace, and update the question. – TJB Jun 02 '17 at 18:34
  • It looks like its an issue with one of my third party tools trying to open the image sent to it, when it is trying to create different versions of the image (Large, Small, Thumbnail, etc.) At this point, I think I might just use a normal Django image field instead of a standard image field. – TJB Jun 02 '17 at 18:43

0 Answers0