简体   繁体   English

从 django 静态文件提供服务并上传到 heroku 时,无法找到反应 static 文件

[英]Unable to locate react static files when serving from django staticfiles and uploading to heroku

I'm trying to add a Django backend and a react frontend to Heroku.我正在尝试向 Heroku 添加一个 Django 后端和一个反应前端。 Following this tutorial .按照本教程 I'm using whitenoise for serving static files.我正在使用白噪声来提供 static 文件。

When runnning python manage.py collectstatic I keep getting the same error: 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)

This command is also run by heroku python hooks when deploying.部署时,此命令也由 heroku python 挂钩运行。 The python hook runs after the react hook, so the react build folder is definitely there. python 钩子在反应钩子之后运行,所以反应构建文件夹肯定在那里。 For testing purposes I also ran build locally for when I call the collectstatic command.出于测试目的,当我调用collectstatic命令时,我还在本地运行了build

The problem is something to do with how I'm defining static roots, but for the life of me I can't figure it out.问题与我如何定义 static 根有关,但对于我的一生,我无法弄清楚。 I've used multiple tutorials, the django docs on static files, and the heroku dev docs on static files.我已经使用了多个教程,static 文件上的 django 文档,以及 ZA81259CEFCA38D10D10D4 文件上的 heroku 开发文档。

Why is it looking for my media files (background-pattern.png etc.) in static?为什么它在 static 中寻找我的媒体文件(background-pattern.png 等)? On collectstatic everything gets put into the staticfiles directory.collectstatic上,所有内容都被放入staticfiles目录。 No matter what I change the file names or variables to, that error about the lookup conflict between staticfiles and static always happens.无论我将文件名或变量更改为什么,关于静态文件和staticfiles之间查找冲突的static总是会发生。

Here's how I'm defining them:这是我定义它们的方式:

settings.py设置.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'),
)

Here's how the project is structured:以下是项目的结构:

在此处输入图像描述

EDIT: Using this config, I can serve the backend just fine.编辑:使用这个配置,我可以很好地为后端服务。 If I go to the root url / , I see the Django 404 page instead o my React homepage.如果我 go 到根 url / ,我看到 Django 404 页面而不是我的 React 主页。 Going to /admin works perfectly, and I can call /api/ endpoints.转到/admin效果很好,我可以调用/api/端点。

First maybe some clarification:-)首先也许是一些澄清:-)

The "Media" directory is used for content uploaded for example by a user. “媒体”目录用于例如由用户上传的内容。 So it's more a dynamic content, not static.所以它更多的是动态内容,而不是 static。 Or at least not static with every instance of your service.或者至少不是 static 与您的服务的每个实例。 Therefore it's usually also not shipped with your application.因此,它通常也不随您的应用程序一起提供。 Details in the django documentation django 文档中的详细信息

Also check settings documentation about MEDIA_ROOT还要检查 有关 MEDIA_ROOT 的设置文档

I assume in your settings you something like MEDIA_ROOT = "build/static/media/" or something similar, which results in the conflict.我假设在你的设置中你有类似MEDIA_ROOT = "build/static/media/"或类似的东西,这会导致冲突。

If you want to use "media" files, hence user uploaded files, you need a different storage on Heroku anyway.如果您想使用“媒体”文件,即用户上传的文件,则无论如何您都需要在 Heroku 上使用不同的存储空间。 Heroku Dynos have a ephemeral filesystem which means you get a fresh copy of your instance once a day, which results in loss of all that data you stored during the life-time of the instance. Heroku Dynos 有一个临时文件系统,这意味着您每天可以获得一次实例的新副本,这会导致您在实例生命周期内存储的所有数据丢失。

To solve this this problem you can store those media files for example on AWS S3.要解决此问题,您可以将这些媒体文件存储在例如 AWS S3 上。 Django has an awesome addon , which replaces the filesystem storage with AWS S3 storage. Django 有一个很棒的插件,它将文件系统存储替换为 AWS S3 存储。 Which means the API from your point of you as a Developer does not change at all.这意味着从您作为开发人员的角度来看,API 根本不会改变。

Here is a Django Development and PROD setting example with django-s3-storage:这是使用 django-s3-storage 的 Django 开发和 PROD 设置示例:

Development example config (nothing special, no S3):开发示例配置(没什么特别的,没有 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

For your local development make SURE media and static do not point to the same directory/structure.对于您的本地开发,请确保媒体和 static 不指向相同的目录/结构。

Production example config:生产示例配置:

# 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM