从 django 静态文件提供服务并上传到 heroku 时无法找到反应静态文件
Unable to locate react static files when serving from django staticfiles and uploading to heroku
我正在尝试向 Heroku 添加 Django 后端和 React 前端。正在关注 this tutorial。我正在使用 whitenoise 来提供静态文件。
当 运行nning python manage.py collectstatic
我一直收到同样的错误:
django.core.exceptions.SuspiciousFileOperation: The joined path (C:\Users\<name>\Documents\combined_connect\static\media\background-pattern.f6347303.png) is located outside of the base path component (C:\Users\<name>\Documents\combined_connect\staticfiles)
此命令在部署时也被 heroku python 挂钩 运行。 python hook 在 react hook 之后 运行s,所以 react build 文件夹肯定在那里。出于测试目的,当我调用 collectstatic
命令时,我还在本地 运行 build
。
问题与我定义静态根的方式有关,但我终究无法弄明白。我使用了多个教程,关于静态文件的 django 文档,以及关于静态文件的 heroku dev 文档。
为什么它以静态方式查找我的媒体文件(背景-pattern.png 等)?在 collectstatic
上,所有内容都放入 staticfiles
目录中。无论我将文件名或变量更改为什么,关于 staticfiles
和 static
之间的查找冲突的错误总是会发生。
我是这样定义它们的:
settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'build')], # pointing to the React build folder
'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',
],
},
},
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = 'build/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'build/static'),
)
项目结构如下:
编辑:使用此配置,我可以很好地为后端提供服务。如果我转到根 url /
,我会看到 Django 404 页面而不是我的 React 主页。转到 /admin
完美无缺,我可以调用 /api/
个端点。
首先可能需要澄清一下:-)
“媒体”目录用于存放例如用户上传的内容。所以它更像是一个动态的内容,而不是静态的。或者至少对于您的服务的每个实例来说都不是静态的。因此,它通常也不随您的应用程序一起提供。 django documentation
中的详细信息
同时勾选 settings documentation about MEDIA_ROOT
我假设在你的设置中你有类似 MEDIA_ROOT = "build/static/media/"
或类似的东西,这会导致冲突。
如果您想使用“媒体”文件,即用户上传的文件,您无论如何都需要在 Heroku 上使用不同的存储空间。 Heroku Dynos 有一个 ephemeral filesystem,这意味着您每天获取一次实例的新副本,这会导致您在实例生命周期内存储的所有数据丢失。
要解决此问题,您可以将这些媒体文件存储在 AWS S3 上。
Django 有一个很棒的 addon,它将文件系统存储替换为 AWS S3 存储。这意味着您作为开发人员的 API 根本没有改变。
这里是一个使用 django-s3-storage 的 Django 开发和 PROD 设置示例:
开发示例配置(没什么特别的,没有 S3):
class Development(Configuration):
... # Your code
@property
def MEDIA_ROOT(self):
default_value = os.path.join(self.BASE_DIR, 'public', 'media')
return values.Value(default=default_value, environ_name='MEDIA_ROOT')
@property
def STATIC_ROOT(self):
default_value = os.path.join(self.BASE_DIR, 'static')
return values.Value(default=default_value, environ_name='STATIC_ROOT')
@property
def STATICFILES_DIRS(self):
return (
os.path.join(self.BASE_DIR, 'whatever', 'react', 'build'),
os.path.join(self.BASE_DIR, 'yourapp', 'admin', 'static'),
)
... # Your code
为了您的本地开发,确保媒体和静态不要指向相同的 directory/structure。
生产示例配置:
# Inheriting from Development only serves as example. Good practice would be to move code used by both environments into a `Base` class.
class Production(Development):
... # Your code
DEFAULT_FILE_STORAGE = 'django_s3_storage.storage.S3Storage'
AWS_REGION = "us-east-1"
AWS_ACCESS_KEY_ID = values.Value(default='', environ_name='AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = values.Value(default='', environ_name='AWS_SECRET_ACCESS_KEY')
AWS_S3_BUCKET_NAME = values.Value(default='', environ_name='AWS_S3_BUCKET_NAME')
@property
def INSTALLED_APPS(self):
return super().INSTALLED_APPS + [
'django_s3_storage',
]
... # Your code
我正在尝试向 Heroku 添加 Django 后端和 React 前端。正在关注 this tutorial。我正在使用 whitenoise 来提供静态文件。
当 运行nning python manage.py collectstatic
我一直收到同样的错误:
django.core.exceptions.SuspiciousFileOperation: The joined path (C:\Users\<name>\Documents\combined_connect\static\media\background-pattern.f6347303.png) is located outside of the base path component (C:\Users\<name>\Documents\combined_connect\staticfiles)
此命令在部署时也被 heroku python 挂钩 运行。 python hook 在 react hook 之后 运行s,所以 react build 文件夹肯定在那里。出于测试目的,当我调用 collectstatic
命令时,我还在本地 运行 build
。
问题与我定义静态根的方式有关,但我终究无法弄明白。我使用了多个教程,关于静态文件的 django 文档,以及关于静态文件的 heroku dev 文档。
为什么它以静态方式查找我的媒体文件(背景-pattern.png 等)?在 collectstatic
上,所有内容都放入 staticfiles
目录中。无论我将文件名或变量更改为什么,关于 staticfiles
和 static
之间的查找冲突的错误总是会发生。
我是这样定义它们的:
settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'build')], # pointing to the React build folder
'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',
],
},
},
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = 'build/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'build/static'),
)
项目结构如下:
编辑:使用此配置,我可以很好地为后端提供服务。如果我转到根 url /
,我会看到 Django 404 页面而不是我的 React 主页。转到 /admin
完美无缺,我可以调用 /api/
个端点。
首先可能需要澄清一下:-)
“媒体”目录用于存放例如用户上传的内容。所以它更像是一个动态的内容,而不是静态的。或者至少对于您的服务的每个实例来说都不是静态的。因此,它通常也不随您的应用程序一起提供。 django documentation
中的详细信息同时勾选 settings documentation about MEDIA_ROOT
我假设在你的设置中你有类似 MEDIA_ROOT = "build/static/media/"
或类似的东西,这会导致冲突。
如果您想使用“媒体”文件,即用户上传的文件,您无论如何都需要在 Heroku 上使用不同的存储空间。 Heroku Dynos 有一个 ephemeral filesystem,这意味着您每天获取一次实例的新副本,这会导致您在实例生命周期内存储的所有数据丢失。
要解决此问题,您可以将这些媒体文件存储在 AWS S3 上。 Django 有一个很棒的 addon,它将文件系统存储替换为 AWS S3 存储。这意味着您作为开发人员的 API 根本没有改变。
这里是一个使用 django-s3-storage 的 Django 开发和 PROD 设置示例:
开发示例配置(没什么特别的,没有 S3):
class Development(Configuration):
... # Your code
@property
def MEDIA_ROOT(self):
default_value = os.path.join(self.BASE_DIR, 'public', 'media')
return values.Value(default=default_value, environ_name='MEDIA_ROOT')
@property
def STATIC_ROOT(self):
default_value = os.path.join(self.BASE_DIR, 'static')
return values.Value(default=default_value, environ_name='STATIC_ROOT')
@property
def STATICFILES_DIRS(self):
return (
os.path.join(self.BASE_DIR, 'whatever', 'react', 'build'),
os.path.join(self.BASE_DIR, 'yourapp', 'admin', 'static'),
)
... # Your code
为了您的本地开发,确保媒体和静态不要指向相同的 directory/structure。
生产示例配置:
# Inheriting from Development only serves as example. Good practice would be to move code used by both environments into a `Base` class.
class Production(Development):
... # Your code
DEFAULT_FILE_STORAGE = 'django_s3_storage.storage.S3Storage'
AWS_REGION = "us-east-1"
AWS_ACCESS_KEY_ID = values.Value(default='', environ_name='AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = values.Value(default='', environ_name='AWS_SECRET_ACCESS_KEY')
AWS_S3_BUCKET_NAME = values.Value(default='', environ_name='AWS_S3_BUCKET_NAME')
@property
def INSTALLED_APPS(self):
return super().INSTALLED_APPS + [
'django_s3_storage',
]
... # Your code