【问题标题】:Collectstatic and S3: not finding updated filesCollectstatic 和 S3:找不到更新的文件
【发布时间】:2013-08-27 02:36:49
【问题描述】:

我正在使用 Amazon S3 存储 Django 项目的静态文件,但 collectstatic 没有找到更新的文件 - 只有新的。

多年来,我一直在寻找答案,我的猜测是我的某些配置不正确。我关注了this blog post 来帮助完成所有设置。

我也遇到了this question,这似乎与我的问题相同,但我已经尝试了所有解决方案。

我什至尝试使用this question 中建议的this plugin

以下是一些可能有用的信息:

settings.py

...
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
...
# S3 Settings
AWS_STORAGE_BUCKET_NAME = os.environ['AWS_STORAGE_BUCKET_NAME']
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL
AWS_PRELOAD_METADATA = False

requirements.txt

...
Django==1.5.1
boto==2.10.0
django-storages==1.1.8
python-dateutil==2.1

编辑1:

如果这个问题对我自己的情况来说太独特而无法对广大观众有任何帮助,我深表歉意。尽管如此 - 这一直阻碍我的工作效率很长一段时间,我浪费了很多时间来寻找解决方案,所以我开始赏金奖励任何可以帮助解决这个问题的人。

编辑2:

我刚刚在某个地方遇到了类似的问题。我所在的时区与我的 AWS 存储桶的位置不同。如果默认情况下collectstatic 使用时间戳,这会干扰进程吗?

谢谢

【问题讨论】:

    标签: django amazon-web-services amazon-s3


    【解决方案1】:

    我想我解决了这个问题。和你一样,我在这个问题上花了很多时间。我也在您在 bitbucket 上找到的错误报告中。这是我刚刚完成的。

    我有

    django-storages==1.1.8
    Collectfast==0.1.11
    

    这根本不起作用。一次删除所有内容也不起作用。之后,它就无法接受修改并拒绝更新任何内容。

    问题在于我们的时区。 S3 会说它的文件最后一次修改晚于我们要上传的文件。 django collectstatic 根本不会尝试复制新的。它将调用文件“未修改”。例如,这是我在修复之前看到的:

    Collected static files in 0:00:45.292022.
    Skipped 407 already synced files.
    0 static files copied, 1 unmodified.
    

    我的解决方案是“修改时间!”。除了我们在这里解决的时区问题,如果我犯了错误需要回滚怎么办?它会拒绝部署旧的静态文件并让我的网站崩溃。

    这是我对 Collectfast https://github.com/FundedByMe/collectfast/pull/11 的拉取请求。我仍然留下了一个标志,所以如果你真的想检查修改时间,你仍然可以这样做。在合并之前,只需在https://github.com/sunshineo/collectfast使用我的代码

    你有一个美好的一天!

    --戈登 PS:为此熬夜到凌晨4:40。我的一天肯定被毁了。

    【讨论】:

    • 值得注意的是,这个功能最终登陆了collectfast。所以不需要用sunsionso的叉子。
    【解决方案2】:

    经过几个小时的挖掘,我找到了this bug report

    我更改了要求以恢复到以前版本的 Django 存储。

    django-storages==1.1.5
    

    【讨论】:

    • 1.1.5 也开始删除我的媒体文件。好在我在 dev 上测试它!
    【解决方案3】:

    您可能需要考虑使用 antonagestam 在 Github 上编写的这个插件: https://github.com/FundedByMe/collectfast

    它比较文件的校验和,这是确定文件何时更改的可靠方法。这是另一个 stackoverflow 问题的公认答案:Faster alternative to manage.py collectstatic (w/ s3boto storage backend) to sync static files to s3?

    【讨论】:

    • 这仍然不起作用。即使在使用它时,我也只能通过先在 S3 上手动删除来更新文件。从好的方面来说,这确实显着提高了速度,但这并不是什么大问题。
    • 嗯,也许您可​​能需要删除所有通过先前调用“collectstatic”收集的现有文件,然后使用这个新的collectstatic命令,以便根据它们新收集的所有文件md5 校验和。
    • 原因是当这个新的collectstatic命令将文件上传到S3时,它会计算并存储文件的md5校验和,以便稍后它可以将它与同一文件的新本地版本进行比较。如果文件是使用旧的 collectstatic 命令(不计算校验和)上传的,则新的 collectstatic 命令无法比较校验和,因为它无法计算已驻留在 S3 上的文件的校验和。
    • 您只需删除 S3 ONCE 上的内容,即可获取所有校验和。在后续的收藏中,您只需运行 collectstatic 命令,它就会上传更新的文件。
    • 对,你说的很有道理,它也应该这样工作。我一遍又一遍地删除了这些文件,并且在使用 1.1.8 版本时没有使用正确的校验和上传它们(或者我假设这是因为它不适用于此版本)。 v1.1.5 目前一切正常 - 我很乐意为您提供赏金,但我不想误导其他人遇到同样的问题。感谢您向我推荐该插件,它非常有用。
    【解决方案4】:

    这里有一些很好的答案,但我今天花了一些时间在这上面,所以我想我会再贡献一个,以防将来对某人有所帮助。根据在其他线程中找到的建议,我确认,对我来说,这确实是由时区差异引起的。我的 django 时间不正确,但设置为 EST,S3 设置为 GMT。在测试中,我恢复到 django-storages 1.1.5,它似乎确实让 collectstatic 工作。部分由于个人喜好,我不愿意 a) 回滚 django-storages 的三个版本并丢失任何潜在的错误修复或 b) 更改我的项目组件的时区,因为这基本上归结为一个便利功能(尽管很重要一)。

    我编写了一个简短的脚本来完成与 collectstatic 相同的工作,而无需进行上述更改。它需要对您的应用程序进行一些修改,但如果将其放置在应用程序级别并且将“static_dirs”替换为项目应用程序的名称,则它应该适用于标准情况。它通过终端运行,带有 'python whatever_you_call_it.py -e environment_name(将其设置为您的 aws 存储桶)。

    import sys, os, subprocess
    import boto3
    import botocore
    from boto3.session import Session
    import argparse
    import os.path, time
    from datetime import datetime, timedelta
    import pytz
    
    utc = pytz.UTC
    DEV_BUCKET_NAME = 'dev-homfield-media-root'
    PROD_BUCKET_NAME = 'homfield-media-root'
    static_dirs = ['accounts', 'messaging', 'payments', 'search', 'sitewide']
    
    def main():
        try: 
            parser = argparse.ArgumentParser(description='Homfield Collectstatic. Our version of collectstatic to fix django-storages bug.\n')
            parser.add_argument('-e', '--environment', type=str, required=True, help='Name of environment (dev/prod)')
            args = parser.parse_args()
            vargs = vars(args)
            if vargs['environment'] == 'dev':
                selected_bucket = DEV_BUCKET_NAME
                print "\nAre you sure? You're about to push to the DEV bucket. (Y/n)"
            elif vargs['environment'] == 'prod':
                selected_bucket = PROD_BUCKET_NAME
                print "Are you sure? You're about to push to the PROD bucket. (Y/n)"
            else:
                raise ValueError
    
            acceptable = ['Y', 'y', 'N', 'n']
            confirmation = raw_input().strip()
            while confirmation not in acceptable:
                print "That's an invalid response. (Y/n)"
                confirmation = raw_input().strip()
    
            if confirmation == 'Y' or confirmation == 'y':
                run(selected_bucket)
            else:
                print "Collectstatic aborted."
        except Exception as e:
            print type(e)
            print "An error occured. S3 staticfiles may not have been updated."
    
    
    def run(bucket_name):
    
        #open session with S3
        session = Session(aws_access_key_id='{aws_access_key_id}',
            aws_secret_access_key='{aws_secret_access_key}',
            region_name='us-east-1')
        s3 = session.resource('s3')
        bucket = s3.Bucket(bucket_name)
    
        # loop through static directories
        for directory in static_dirs:
            rootDir = './' + directory + "/static"
            print('Checking directory: %s' % rootDir)
    
            #loop through subdirectories
            for dirName, subdirList, fileList in os.walk(rootDir):
                #loop through all files in subdirectory
                for fname in fileList:
                    try:
                        if fname == '.DS_Store':
                            continue
    
                        # find and qualify file last modified time
                        full_path = dirName + "/" + fname
                        last_mod_string = time.ctime(os.path.getmtime(full_path))
                        file_last_mod = datetime.strptime(last_mod_string, "%a %b %d %H:%M:%S %Y") + timedelta(hours=5)
                        file_last_mod = utc.localize(file_last_mod)
    
                        # truncate path for S3 loop and find object, delete and update if it has been updates
                        s3_path = full_path[full_path.find('static'):]
                        found = False
                        for key in bucket.objects.all():
                            if key.key == s3_path:
                                found = True 
                                last_mode_date = key.last_modified
                                if last_mode_date < file_last_mod:
                                    key.delete()
                                    s3.Object(bucket_name, s3_path).put(Body=open(full_path, 'r'), ContentType=get_mime_type(full_path))
                                    print "\tUpdated : " + full_path
                        if not found:
                            # if file not found in S3 it is new, send it up
                            print "\tFound a new file. Uploading : " + full_path
                            s3.Object(bucket_name, s3_path).put(Body=open(full_path, 'r'), ContentType=get_mime_type(full_path))
                    except:
                        print "ALERT: Big time problems with: " + full_path + ". I'm bowin' out dawg, this shitz on u." 
    
    
    def get_mime_type(full_path):
        try:
            last_index = full_path.rfind('.')
            if last_index < 0:
                return 'application/octet-stream'
            extension = full_path[last_index:]
            return {
                '.js' : 'application/javascript',
                '.css' : 'text/css',
                '.txt' : 'text/plain',
                '.png' : 'image/png',
                '.jpg' : 'image/jpeg',
                '.jpeg' : 'image/jpeg',
                '.eot' : 'application/vnd.ms-fontobject',
                '.svg' : 'image/svg+xml',
                '.ttf' : 'application/octet-stream',
                '.woff' : 'application/x-font-woff',
                '.woff2' : 'application/octet-stream'
            }[extension]
        except:
            'ALERT: Couldn\'t match mime type for '+ full_path + '. Sending to S3 as application/octet-stream.'
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

      【解决方案5】:

      我在将新文件推送到 S3 存储桶时遇到了类似的问题(以前运行良好),但 django 或 python 没有问题,最后我在删除本地存储库并再次克隆它时解决了这个问题。

      【讨论】:

        猜你喜欢
        • 2012-08-02
        • 2018-09-19
        • 1970-01-01
        • 2021-11-07
        • 2015-07-21
        • 2018-04-24
        • 2015-01-02
        • 1970-01-01
        • 2021-05-03
        相关资源
        最近更新 更多