Django перестает обслуживать статические файлы, когда DEBUG имеет значение False

Я использую Docker Compose вместе с этим Dockerfile, который копирует статическую папку в /static:

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.

Итак, вы видите проблему?


person 4m1nh4j1    schedule 24.07.2019    source источник
comment
Статические файлы Django не работают в рабочей среде (docs.djangoproject.com/en/2.2/howto/static-files/), для этого лучше настроить nginx/apache/....   -  person Willem Van Onsem    schedule 24.07.2019
comment
См., например, docs.djangoproject.com/en/2.2/howto/ статические файлы/развертывание   -  person Willem Van Onsem    schedule 24.07.2019
comment
STATICFILES_DIRS – это расположение ваших статических файлов внутри репозитория кода, откуда Django должен получить их для collectstatic. Так что эта настройка неверна, она не должна быть /static (обычно, если внутри «статической» папки в вашем приложении, вам вообще не нужно устанавливать это). Также покажите нам свою конфигурацию apache/nginx.   -  person dirkgroten    schedule 24.07.2019
comment
Примечание. Я написал сообщение в блоге о том, как настроить статические файлы с помощью whitenoise и CDN (предназначено для AWS, но содержит полезные пояснения, которые помогут вам понять, как все это работает).   -  person dirkgroten    schedule 24.07.2019


Ответы (2)


Хотя **настоятельно не рекомендуется* использовать статические файлы из Django в рабочей среде (и по ОЧЕНЬ веским причинам), мне все равно часто приходится это делать.

В некоторых случаях это вполне приемлемо (низкий трафик, только сервер REST API и т. д.). Если вам нужно это сделать, этот фрагмент должен помочь. Отрегулируйте 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)
]

person Andrew Backer    schedule 24.07.2019
comment
Не уверен, почему у меня возникает ошибка сервера (500) в активах. - person 4m1nh4j1; 24.07.2019
comment
Я должен был протестировать re_path. Измените его на static/(.+) и все заработает. Очевидно, ему нужно захватить подпуть, чтобы он мог передать его как позиционный параметр. Моя пользовательская оболочка создала эту группу для меня, извините, я этого не заметила! - person Andrew Backer; 24.07.2019
comment
Спасибо, это работает. Я приму этот ответ, но для людей, которые ищут решение с docker-compose и nginx, другое решение, которое я написал, тоже работает. - person 4m1nh4j1; 24.07.2019
comment
Честно говоря, я думаю, что ваше решение лучше! Мины своего рода хак, на самом деле не решение. Этому свое время и место, вот и все. - person Andrew Backer; 24.07.2019
comment
Я обновил свой ответ и упомянул, что дело в низком трафике. - person 4m1nh4j1; 24.07.2019
comment
Нет причин делать это. Если вы хотите обслуживать статические файлы из Django, используйте Whitenoise. - person Daniel Roseman; 24.07.2019
comment
Добавлю это к моему ответу. - person 4m1nh4j1; 24.07.2019

Примечание. Этот ответ также правильный, но я также принял приведенный выше ответ (поскольку мое приложение будет получать очень низкий трафик).

Спасибо за ваши комментарии. Они были полезны.

Это мой новый файл компоновки докеров:

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;
}

Вы также должны добавить «веб» в разрешенные хосты:

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 (Спасибо Дэниелу Роузману).

person 4m1nh4j1    schedule 24.07.2019
comment
Для полноты покажите свои настройки (STATIC_ROOT должен быть «/ static», а STATICFILES_DIRS должен быть os.path.join(BASE_DIR, static) или ничего, если ваши статические файлы находятся в статическом каталоге вашего приложения) - person dirkgroten; 24.07.2019
comment
Кроме того, как упоминалось в моем сообщении в блоге, если вы обслуживаете свои статические файлы с помощью nginx, вы должны установить заголовки с истечением срока действия, чтобы пользователям не приходилось загружать их для каждой страницы. И вы должны использовать другое STATICFILES_STORAGE для добавления манифеста. - person dirkgroten; 24.07.2019