Как обслуживать статические файлы с помощью django с жестко заданными относительными путями в Heroku/OpenShift/etc?
У меня есть файлы HTML/JS/CSS, предоставленные третьей стороной (которую я не могу контролировать), которая служит одностраничным приложением, которое взаимодействует с бэкэндом, созданным с помощью Django и django-rest-framework.
Я хочу разместить это на Heroku, и таким образом эти статические ресурсы обслуживает Django. Эти файлы содержат относительные пути друг к другу. Например, index.html содержит:
<link rel="stylesheet" type="text/css" media="screen" href="styles/css/bootstrap.min.css">
Что приводит к 404, потому что styles/css/bootstrap.min.css
не маршрутизируется Джанго.
Единственный известный мне способ обслуживания index.html из корня моего домена www.domain.com
это с конфигурацией URL, как:
url(r'^$', TemplateView.as_view(template_name='index.html'), name='home'),
... хотя на самом деле это не шаблон, это просто обычный HTML.
Проблема возникает из-за того, что все URL в других активах относительно этого index.html
и, конечно, Django не работает так. Если бы я разрабатывал это интерфейсное приложение, я бы использовал static
тег шаблона и один из различных способов получить URL-адреса для JavaScript.
Я не возражаю переключиться с Heroku на другой PaaS, если они предлагают решение этой проблемы, но ручное редактирование всех этих файлов не похоже на забавную работу... особенно учитывая тот факт, что я буду получать обновления этих файлов идти вперед.
Я думаю, что для решения этой проблемы на обычном старом сервере можно было бы настроить веб-сервер для правильного разрешения этих URL-адресов, но эта опция недоступна в Heroku.
2 ответа
Вот как настроить Django для обслуживания ваших статических файлов и index.html в / при сохранении возможности использовать представления Django для панели администратора, регистрации и т. Д.
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.staticfiles.views import serve
from django.views.generic import RedirectView
admin.autodiscover()
urlpatterns = [
# / routes to index.html
url(r'^$', serve,
kwargs={'path': 'index.html'}),
# static files (*.css, *.js, *.jpg etc.) served on /
# (assuming Django uses /static/ and /media/ for static/media urls)
url(r'^(?!/?static/)(?!/?media/)(?P<path>.*\..*)$',
RedirectView.as_view(url='/static/%(path)s', permanent=False)),
# other views still work too
url(r'^admin/', include(admin.site.urls)),
]
Я уточняю urlpatterns
как список, как требует Django 1.10. Перенаправления не являются постоянными по умолчанию с 1.9, поэтому вам нужно явно установить permanent=True
если вы хотите, чтобы браузеры кешировали это, хотя при отладке лучше начать с False
,
Этот подход позволяет вам использовать что-то вроде create-реагировать-приложение или генераторы внешнего интерфейса Yeoman, которые упаковывают встроенное минифицированное приложение внешнего интерфейса в одну папку (например, dist /). Затем вы, например, используете скрипт, чтобы переместить его в папку статических файлов Django (например, myproject / static /) и передать его из Heroku.
То, что написал Ян о желании использовать что-то вроде S3 для своих статических файловых стендов, но иногда вы просто хотите начать с простого репозитория, одного Heroku dyno, и при этом иметь возможность использовать Django + SPA. Кроме того, использование чего-то вроде WhiteNoise делает обслуживание статических файлов из Python вполне приемлемым и позволяет вам позже легко разместить CDN перед вашими статическими файлами.
Примечание: для загружаемых пользователем файлов вы все равно должны использовать сторонний сервис, такой как Amazon S3 или Backblaze B2 (который представляет собой 4 строки кода для интеграции).
Обслуживание медиафайлов
WhiteNoise не подходит для обслуживания загруженных пользователем "медиа" файлов. Во-первых, как описано выше, он проверяет только статические файлы при запуске, поэтому файлы, добавленные после запуска приложения, не будут видны. Что еще более важно, обслуживание загруженных пользователями файлов из того же домена, что и основное приложение, представляет угрозу безопасности ( этот пост в блоге безопасности Google хорошо описывает проблему). Кроме того, использование локального диска для хранения и обслуживания пользовательских носителей затрудняет масштабирование приложения на нескольких компьютерах.
По всем этим причинам гораздо лучше хранить файлы в отдельной выделенной службе хранения и предоставлять их пользователям оттуда. Библиотека django-storages предоставляет множество опций, например Amazon S3, Azure Storage и Rackspace CloudFiles.
Примечание 2: на производстве с DEBUG=False
Есть проблемы, поэтому проверьте эту проблему WhiteNoise для решения.
Примечание 3: Превратил этот ответ в сообщение в блоге здесь.
Примечание 4: с момента написания этой статьи я все больше и больше настраивал решение для маршрутизации через веб- интерфейс, поэтому в итоге я выпустил новый пакет django-spa, предназначенный для простого обслуживания одностраничных приложений от Django.
Хранение статических / мультимедийных файлов на серверах Heroku проблематично и не рекомендуется. Есть обходные пути, но проще использовать альтернативу для их размещения. Кроме того, при повторном запуске динамо файлы на Heroku будут удалены.
Вместо этого используйте веб-сервис для хранения ваших файлов. Эти файлы собираются с помощью collectstatic (который запускается каждый раз, когда вы нажимаете на Heroku), это ожидаемое поведение.
Для простоты использования и производительности вы должны использовать статические файлы из другого источника, например AWS S3, как подробно описано здесь - https://devcenter.heroku.com/articles/s3
Все это означает, что файлы, которые вы хотите обслуживать, НЕ ДОЛЖНЫ подаваться через ваш производственный сервер (например, ваш Heroku dyno), поскольку это может обеспечить явную дыру в безопасности. Вместо этого все ваши вспомогательные файлы, которые будут обслуживаться, должны быть переданы через другой сервер / местоположение. Для этого в Django есть статические файлы, и когда вы отправляете их в Heroku, эти файлы (любые из найденных в каталогах, указанных в STATICFILES_DIRS в вашем файле settings.py) собираются в общем месте.
Я знаю, что вы, вероятно, спрашиваете "Почему это так сложно?", И это справедливый вопрос, но как только вы поймете, как Django обрабатывает статические файлы, это станет проще и понятнее.
Отличная статья, которая может помочь устранить путаницу. http://agiliq.com/blog/2014/06/heroku-django-s3-for-serving-media-files/