Django S3 ValueError : I/O operation on closed file

2020. 2. 27. 11:59Trouble Shooting

728x90

Django 에서 AWS S3 사용시 ValueError : I/O operation on closed file

라는 오류를 접하게 됐는데...

 

 

https://github.com/jschneier/django-storages/issues/382#issuecomment-377174808

 

S3Boto3Storage raises ValueError: I/O operation on closed file. · Issue #382 · jschneier/django-storages

When running python manage.py collectstatic we get the following exception: Traceback (most recent call last): File "manage.py", line 10, in execute_from_command_line(sys.a...

github.com

 

파일스토리지를 커스텀하여 적용하면 된다고 해서

from storages.backends.s3boto3 import S3Boto3Storage, SpooledTemporaryFile
import os


class CustomS3Boto3Storage(S3Boto3Storage):

    def _save_content(self, obj, content, parameters):
        """
        We create a clone of the content file as when this is passed to boto3 it wrongly closes
        the file upon upload where as the storage backend expects it to still be open
        """
        # Seek our content back to the start
        content.seek(0, os.SEEK_SET)

        # Create a temporary file that will write to disk after a specified size
        content_autoclose = SpooledTemporaryFile()

        # Write our original content into our copy that will be closed by boto3
        content_autoclose.write(content.read())

        # Upload the object which will auto close the content_autoclose instance
        super(CustomS3Boto3Storage, self)._save_content(obj, content_autoclose, parameters)

        # Cleanup if this is fixed upstream our duplicate should always close
        if not content_autoclose.closed:
            content_autoclose.close()

위 코드를 적용해도 안됩니다...

 

 

오류 내용을 잘 보시면 원인은 입출력 파일이 이미 닫혔는데 작업을 진행해서 생긴 Value Error 입니다.

저의 경우는 Form.save를 진행할때 발생합니다.

 


def save(self, commit=True):
	obj = super().save(commit=False)
  	try:
		obj.test = self.cleaned_data.get('test', '')
		obj.attach1 = self.cleaned_data.get('attach1', '')
    except IntegrityError:
		return obj
	if commit:
		obj.save()

위 처럼 commit이 False일때 첨부파일을 캐치하게될 경우

AWS S3에는 이미지가 이미 업로드 된 상태가되고, 메모리에 파일이 상주하게 됩니다.

그럼 추후 작업후 commit=True일 때 save가 들어오게 되면

S3에서는 이미 닫힌 파일이기 때문에 저장할 때 에러가 발생하게 되죠.

 

이런 경우는

 

commit을 진행할때 같이 저장하면 해결할 수 있습니다.

 


def save(self, commit=True):
	obj = super().save(commit=False)
  	try:
		obj.test = self.cleaned_data.get('test', '')
    except IntegrityError:
		return obj
	if commit:
		obj.attach1 = self.cleaned_data.get('attach1', '')
		obj.save()

 

728x90