Ошибка атрибута при запуске collectstatic для приложения Django
Я получаю следующую ошибку при запуске collectstatic:
AttributeError: 'cStringIO.StringO' object has no attribute 'name'
Все работает нормально, пока я не попытаюсь сжать файлы, используя настройку хранилища "AWS_IS_GZIPPED" (см. Мой settings.py ниже).
Я использую django-хранилища, которые используют boto для отправки моих статических файлов на S3 и django-compress для их сжатия.
Вот полный след моей ошибки:
Copying '/home/somewhere/current/something/shows/static/skin/jplayer.band.css'
Traceback (most recent call last):
File "./manage.py", line 14, in <module>
execute_manager(settings)
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/management/base.py", line 351, in handle
return self.handle_noargs(**options)
File "/home/somewhere/env/lib/python2.6/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 89, in handle_noargs
self.copy_file(path, prefixed_path, storage, **options)
File "/home/somewhere/env/lib/python2.6/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 202, in copy_file
self.storage.save(prefixed_path, source_file)
File "/home/somewhere/current/something/storage.py", line 28, in save
self.local_storage._save(filename, content)
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/files/storage.py", line 190, in _save
for chunk in content.chunks():
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/files/base.py", line 65, in chunks
counter = self.size
File "/home/somewhere/env/lib/python2.6/site-packages/django/core/files/base.py", line 39, in _get_size
elif os.path.exists(self.file.name):
AttributeError: 'cStringIO.StringO' object has no attribute 'name'
Вот мой storage.py
class CachedS3BotoStorage(S3BotoStorage):
def __init__(self, *args, **kwargs):
super(CachedS3BotoStorage, self).__init__(*args, **kwargs)
self.local_storage = get_storage_class('compressor.storage.CompressorFileStorage')()
def save(self, filename, content):
filename = super(CachedS3BotoStorage, self).save(filename, content)
self.local_storage._save(filename, content)
return filename
который идет прямо из документации Django-компрессора.
У меня также есть следующее в моей settings.py
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = 'something'
AWS_SECRET_ACCESS_KEY = 'something_else'
AWS_STORAGE_BUCKET_NAME = 'something'
AWS_S3_CUSTOM_DOMAIN = 'static.example.com' #without this compressor points to my s3 bucket, I serve from CloudFront
AWS_IS_GZIPPED = True #If this is false, everything works, but no gzipping!
AWS_S3_SECURE_URLS = False #turns off https for static files (necessary)
import datetime
future = datetime.datetime.now() #+ datetime.timedelta(days=364)
AWS_HEADERS = {
'Expires': future.strftime('%a, %d %b %Y %H:%M:%S GMT'),
'Cache-Control': 'max-age=60, public' #'max-age=31536000, public'
}
STATICFILES_STORAGE = 'something.storage.CachedS3BotoStorage'
from S3 import CallingFormat
AWS_CALLING_FORMAT = CallingFormat.SUBDOMAIN
COMPRESS_ENABLED = True #can remove when ready for production
COMPRESS_OFFLINE = True
COMPRESS_URL = 'http://static.example.com/'
COMPRESS_STORAGE = 'something.storage.GzipCompressorStorage'
COMPRESS_OUTPUT_DIR = 'compressed_static'
COMPRESS_ROOT = '/home/somewhere/static'
Любая помощь приветствуется. Немного заблудился в лесу.
2 ответа
https://github.com/jezdez/django_compressor/issues/100 предлагает предложенное решение.
Я исправил эту проблему следующим образом:
Проблема заключается в том, чтобы использовать тот же [параметр содержимого], чтобы сохранить локальный и загрузить на S3. Потому что, когда мы передаем содержимое параметра в super(CachedS3BotoStorage, self).save(имя, содержимое), внутренне содержимое параметра изменяется, поэтому при передаче следующему.save _self.local_storage.сохранить (имя, содержимое) он с другим состоянием из-за conf AWS_IS_GZIPPED, который сжимает файл внутри содержимого. Чтобы это исправить, просто создайте одну копию параметра содержимого.
В settings.py
STATICFILES_STORAGE = 'mypackage.s3utils.CachedS3BotoStorage'
в mypackage.s3utils.py
from storages.backends.s3boto import S3BotoStorage
from compressor.storage import CompressorFileStorage
from django.core.files.storage import get_storage_class
import copy
class CachedS3BotoStorage(S3BotoStorage):
"""
S3 storage backend that saves the files locally, too.
"""
location = 'static'
def __init__(self, *args, **kwargs):
super(CachedS3BotoStorage, self).__init__(*args, **kwargs)
self.local_storage = get_storage_class(
"compressor.storage.CompressorFileStorage")()
def url(self, name):
"""
Fix the problem of dont show the natives images django admin
"""
url = super(CachedS3BotoStorage, self).url(name)
if name.endswith('/') and not url.endswith('/'):
url += '/'
return url
def save(self, name, content):
content2 = copy.copy(content) #-> THE SECRET IS HERE
name = super(CachedS3BotoStorage, self).save(name, content)
self.local_storage._save(name, content2) #-> AND HERE
# print id(content)
# print id(content2)
return name
def get_available_name(self, name):
if self.exists(name):
self.delete(name)
return name