将 django 应用程序部署到 heroku 时如何解决“FileNotFoundError: [Errno 2] No such file or directory: '/code/static”?

问题描述

我正在阅读 William S. vincent 的书 Django for Professionals,我尝试将 django 应用程序部署到 heroku,但是在部署此应用程序时静态文件夹位置失败,我正在使用 Dockerwhitenoise 包用于处理静态文件,这里是文件中的重要信息。 设置.py 导入 dj_database_url 进口插座 从 pathlib 导入路径 导入操作系统

# 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)

docker-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'

解决方法

如果你还没有解决这个问题? 这对我有用。 在您的 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 注意:我会建议你在路径查找器中使用白噪声

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...