Dlaczego DEBUG = Fałszywe ustawienie powoduje awarię dostępu do plików statycznych django?

356

Buduję aplikację, używając Django jako mojego konia roboczego. Do tej pory wszystko było dobrze - określone ustawienia db, skonfigurowane katalogi statyczne, adresy URL, widoki itp. Ale problemy zaczęły się pojawiać w momencie, gdy chciałem wyrenderować własne piękne i niestandardowe strony 404.html i 500.html.

Przeczytałem dokumenty na temat niestandardowej obsługi błędów i ustawiłem niezbędne konfiguracje w UrlsConf, utworzyłem odpowiednie widoki i dodałem pliki 404.html i 500.html do katalogu szablonów mojej aplikacji (również określonego w pliku settings.py).

Ale doktorzy mówią you can actually view custom error views until Debug is Off, więc wyłączyłem to, aby przetestować swoje rzeczy, i to wtedy rzeczy szaleją!

Nie tylko nie mogę wyświetlić niestandardowego pliku 404.html (w rzeczywistości ładuje się, ale ponieważ każda z moich stron błędów zawiera graficzny komunikat o błędzie - jak jakiś fajny obraz), źródło strony błędów ładuje się, ale nic innego się nie ładuje! Nawet niepowiązany CSS lub JavaScript!

Zasadniczo po ustawieniu DEBUG = Falsewszystkie widoki zostaną załadowane, ale żadna powiązana treść (CSS, JavaScript, obrazy itp.) Nie będzie ładowana! Co się dzieje? Czy czegoś brakuje w odniesieniu do plików statycznych i DEBUGustawień?

nemesisfixx
źródło
Jak się masz? Komputer lokalny z serwerem testowym?
j_syk
komputer lokalny z serwerem testowym. Zasadniczo chcę zobaczyć, jak działałaby moja niestandardowa obsługa błędów, lokalnie symulując scenariusze, takie jak uzyskiwanie dostępu do nieistniejących stron i powodowanie błędów w czasie wykonywania - ale moja zawartość statyczna nie ładuje się.
nemesisfixx
Albo można to zrobić na poziomie serwera, jak tutaj, lub można to zrobić na poziomie Django, dodając urlpattern. Znalazłem to poniższe pytanie dotyczące tego samego problemu. stackoverflow.com/questions/6405173/…
Pankaj Anand

Odpowiedzi:

353

Po wyłączeniu debugowania Django nie będzie już obsługiwał plików statycznych - produkcyjny serwer WWW (Apache lub coś takiego) powinien się tym zająć.

Marek Sapota
źródło
3
To faktycznie uspokaja moją ciekawość, więc teraz ma to sens i rzeczywiście mogę zająć się tym z Apache, jeśli zajdzie taka potrzeba. Myślałem, że to problem z moimi własnymi ustawieniami. Dzięki
nemesisfixx
5
Ta odpowiedź była dla mnie bardzo pomocna. Na wypadek, gdyby ktoś był w tej samej sytuacji (używając Google App Engine dla aplikacji z nonrel django): nie zapomnij zaktualizować app.yaml.
Lyndsey Ferguson,
3
handlers: - url: / static static_dir: static
Lyndsey Ferguson
475

Jeśli nadal potrzebujesz lokalnego serwera statycznego (np. Do testowania bez debugowania), możesz uruchomić devserver w trybie niepewnym:

manage.py runserver --insecure
Dmitrij Szewczenko
źródło
6
Chociaż ta flaga działa, nie wyświetla treści z folderu kolekcjonerskiego
Howie
5
To magia. Dziękuję panu, jesteś bohaterem. Ta odpowiedź powinna zostać połączona z odpowiedzią zaakceptowaną, ponieważ rozwiązuje problem bez konieczności podawania statycznego za pomocą innego sposobu niż sam django.
Depado
1
To było wszystko, czego potrzebowałem. Chociaż najlepszą praktyką byłoby użycie zmiennej środowiskowej do rozróżnienia między środowiskiem programistycznym i produkcyjnym oraz przełączania debugowania.
Neeraj Gupta
1
Uwaga: to NIE będzie działać z ManifestStaticFilesStorage jako code.djangoproject.com/ticket/19295
Andrea Rabbaglietti
9
czy ktoś może mi powiedzieć, co jest w tym takiego niepewnego
Kavi Vaidya,
36

Możesz użyć WhiteNoise do obsługi plików statycznych w produkcji.

Zainstalować:

pip install WhiteNoise

I zmień plik wsgi.py na:

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

I możesz iść!

Kredyt na blogu Creative Handlebar .

ALE tak naprawdę nie zaleca się serwowania plików statycznych w ten sposób podczas produkcji. Twój produkcyjny serwer internetowy (jak nginx) powinien się tym zająć.

Johnny Zhao
źródło
1
Brzmi interesująco, ale nie działało dla mnie, po prostu dodając tę ​​linię do wgsi.pypliku. Dokumentacja, którą dowiązałeś, wydaje się zawierać inne instrukcje dotyczące korzystania z WhiteNoise. Spróbuję innych sposobów i zaktualizuję cię tutaj.
DarkCygnus,
+1, ponieważ to ostatecznie doprowadziło mnie do rozwiązania. Dodałem odpowiedź, w której zawarłem dodatkowe kroki, które podjąłem, aby faktycznie to działało.
DarkCygnus,
manage.py runserver --insecurenie działało dla mnie. Ten jednak ma.
Jee
3
Pamiętaj, że w wersji 4.0 WhiteNoise konfiguracja uległa zmianie. Nie dodawaj tych wierszy do pliku wsgi.py. Zamiast tego po prostu dodaj 'whitenoise.middleware.WhiteNoiseMiddleware'do oprogramowania pośredniego. Zobacz informacje o wydaniu dziennika zmian
Doug Harris
Dlaczego * nie jest zalecane? Używam go od lat w kilku witrynach, działa świetnie. Nawet Heroku używa go w szablonie Django.
Omar Gonzalez
33

W urls.py dodałem tę linię:

from django.views.static import serve 

dodaj te dwa adresy URL w urlpatterns:

url(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}), 
url(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}), 

a zarówno statyczne, jak i multimedialne pliki były dostępne, gdy DEBUG = FAŁSZ.
Mam nadzieję, że to pomoże :)

Stathoula
źródło
Po zakończeniu css panel administracyjny nie ładuje się ??
Takitha Deepal
Tak. Jedyny, który działa !! dzięki.
DrGeneral
NIESAMOWITE! Nie zapomnij ustawić STATIC_ROOT i manage.py collectstatic.
DomingoR,
2
Obecnie wymienić url(zre_path(
Leopd
19

Jeśli używasz statycznego widoku udostępniania w fazie projektowania, musisz mieć DEBUG = True:

Ostrzeżenie

Działa to tylko wtedy, gdy DEBUG jest Prawdą.

Jest tak, ponieważ ten pogląd jest rażąco nieefektywny i prawdopodobnie niepewny. Jest to przeznaczone wyłącznie na rozwój lokalny i nigdy nie powinno być wykorzystywane w produkcji.

Dokumenty: serwowanie plików statycznych w programistyce

EDYCJA: Możesz dodać kilka adresów URL tylko w celu przetestowania szablonów 404 i 500, po prostu użyj ogólnego widoku direct_to_template w swoich adresach URL.

from django.views.generic.simple import direct_to_template

urlpatterns = patterns('',
    ('^404testing/$', direct_to_template, {'template': '404.html'})
)
j_syk
źródło
1
W jaki sposób można następnie obsłużyć pliki statyczne podczas produkcji? NVM, właśnie to widziałem. Dzięki.
skonfigurowałbyś swój serwer WWW do obsługi określonego katalogu. Najczęściej będziesz używać Apache lub Nginx. Dokumenty trochę w to zagłębiają.
j_syk
dzięki @j_syk, już wypróbowałem to podejście do przeglądania 404.html i 500.html za pomocą innego mechanizmu niezwiązanego z błędami podobnego do tego, co sugerujesz. Chciałem jednak wiedzieć, czy nie jest możliwe, aby moje strony renderowały się poprawnie tak, jak w środowisku produkcyjnym, a jednocześnie działały tylko na moim serwerze testowym - delegowanie obsługi plików statycznych do Apache, gdy Debugowanie jest wyłączone, rozwiązuje to dla mnie. Dziękuję za pomoc.
nemesisfixx
@mcnemesis Nie jestem pewien, co się stanie, ale spróbuj ustawić TEMPLATE_DEBUG = Fałsz, a DEBUG = Prawda. Jeśli wyłączysz ładne błędy, nie jestem pewien, czy zamiast tego trafi do szablonów
404/500
zgodnie z oczekiwaniami, zrobienie tego nie przyniosło żadnych pozytywnych rezultatów, ale wciąż dzięki.
nemesisfixx
17

Odpowiedź Johnny'ego jest świetna, ale nadal nie działała dla mnie po prostu poprzez dodanie linii tam opisanych. W oparciu o tę odpowiedź kroki, które faktycznie dla mnie zadziałały, gdzie:

  1. Zainstaluj WhiteNoise zgodnie z opisem:

    pip install WhiteNoise
  2. Utwórz STATIC_ROOTzmienną i dodaj WhiteNoise do swojej MIDDLEWAREzmiennej w settings.py:

    #settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware', #add whitenoise
        'django.contrib.sessions.middleware.SessionMiddleware',
        ...
    ]
    
    #...
    
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') ##specify static root
  3. Następnie zmodyfikuj wsgi.pyplik zgodnie z wyjaśnieniem w odpowiedzi Johnny'ego:

    #wsgi.py
    from django.core.wsgi import get_wsgi_application
    from whitenoise.django import DjangoWhiteNoise
    
    application = get_wsgi_application()
    application = DjangoWhiteNoise(application)
  4. Następnie wdróż zmiany na serwerze (za pomocą git lub cokolwiek, którego używasz).

  5. Na koniec uruchom tę collectstaticopcję manage.pyna swoim serwerze. Spowoduje to skopiowanie wszystkich plików z folderów statycznych do STATIC_ROOTokreślonego wcześniej katalogu:

    $ python manage.py collectstatic

    Zobaczysz teraz nowy folder o nazwie staticfileszawierającej takie elementy.

Po wykonaniu tych kroków możesz teraz uruchomić swój serwer i będziesz mógł zobaczyć swoje pliki statyczne w trybie produkcyjnym.

Aktualizacja: W przypadku, gdy miał wersję <4 changelog wskazuje, że nie jest już konieczne, aby zadeklarować WSGI_APPLICATION = 'projectName.wsgi.application'na settings.pypliku.

DarkCygnus
źródło
Zrobiłem to odpowiednio i przy rozwoju działało dobrze, ale nie w produkcji. Nadal mam ten sam problem, gdy DEBUG == False
Anna Huang
@AnnaHuang Co rozumiesz przez rozwój i produkcję? Czy masz oddzielne środowiska lub maszyny? Czy są skonfigurowane w ten sam sposób?
DarkCygnus,
13

W rzeczywistości możesz obsługiwać pliki statyczne w produkcyjnej aplikacji Django, bezpiecznie i bez DEBUG=True .

Zamiast używać samego Django, użyj dj_static w pliku WSGI ( github ):

# requirements.txt:

...
dj-static==0.0.6


# YOURAPP/settings.py:

...
STATIC_ROOT = 'staticdir'
STATIC_URL = '/staticpath/'

# YOURAPP/wsgi.py:

...
from django.core.wsgi import get_wsgi_application
from dj_static import Cling

application = Cling(get_wsgi_application())
Robin Winslow
źródło
2
Od tego czasu odkryłem whitenoise , który może być bardziej w pełni funkcjonalny.
Robin Winslow,
7

Po prostu otwórz projekt urls.py, a następnie znajdź tę instrukcję if.

if settings.DEBUG:
    urlpatterns += patterns(
        'django.views.static',
        (r'^media/(?P<path>.*)','serve',{'document_root': settings.MEDIA_ROOT}), )

Możesz zmienić ustawienia. DEBUG na True i zawsze będzie działać. Ale jeśli twój projekt jest czymś poważnym, powinieneś pomyśleć o innych rozwiązaniach wymienionych powyżej.

if True:
    urlpatterns += patterns(
        'django.views.static',
        (r'^media/(?P<path>.*)','serve',{'document_root': settings.MEDIA_ROOT}), )

W django 1.10 możesz napisać:

urlpatterns += [ url(r'^media/(?P<path>.*)$', serve, { 'document_root': settings.MEDIA_ROOT, }), url(r'^static/(?P<path>.*)$', serve, { 'document_root': settings.STATIC_ROOT }), ]
Siergiej Łuczko
źródło
3
Twój kod jest poprawny, ale w Django 1.10 konfiguracja jest dla mediów, a statyczna to: urlpatterns + = [url (r '^ media / (? P <ścieżka>. *) $', Serw, {'document_root': ustawienia .MEDIA_ROOT,}), url (r '^ static / (? P <path>. *) $', Służyć, {'document_root': settings.STATIC_ROOT}),]
Roberth Solís
6

Możesz to debugować na wiele różnych sposobów. Oto moje podejście.

localsettings.py:

DEBUG = False
DEBUG404 = True

urls.py:

from django.conf import settings
import os

if settings.DEBUG404:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', 'django.views.static.serve',
         {'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
    )

Przeczytaj dokumenty;)

