У меня есть приложение Django, и у меня есть следующие варианты использования:
manage.py runserver подход. Поэтому я ожидаю, что мое приложение будет работать для этого случая.https://myserver.com/tool1, https://myserver.com/tool2 и т. д. Поэтому я хотел бы разместить свое приложение в этой структуре.https://tool.myserver.comНо когда я попытался сделать это, у меня возникла проблема со статическими файлами (вздох!), потому что если у меня STATIC_URL в качестве относительного пути STATIC_URL='static/', то это не работает для «вложенных» страниц (т.е. если я нахожусь на myserver.com/tool1/page, то статические URL-адрес будет отображаться на myserver.com/tool1/page/static, что неверно).
С другой стороны, если я использую абсолютный путь STATIC_URL='/static/', то он вообще не работает для случая 2, потому что приложение Django ничего не знает о /tool1 части URL, где оно находится.
Я могу использовать два разных варианта для STATIC_URL в зависимости от среды и жесткого кода STATIC_URL='/tool1/static/', но тогда один и тот же код не будет работать для случая 3...
Как мне поступить в этой ситуации?
УПД
На самом деле я понял, что это больше похоже на общий вопрос nginx + backend, чем на вопрос Django. Потому что в конце дня веб-страница, созданная бэкэндом, скорее всего, будет иметь src = "/static/...." (если я не добавлю некоторые хаки в бэкэнд, чтобы вставить префикс /tool1). И мне интересно, как с этим обычно обращаются? Есть способ заменить фактический HTML-контент в nginx, но это сильно повлияет на производительность...
UPD2
Похоже, многие люди неправильно поняли мой вопрос, думая, что единственная проблема заключается в статических файлах. Однако это был всего лишь пример, потому что, как правильно заметил Иван, со ссылками та же проблема. Обычно на странице у меня есть ссылки вида a href = "/category/post?id=1". И, очевидно, когда сайт открывается как my.domain/tool1, это разрешается как my.domain/category..., что неверно (я хочу, чтобы он указывал на my.domain/tool1/category....)
@Иван, что ты имеешь в виду?
У вас есть гиперссылки в вашем веб-приложении? Как вы ссылаетесь на одну страницу с другой?
Поскольку мое приложение простое, у меня нет многоуровневых иерархических ссылок, у меня есть запрос на ту же страницу (например, href = "#", которая отлично работает). Но да, вы правы, такая же проблема у меня будет и со ссылками, не только со статическими
где STATIC_URL='static/' установлен? Можете ли вы показать свой файл конфигурации или соответствующие части?
Неважно, это очень специфично для Django, мои серверы nginx не используют static_url. Этот вопрос может помочь: stackoverflow.com/questions/7307549/…






Я рекомендую размещать ваши статические файлы в службе хранения, такой как AWS S3, Google Cloud Storage и т. д. Таким образом, он всегда доступен для любого URL-адреса, как у вас (вложенный, поддомен, что угодно)
Пример настройки (может потребоваться еще несколько шагов):
Измените свой settings.py:
STATIC_URL = 'https://storage.googleapis.com/your_bucket/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
Перед развертыванием приложения запустите manage.py collectstatic --noinput
staticfiles в службу хранилища и убедитесь, что они общедоступны.P.S. Я считаю, что whitenoise действительно помогает с размерами статических файлов и упрощает развертывание.
Использование облака здесь не помогает, потому что проблема не только в статических файлах (как указано в комментарии), но и в ссылках вообще. Также на каждом CDN есть примечание «не используйте CDN в качестве основного хранилища, используйте его только как зеркало», поэтому мне все равно нужно где-то хранить свои файлы (в том числе для локальной разработки, когда я изменяю статические)
Решение работает для локальной (файлы загружаются из локальной папки), среды разработки и производственной среды. Преимущество службы «Хранение в хранилище» заключается в том, что она поддерживает несколько регионов (если хотите), повышает скорость загрузки веб-страницы и снижает нагрузку на ваш сервер приложений. Что касается других ссылок, я не понимаю, почему они не работают. Вы можете объяснить?
см. комментарий Ивана к самому вопросу. Поскольку у меня есть ссылки `a href='/my/folder/page?id=1', и это неправильно разрешается, когда приложение находится в папке
Обработка приложения STATIC_URL from django может привести к накладным расходам. Поскольку у вас есть несколько подкаталогов, почему бы не обслуживать статические файлы только из одного из них? Нет необходимости сопоставлять подкаталог при обслуживании статических файлов.
Допустим, если вы установите STATIC_URL следующим образом:
STATIC_URL = "/tool1/static/"
Затем вы можете просто настроить NGINX следующим образом:
server {
listen 80
server_name *.myserver.com;
location /tool1/static/ {
root /path/to/STATIC_ROOT;
}
location / {
proxy_pass http://localhost:8000; # <-- No trailing slash to make it work with gunicorn
}
location /tool2/ {
proxy_pass http://localhost:8000;
proxy_set_header SCRIPT_NAME /tool2; # <-- For serving in sub path
}
location /tool1/ {
proxy_pass http://localhost:8000;
proxy_set_header SCRIPT_NAME /tool1; # <-- For serving in sub path
}
}
И в настройках обновите STATIC_URL на /tool1/static/. Также убедитесь, что ваш STATIC_ROOT указывает на правильный путь, по которому статические файлы будут находиться на сервере. Наконец, перед развертыванием статических файлов вам необходимо запустить collectstatic command, чтобы поместить статические файлы в каталог STATIC_ROOT, а затем перезапустить сервер NGINX.
Обновлять: не рекомендуется использовать жестко заданный URL. Вместо этого в шаблоне вы должны использовать тег {% URL '<url_name> '%} или reverse() в коде Python. Таким образом, django сам разрешит URL-адреса. Когда он находится в /tool1 месте, URL-адреса будут разрешены как /tool1/url_name/, а /tool2/url_name, когда вы находитесь в местоположении /tool2 (на основе SCRIPT_NAME).
Я правильно понял, что вы предлагаете хардкодить tool1 один раз в Django и два раза в Nginx? В чем преимущество этого вместо того, чтобы явно помещать его один раз на стороне nginx, а затем динамически использовать SCRIPT_NAME на резервной стороне? Кроме того, это также не помогает для ссылок на страницах, похожих на a href = "/main/page?id=1" — это неправильно разрешается, когда приложение находится в папке.
При вызове URL-адресов вы не должны жестко кодировать его. вместо этого используйте тег {% URL%}, поэтому django решит его сам. Кроме того, как вы собираетесь динамически определять SCRIPT_NAME на стороне сервера? В django есть одна переменная с именем FORCE_SCRIPT_NAME, но она не динамическая. Но вам это не нужно, так как вы можете указать его в заголовке SCRIPT_NAME явно в конфигурации NGINX.
Из документа url: «Возвращает ссылку на абсолютный путь (URL-адрес без имени домена)». Так что он вернет мне абсолютно тот же URL href = "/my/page"
Возможно нет. Из-за SCRIPT_NAME он должен настроить URL-адрес, например «/tool1/url/», если он находится в /tool1.
Звучит как недокументированная магия, вау. Но спасибо, что указали на это, Django действительно может автоматически обрабатывать заголовок SCRIPT_NAME, если он правильно перенаправлен/установлен. Я узнал что-то новое сегодня :)
Кажется, что нет действительно хорошего способа решить эту проблему. Однако есть несколько вариантов, которые я нашел:
Всегда используйте один канонический адрес (лично предпочтительно)
Я должен спросить себя: «Почему вы хотите, чтобы ваш инструмент был доступен как в https://myserver.com/tool1, так и в https://tool1.myserver.com?». И на самом деле у меня нет причин, почему он должен быть доступен отдельно в то же время. Так что просто выберите «канонический» адрес и настройте правильные перенаправления:
Если домен канонический:
server_name myserver.com
location /tool1/ {
rewrite ^/tool1/?(.*)$ https://tool1.myserver.com/$1 permanent;
}
Если папка каноническая:
server_name tool1.myserver.com
location / {
rewrite ^ https://myserver.com/tool1$request_uri? permanent;
}
Затем на стороне сервера используйте любую опцию один STATIC_URL, соответствующую каноническому адресу (например, /static для поддомена или /tool1/static для папки)
Дополнительные заголовки или параметры URL
Если есть причина (скажите мне, почему!) не использовать перенаправления и использовать оба адреса, то, как упоминал ruddra, можно добавить дополнительные заголовки, а затем использовать их на стороне сервера для создания немного разных страниц:
location /tool1/ {
<proxy_pass something>
proxy_set_header SCRIPT_NAME /tool1;
}
Тот же подход можно использовать, если вы выбираете папку в качестве канонического адреса, тогда вы можете избежать жесткого кодирования tool1 в бэкэнде. Тогда, возможно, вы можете использовать либо собственный заголовок, либо дополнительный параметр URL, например ?from=domain[1], который можно обрабатывать в бэкэнде. Здесь у меня нет готового решения, так как для меня был предпочтительнее случай поддомена.
Допустим, у вас есть 2 разных домена abc.com/sales/ и xyz.com/e-commerce/, и вы хотите использовать одно и то же приложение для обоих доменов, тогда подход Additional headers or URL params полезен. :)
Как вы решили это для всех других страниц / URL-адресов?