【问题标题】:Attribute Error when running collectstatic for Django app为 Django 应用程序运行 collectstatic 时出现属性错误
【发布时间】:2012-02-09 04:47:06
【问题描述】:

我在运行 collectstatic 时收到以下错误:

AttributeError: 'cStringIO.StringO' object has no attribute 'name'

在我尝试使用存储“AWS_IS_GZIPPED”设置对文件进行 gzip 压缩之前,一切正常(请参阅下面的 settings.py)。

我正在使用 django-storages,它利用 boto 将我的静态文件发送到 S3 和 django-compressor 来压缩它们。

这是我的错误的完整追溯:

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-compressor docs

我的 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'

任何帮助将不胜感激。有点迷失在树林里。

【问题讨论】:

    标签: django gzip boto django-compressor django-storage


    【解决方案1】:

    https://github.com/jezdez/django_compressor/issues/100 有一个建议的解决方法。

    【讨论】:

      【解决方案2】:

      我这样解决了这个问题:

      问题是使用相同的[参数content]保存本地并上传到S3。因为当我们把参数内容传给super(CachedS3BotoStorage, self).save(name, content)的时候,内部参数content被修改了,所以传给next.save的时候是_self.local_storage. save(name, content) 由于 conf AWS_IS_GZIPPED,他处于其他状态,压缩 content 中的文件。 要解决此问题,只需创建一份内容参数的副本。

      在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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-29
        • 1970-01-01
        • 2018-09-09
        • 2021-05-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-14
        • 2018-08-26
        相关资源
        最近更新 更多