【问题标题】:Django stops serving static files when DEBUG is False当 DEBUG 为 False 时,Django 停止提供静态文件
【发布时间】:2019-12-02 09:04:51
【问题描述】:

我使用 Docker Compose 以及将静态文件夹复制到 /static 的 Dockerfile:

FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY static /static/
COPY . /code/

在我使用的设置文件中:

if env == "dev":
    DEBUG = True
else:
    DEBUG = False
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SECURE_BROWSER_XSS_FILTER = True
    X_FRAME_OPTIONS = "DENY"

STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]

STATICFILES_DIRS = [
    # os.path.join(BASE_DIR, "static/"),
    '/static'
]

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

静态文件在 dev 中工作,但是当我将 env 更改为 prod 时,我开始收到 404 错误。

所以你看出问题了吗?

【问题讨论】:

  • Django 的静态文件在生产环境中不起作用 (docs.djangoproject.com/en/2.2/howto/static-files/…) 你最好为此配置 nginx/apache/...。
  • STATICFILES_DIRS 是您的静态文件的位置在您的代码存储库中,Django 应该从那里为collectstatic 获取它们。所以这个设置是错误的,它不应该是/static(通常,如果在你的应用程序的“静态”文件夹中,你根本不需要设置它)。同时向我们展示你的 apache/nginx 配置。
  • 注意:我已经写了一个blog post,介绍了如何使用白噪声和 CDN 设置静态文件(针对 AWS,但包含有用的解释,可帮助您了解整个事情的工作原理)。跨度>

标签: django django-staticfiles django-static


【解决方案1】:

虽然**强烈不鼓励*在生产环境中提供来自 Django 的静态文件(并且出于非常充分的理由),但我经常需要这样做。

在某些情况下它完全可以接受(低流量、仅 REST API 的服务器等)。如果你需要这样做,这个 sn-p 应该会有所帮助。调整 re_path 或使用 url() 如果那是您的 django 风格。

from django.contrib.staticfiles.views import serve as serve_static

def _static_butler(request, path, **kwargs):
    """
    Serve static files using the django static files configuration
    WITHOUT collectstatic. This is slower, but very useful for API 
    only servers where the static files are really just for /admin

    Passing insecure=True allows serve_static to process, and ignores
    the DEBUG=False setting
    """
    return serve_static(request, path, insecure=True, **kwargs)

urlpatterns = [
    ...,
    re_path(r'static/(.+)', _static_butler)
]

【讨论】:

  • 不知道为什么我的资产上出现“服务器错误 (500)”
  • 我应该测试 re_path。将其更改为 static/(.+) 即可。显然它需要捕获子路径,以便可以将其作为位置参数传递。我的自定义包装器为我制作了该组,抱歉我没有注意到!
  • 谢谢,它有效。我会接受这个回复,但对于正在寻找 docker-compose 和 nginx 解决方案的人来说,我写的另一个解决方案也可以。
  • 老实说,我认为您的解决方案更好!地雷有点像黑客,而不是真正的“解决方案”。它有它的时间和地点,仅此而已。
  • 我更新了我的回复并提到了低流量的情况。
【解决方案2】:

注意:这个答案也是正确的,但我也接受了上面的答案(因为我的应用会收到非常低的流量。)

感谢您的 cmets。它们很有用。

这是我的新 docker compose 文件:

version: '3.5'

services:
  nginx:
    image: nginx:latest
    ports:
      - "8002:8000"
    volumes:
      - $PWD:/code
      - ./config/nginx:/etc/nginx/conf.d
      - ./static:/static
    depends_on:
      - web
    networks:
      - my_net
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    env_file: .env
    volumes:
      - $PWD:/code
      - ./static:/static
    expose:
      - "8000"
    networks:
      - my_net

networks:
  my_net:
    driver: bridge

这是 Nginx 配置文件:

upstream web {
  ip_hash;
  server web:8000;
}

server {

    location /static/ {
        autoindex on;
        alias /static/;
    }

    location / {
        proxy_pass http://web/;
    }
    listen 8000;
    server_name localhost;
}

您还应该将“web”添加到允许的主机:

ALLOWED_HOSTS = ['0.0.0.0', 'localhost', 'web']

更新: settings.py 文件:

STATICFILES_FINDERS = [
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
    # '/static'
]

STATIC_ROOT = '/static' #os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'

正如@dirkgroten 所说,您可以在您服务的静态文件中设置过期标头。

另一种解决方案是使用 Whitenoise(感谢 Daniel Roseman)。

【讨论】:

  • 为了完整起见,请显示您的设置(STATIC_ROOT 应该是 '/static' 并且 STATICFILES_DIRS 应该是 os.path.join(BASE_DIR, "static") 或者如果您的静态文件位于应用程序的静态目录中,则不显示任何内容)
  • 另外,正如我的博文中提到的,如果您使用 nginx 提供静态文件,您应该设置过期标头,这样用户就不必为每个页面下载它们。您应该使用不同的 STATICFILES_STORAGE 添加清单。
猜你喜欢
  • 2019-06-01
  • 2012-11-27
  • 2020-10-27
  • 2018-08-24
  • 2016-11-26
  • 1970-01-01
  • 2022-12-10
  • 2020-08-19
相关资源
最近更新 更多