Django collectstatic 不适用于 S3 的生产,但相同的设置在本地有效

Django collectstatic not working on production with S3, but same settings work locally

我一直在移动一些设置以创建更明确的本地和生产环境,我一定是搞砸了。

以下是大部分相关设置。如果我将 production.py 设置(目前只包含与 AWS 相关的设置)移动到 base.py,我可以从我的本地机器更新 S3 就好了。同样,如果我将这些 AWS 设置保留在 base.py 中并推送到生产环境,S3 会相应更新。此外,如果我从 production.py 打印某些内容,它会打印出来。但是,如果我在 manage.py 上进行 production.py 我的 "local" 设置,或者当我使用如下所示的设置推送到 Heroku 时,S3 不会更新。

我的设置不正确怎么办? (好吧,我确定了一些事情,但特别是导致 S3 不更新?)

下面是一些相关代码:

__init__.py(在有base、local、production的目录下)

from cobev.settings.base import *

base.py

INSTALLED_APPS = [
    ...
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',
    ...
    'storages',
]

...

STATIC_URL = '/static/'

STATICFILES_DIRS = [os.path.join(BASE_DIR, "global_static"),
                    os.path.join(BASE_DIR, "media", )
                    ]

MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'

local.py

# local_settings.py
from .base import *

...

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

production.py

from .base import *

# AWS Settings

AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = 'cobev'

AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'

AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
DEFAULT_FILE_STORAGE = 'cobev.storage_backends.MediaStorage'
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)

ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'

# End AWS

wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cobev.settings.production")

application = get_wsgi_application()

from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)

manage.py

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cobev.settings.local") 
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)

好的,让我试试,正如问题评论中发现的那样,您使用 collectstatic 进行 S3 更新,但这是一个管理命令,使用 manage.py 文件调用,您在其中设置 cobev.settings.local 作为不等于用于 wsgi.py 文件的 cobev.settings.production 的设置。

我认为您应该使用正常的 Django 方式管理您的设置文件,OS 名为 DJANGO_SETTINGS_MODULE 的环境变量。

当然,您应该能够在您所在的任何生产环境中设置它 运行。

那么如果这对我有帮助的话,这是我在生产环境中对 AWS/Django/S3 的配置:

常用静态配置:

# STATIC FILE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
STATIC_ROOT = str(ROOT_DIR('staticfiles'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = '/static/'

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = [
    str(APPS_DIR.path('static'))
]

# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder'
]

通用媒体配置:

# MEDIA CONFIGURATION
# ------------------------------------------------------------------------------

# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
MEDIA_ROOT = str(APPS_DIR('media'))

# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = '/media/'

生产静态配置:

# STATIC CONFIG PRODUCTION
# ------------------------------------------------------------------------------
# See: http://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html

AWS_STORAGE_BUCKET_NAME = 'mybucket-name-production'
AWS_ACCESS_KEY_ID = 'YOUR_KEY_ID'
AWS_SECRET_ACCESS_KEY = 'YOUR_SECRET_KEY'
AWS_S3_HOST = "s3.amazonaws.com"
AWS_S3_URL = 'https://{bucker_name}.s3.amazonaws.com/'.format(bucker_name=AWS_STORAGE_BUCKET_NAME)

AWS_LOCATION = 'static/'

AWS_S3_URL_PROTOCOL = 'https:'
AWS_S3_CUSTOM_DOMAIN = 'static.mydomain.com' # I use sub domaine to serve static 

STATIC_URL = '{AWS_S3_URL_PROTOCOL}//{AWS_S3_CUSTOM_DOMAIN}/{AWS_LOCATION}'.format(
    AWS_S3_URL_PROTOCOL=AWS_S3_URL_PROTOCOL,
    AWS_S3_CUSTOM_DOMAIN=AWS_S3_CUSTOM_DOMAIN,
    AWS_LOCATION=AWS_LOCATION)

AWS_QUERYSTRING_AUTH = False

AWS_IS_GZIPPED = True
AWS_EXPIREY = 60 * 60 * 24 * 14

# For s3boto
AWS_HEADERS = {
    'Cache-Control': 'max-age=%d, s-maxage=%d, must-revalidate' % (AWS_EXPIREY, AWS_EXPIREY)
}

# For s3boto3
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=%d' % AWS_EXPIREY,
}

AWS_PRELOAD_METADATA = True
#AWS_S3_FILE_OVERWRITE = True

STATICFILES_STORAGE = 'config.storages.StaticStorage'
DEFAULT_FILE_STORAGE = 'config.storages.DefaultStorage'



# MEDIA S3 CONFIG PRODUCTION
# --------------------------------------------------------------------------------

AWS_MEDIA_DIR = 'media'
MEDIA_URL = AWS_S3_URL + AWS_MEDIA_DIR + '/'
MEDIA_ROOT = MEDIA_URL

这是我的 StaticStorage Class :

from storages.backends.s3boto3 import S3Boto3Storage


class StaticStorage(S3Boto3Storage):
    location = 'static'
    file_overwrite = False


class DefaultStorage(S3Boto3Storage):
    location = ''
    file_overwrite = False

之后,我在 .config 文件的 .ebextensions 文件夹中为 collectstatic 添加了命令:

# ./ebextensions/02_container_commands.config file : 

container_commands:
  0.3.0.push.static.to.s3:
    command: "source /opt/python/run/venv/bin/activate && python manage.py collectstatic --ignore=.scss --noinput"
    leader_only: true
    ignoreErrors: true

您似乎在使用 Whitenoise。 Whitenoise 允许 django 为其静态文件提供服务。如果您想从 AWS 为它们提供服务,这是不同的方法。

因此,您需要删除 Whitenoise 才能使用 django-storages。从设置、中间件、wsgi.py 等中删除它

此外,您可以在设置中删除 __init__.py 中的所有内容 - 要使用的设置文件由 DJANGO_SETTINGS_MODULE env 变量设置。


根据您的 STATICFILES_DIRSmedia 目录包含为静态文件。最好将媒体与静态文件分开提供(差异之一 - 静态文件更有可能被缓存和 gzip 压缩) - 即也使用 AWS,但来自单独的 S3 存储桶。

您也可以稍后在您的存储桶前面添加 AWS CloudFront 作为 CDN。