使用 Amazon S3 的 Django

Django using Amazon S3

因此,每当我 运行 创建以下静态文件文件夹时,我无法将静态收集到我的 AWS S3 存储桶中。

(portfolio) PS C:\Users\arund\Desktop\Code\Django\portfolio-project> python manage.py collectstatic
Found another file with the destination path 'user\main.css'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure every static file has a unique path.

settings.py

"""
Django settings for portfolio project.

Generated by 'django-admin startproject' using Django 3.2.9.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
import os

SECRET_KEY = os.getenv("SECRET_KEY", default="dev key")
# SECURITY WARNING: don't run with debug turned on in production!
#DEBUG = True

DEBUG = os.environ.get('DJANGO_DEBUG', '') 

ALLOWED_HOSTS = ["url.com"]


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'pages.apps.PagesConfig',
    'storages',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django_session_timeout.middleware.SessionTimeoutMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'portfolio.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'portfolio.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

import dj_database_url
db_from_env = dj_database_url.config(conn_max_age=600)
DATABASES['default'].update(db_from_env)

# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
# All of this is in my console.aws.amazon to configure aws s3 static files only
# IAM Management Console
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID', '') 
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY', '') 
# Amazon S3 Buckets
AWS_STORAGE_BUCKET_NAME =  os.environ.get('AWS_STORAGE_BUCKET_NAME', '') 
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'pages/static'),
]
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
# STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'


# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_ENGINE = (
'django.contrib.sessions.backends.cache'
)
SESSION_COOKIE_AGE = 10  # change expired session
SESSION_IDLE_TIMEOUT = 10  # logout

SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_SAVE_EVERY_REQUEST = True
SESSION_TIMEOUT_REDIRECT = '/accounts/login/' 

import django_heroku
django_heroku.settings(locals())

它会像这样创建另一个文件夹

尝试了 django_heroku.settings(locals(), staticfiles=False)

(portfolio) PS C:\Users\arund\Desktop\Code\Django\portfolio-project> git push heroku master
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 400 bytes | 200.00 KiB/s, done.
Total 4 (delta 3), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Building on the Heroku-20 stack
remote: -----> Using buildpack: heroku/python
remote: -----> Python app detected
remote: -----> Using Python version specified in runtime.txt
remote:  !     Python has released a security update! Please consider upgrading to python-3.9.9
remote:        Learn More: https://devcenter.heroku.com/articles/python-runtimes
remote: -----> Using cached install of python-3.9.6
remote: -----> Installing pip 21.3.1, setuptools 57.5.0 and wheel 0.37.0
remote: -----> Installing SQLite3
remote: -----> Installing requirements with pip
remote: -----> $ python manage.py collectstatic --noinput
remote:        Found another file with the destination path 'user/main.css'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure every static file has a unique path.
remote:        129 static files copied.
remote:
remote: -----> Discovering process types
remote:        Procfile declares types -> release, web
remote:
remote: -----> Compressing...
remote:        Done: 68.7M
remote: -----> Launching...
remote:  !     Release command declared: this new release will not be available until the command succeeds.
remote:        Released v169
remote:        https://url.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
remote: Running release command...
remote:
remote: Operations to perform:
remote:   Apply all migrations: admin, auth, contenttypes, sessions
remote: Running migrations:
remote:   No migrations to apply.
To ------
   74524a2..f5e5fe8  master -> master
(portfolio) PS C:\Users\arund\Desktop\Code\Django\portfolio-project> python manage.py collectstatic

You have requested to collect static files at the destination
location as specified in your settings.

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes
Traceback (most recent call last):
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\manage.py", line 22, in <module>
    main()
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\core\management\__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\core\management\__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\core\management\base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\core\management\base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 187, in handle
    collected = self.collect()
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 114, in collect
    handler(path, prefixed_path, storage)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 338, in copy_file
    if not self.delete_file(path, prefixed_path, source_storage):
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\django\contrib\staticfiles\management\commands\collectstatic.py", line 248, in delete_file
    if self.storage.exists(prefixed_path):
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\storages\backends\s3boto3.py", line 469, in exists
    self.connection.meta.client.head_object(Bucket=self.bucket_name, Key=name)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\client.py", line 391, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\client.py", line 691, in _make_api_call
    request_dict = self._convert_to_request_dict(
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\client.py", line 737, in _convert_to_request_dict
    api_params = self._emit_api_params(
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\client.py", line 766, in _emit_api_params
    self.meta.events.emit(
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\hooks.py", line 357, in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\hooks.py", line 228, in emit
    return self._emit(event_name, kwargs)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\hooks.py", line 211, in _emit
    response = handler(**kwargs)
  File "C:\Users\arund\Desktop\Code\Django\portfolio-project\venv\lib\site-packages\botocore\handlers.py", line 243, in validate_bucket_name
    raise ParamValidationError(report=error_msg)
botocore.exceptions.ParamValidationError: Parameter validation failed:
Invalid bucket name "": Bucket name must match the regex "^[a-zA-Z0-9.\-_]{1,255}$" or be an ARN matching the regex "^arn:(aws).*:(s3|s3-object-lambda):[a-z\-0-9]*:[0-9]{12}:accesspoint[/:][a-zA-Z0-9\-.]{1,63}$|^arn:(aws).*:s3-outposts:[a-z\-0-9]+:[0-9]{12}:outpost[/:][a-zA-Z0-9\-]{1,63}[/:]accesspoint[/:][a-zA-Z0-9\-]{1,63}$"

你的问题在 django-heroku 包中。

Django-heroku 会覆盖您的静态文件设置,您可以在 source code here.

中看到

要禁用此功能,请将 django_heroku.settings(locals()) 更改为 django_heroku.settings(locals(), staticfiles=False)

这将保留您自己的静态文件设置。