https://docs.djangoproject.com/en/2.0/howto/static-files/#limiting-use-to-debug-true

Conrado
źródło
0

Obsługa argumentów widoku łańcucha dla url () jest przestarzała i zostanie usunięta w Django 1.10

Moje rozwiązanie to tylko niewielka korekta powyższego rozwiązania Conrado.

from django.conf import settings
import os
from django.views.static import serve as staticserve

if settings.DEBUG404:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', staticserve,
            {'document_root': os.path.join(os.path.dirname(__file__), 'static')} ),
        )
be_good_do_good
źródło
0

Chociaż nie jest to najbezpieczniejsze, ale możesz zmienić kod źródłowy. nawigować doPython/2.7/site-packages/django/conf/urls/static.py

Następnie edytuj w następujący sposób:

if settings.DEBUG or (prefix and '://' in prefix):

Więc jeśli settings.debug==Falsenie wpłynie to na kod, również po uruchomieniu spróbujpython manage.py runserver --runserver uruchomić pliki statyczne.

UWAGA : Informacje należy wykorzystywać wyłącznie do testowania

Natuto
źródło
0

Wprowadziłem następujące zmiany w moim projekcie / urls.py i zadziałało to dla mnie

Dodaj tę linię: z adresu importu django.conf.urls

i dodaj: url (r '^ media / (? P. *) $', obsłuż, {'document_root': settings.MEDIA_ROOT,}), w urlpatterns.

Namrata Sharma
źródło