Django-storages 未检测到更改的静态文件

Posted

技术标签:

【中文标题】Django-storages 未检测到更改的静态文件【英文标题】:Django-storages not detecting changed static files 【发布时间】:2013-07-04 16:13:27 【问题描述】:

我将 django-storages 和 amazon s3 用于我的静态文件。按照文档,我将这些设置放在我的 settings.py 中

STATIC_URL = 'https://mybucket.s3.amazonaws.com/'

ADMIN_MEDIA_PREFIX = 'https://mybucket.s3.amazonaws.com/admin/'

INSTALLED_APPS += (
    'storages',
)

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = 'mybucket_key_id'
AWS_SECRET_ACCESS_KEY = 'mybucket_access_key'
AWS_STORAGE_BUCKET_NAME = 'mybucket'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

我第一次运行 collect static 时一切正常,我的静态文件已上传到我的 s3 存储桶。

但是,在对我的静态文件进行更改并运行 python manage.py collectstatic 之后,尽管静态文件已被修改,但仍会输出此内容

-----> Collecting static files
    0 static files copied, 81 unmodified.

但是,如果我重命名更改后的静态文件,更改后的静态文件会正确复制到我的 s3 存储桶中。

为什么 django-storages 不上传我更改的静态文件?是配置问题还是问题更深?

【问题讨论】:

【参考方案1】:

如果“目标”文件比源文件“年轻”,collectstatic 会跳过文件。似乎亚马逊 S3 存储为您的文件返回了错误的日期。

您可以调查 [code][1] 并调试服务器响应。可能时区有问题。

或者您可以将 --clear 参数传递给 collectstatic,以便在收集之前在 S3 上删除所有文件

【讨论】:

感谢这工作。我会等着看是否有人为我的问题发布了一个确切的解决方案,但如果没有,你可以得到 +50 :) --clear 似乎不适用于我的 s3。但是,如果我从 s3 手动删除文件,它们都会被重新复制。【参考方案2】:

https://github.com/antonagestam/collectfast

来自 readme.txt :比较来自 S3 的 MD5 sum 和 etag 的自定义管理命令,如果两者相同,则跳过文件复制。这使得运行 collect static 更快 如果您使用 git 作为更新时间戳的源代码控制系统。

【讨论】:

【参考方案3】:

collectstatic 同步创建一个设置文件,使用以下配置:

TIME_ZONE = 'UTC'

使用此行使用特定设置运行 collectstatic:

python manage.py collectstatic --settings=settings.collectstatic

【讨论】:

【参考方案4】:

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

我编写了一个简短的脚本来完成与 collectstatic 相同的工作,而无需进行上述更改。它需要对您的应用程序进行一些修改,但如果将其放置在应用程序级别并且将“static_dirs”替换为项目应用程序的名称,则它应该适用于标准情况。它通过终端运行 'pythonwhatever_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()

【讨论】:

代码中的注释至少可以说是有帮助的..

以上是关于Django-storages 未检测到更改的静态文件的主要内容,如果未能解决你的问题,请参考以下文章

django-storages + sorl_thumbnail + S3 不能很好地协同工作(URL 不匹配)

SegmentedControl 未检测到更改

Django 迁移未检测到所有更改

MobileFirst Eclipse 未检测到更改

makemigrations 显示未检测到更改

Django迁移更改目录结构后未检测到更改