0

我正在阅读 William S. Vincent 的Django for Professionals书,我尝试将 django 应用程序部署到 heroku,但在部署此应用程序时静态文件夹位置失败,我使用Dockerwhitenoise包来处理静态文件,这里有重要信息在文件中。settings.py import dj_database_url import socket from pathlib import Path import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Este cambio es para el despliegue en heroku, ya que hay problemas con los archivos estáticos
# para más información vea: https://devcenter.heroku.com/articles/django-assets
#BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# El entorno, producción vs desarrollo
ENVIRONMENT = os.environ.get('ENVIRONMENT', default='production')

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

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
# por defecto 0, ya que el proyecto estará pronto en producción
DEBUG = int(os.environ.get('DEBUG', default=0))

ALLOWED_HOSTS = ['aplicacion-de-ventas.herokuapp.com',
                 'localhost', '127.0.0.1']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'whitenoise.runserver_nostatic',
    'django.contrib.staticfiles',
    'django.contrib.sites',

    # 3rd party
    'crispy_forms',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.github',
    'allauth.socialaccount.providers.google',
    'debug_toolbar',

    # local apps
    'pages.apps.PagesConfig',
    'ventas.apps.VentasConfig',
    'perfiles.apps.PerfilesConfig',
]

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

# Configuración de CACHE
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 604800
CACHE_MIDDLEWARE_KEY_PREFIX = ''

ROOT_URLCONF = 'clothes_shop_project.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 = 'clothes_shop_project.wsgi.application'


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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.1/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.1/topics/i18n/

LANGUAGE_CODE = 'es'

TIME_ZONE = 'America/Lima'

USE_I18N = True

USE_L10N = True

# si esto permanece en False considera correctamente el tiempo de America/Lima
# si esto está en True considera el timezone en UTC
USE_TZ = False

# django crispy_forms
CRISPY_TEMPLATE_PACK = 'bootstrap4'

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_FINDERS = [
    "django.contrib.staticfiles.finders.FileSystemFinder",
    "django.contrib.staticfiles.finders.AppDirectoriesFinder",
]


# redirections when a user login or logout of our app
LOGIN_REDIRECT_URL = "pages:bienvenida"
LOGOUT_REDIRECT_URL = "pages:bienvenida"

# configuraciones para enviar correos electrónicos de cambio de contraseña
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL')
EMAIL_HOST = os.environ.get('EMAIL_HOST')
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = (
    os.environ.get('EMAIL_HOST_PASSWORD')
)
EMAIL_PORT = os.environ.get('EMAIL_PORT')
EMAIL_USE_TLS = True

# allauth configuration
SITE_ID = 1

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
)

SOCIALACCOUNT_PROVIDERS = {
    'google': {
        'SCOPE': [
            'profile',
            'email',
        ],
        'AUTH_PARAMS': {
            'access_type': 'online',
        }
    }
}

ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'

# django-debug-toolbar
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
INTERNAL_IPS = [ip[:-1] + "1" for ip in ips]

# production
if ENVIRONMENT == 'production':
    SECURE_BROWSER_XSS_FILTER = True
    X_FRAME_OPTIONS = 'DENY'
    SECURE_SSL_REDIRECT = True
    SECURE_HSTS_SECONDS = 3600
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_PRELOAD = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True
    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Heroku
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

码头工人-compose.yml

version: '3.8'

services:
  web:
    build: .
    # command: python /code/manage.py runserver 0.0.0.0:8001
    command: gunicorn clothes_shop_project.wsgi -b 0.0.0.0:8001
    environment: 
      - ENVIRONMENT=development
      - SECRET_KEY=<secret_key>
      - DEFAULT_FROM_EMAIL=<email>
      - EMAIL_HOST=smtp.sendgrid.net
      - EMAIL_HOST_USER=apikey
      - EMAIL_HOST_PASSWORD=<email_host_password>
      - EMAIL_PORT=<port>
      - DEBUG=1
    volumes:
      - .:/code
    ports:
      - 8001:8001
    depends_on:
      - db
  db:
    image: postgres:11
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - "POSTGRES_HOST_AUTH_METHOD=trust"

volumes:
  postgres_data:

docker-compose-prod.yml

version: '3.8'

services:
  web:
    build: .
    # command: python /code/manage.py runserver 0.0.0.0:8001
    command: gunicorn clothes_shop_project.wsgi -b 0.0.0.0:8001
    environment: 
      - ENVIRONMENT=production
      - SECRET_KEY=71dmqf6x1k^bnns1p!kkld7tq%=p!s)%r&f5h2y@^eq4h8i86$$
      - DEFAULT_FROM_EMAIL=luckly083@gmail.com
      - EMAIL_HOST=smtp.sendgrid.net
      - EMAIL_HOST_USER=apikey
      - EMAIL_HOST_PASSWORD=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
      - EMAIL_PORT=587
      - DEBUG=0
    ports:
      - 8001:8001
    depends_on:
      - db
  db:
    image: postgres:11
    environment:
      - "POSTGRES_HOST_AUTH_METHOD=trust"

Dockerfile

# Pull base image
FROM python:3.8

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set work directory
WORKDIR /code

# Install dependencies
COPY Pipfile Pipfile.lock /code/
RUN pip install --upgrade pip
RUN pip install pipenv && pipenv install --system

# Copy project
COPY . /code/

heroku.yml

setup:
  addons:
  - plan: heroku-postgresql
build:
  docker:
    web: Dockerfile
release:
  image: web
  command:
    - python manage.py collectstatic --noinput
run:
  web: gunicorn clothes_shop_project.wsgi

当我执行时出现问题python manage.py collectstatic --noinput,控制台显示的错误如下:

2021-03-18T23:01:40.412515+00:00 app[release.7010]: Traceback (most recent call last):
2021-03-18T23:01:40.412541+00:00 app[release.7010]: File "manage.py", line 22, in <module>
2021-03-18T23:01:40.412547+00:00 app[release.7010]: main()
2021-03-18T23:01:40.412548+00:00 app[release.7010]: File "manage.py", line 18, in main
2021-03-18T23:01:40.412644+00:00 app[release.7010]: execute_from_command_line(sys.argv)
2021-03-18T23:01:40.412646+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
2021-03-18T23:01:40.413128+00:00 app[release.7010]: utility.execute()
2021-03-18T23:01:40.413149+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
2021-03-18T23:01:40.413422+00:00 app[release.7010]: self.fetch_command(subcommand).run_from_argv(self.argv)
2021-03-18T23:01:40.413423+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 330, in run_from_argv
2021-03-18T23:01:40.413711+00:00 app[release.7010]: self.execute(*args, **cmd_options)
2021-03-18T23:01:40.413811+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/core/management/base.py", line 371, in execute
2021-03-18T23:01:40.414107+00:00 app[release.7010]: output = self.handle(*args, **options)
2021-03-18T23:01:40.414108+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 194, in handle
2021-03-18T23:01:40.414353+00:00 app[release.7010]: collected = self.collect()
2021-03-18T23:01:40.414354+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 109, in collect
2021-03-18T23:01:40.414518+00:00 app[release.7010]: for path, storage in finder.list(self.ignore_patterns):
2021-03-18T23:01:40.414519+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/contrib/staticfiles/finders.py", line 130, in list
2021-03-18T23:01:40.414613+00:00 app[release.7010]: for path in utils.get_files(storage, ignore_patterns):
2021-03-18T23:01:40.414614+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/contrib/staticfiles/utils.py", line 23, in get_files
2021-03-18T23:01:40.414811+00:00 app[release.7010]: directories, files = storage.listdir(location)
2021-03-18T23:01:40.414811+00:00 app[release.7010]: File "/usr/local/lib/python3.8/site-packages/django/core/files/storage.py", line 316, in listdir
2021-03-18T23:01:40.414998+00:00 app[release.7010]: for entry in os.scandir(path):
2021-03-18T23:01:40.415096+00:00 app[release.7010]: FileNotFoundError: [Errno 2] No such file or directory: '/code/static'
4

1 回答 1

3

如果你还没有解决这个问题?这对我有用。在您的 settings.py 中,删除这些行:

STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

并将其替换为

PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT  =   os.path.join(PROJECT_ROOT, 'staticfiles')

然后创建一个名为“static”的文件夹并创建一个文件并将其命名为 .any_thing_you_like,否则它不会保存。

ps注意:别忘了导入os

Ps 注意:我会建议你使用白噪声作为路径查找器

于 2021-06-21T17:49:26.870 回答