Dotąd w zasadzie nie zastanawiałem się nad sposobem konfiguracji Apache'a w Django, stosowałem po prostu przepis z dokumentacji. Że zastanowić się warto, uświadomił mi kolega Jakub.
Zwrócił mi on uwagę, że roboty wyszukujące spodziewają się często znaleźć plik favicon.ico w głównym katalogu czyli DocumentRoot witryny.
Zastanówmy się się więc punkt po punkcie nad przepisem ze wspomnianej dokumentacji. Zakładam, że mamy porawnie zainstalowanego apache'a i mod-pythona (jeśli nie, to tu jest instrukcja po polsku jak to zrobic pod ubuntu).
W dokumentacji Django znajdziemy mniej więcej następujący przykład:
<Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonPath "['/path/to/project'] + sys.path" </Location> <Location "/media"> SetHandler None </Location> <LocationMatch "\.(jpg|gif|png|ico)$"> SetHandler None </LocationMatch>
Przede wszystkim ktoś może zapytać gdzie ten kod umieścić. Możliwe jest to nawet w plikach .htaccess, ale nie polecam tego rozwiązania, choć kiedyś je z powodzeniem stosowałem. Obecnie jednak serwery VPS są już tak tanie, że nie widzę potrzeby męczenia się z jakimś dzielonym hostingiem. Tak więc możemy umieścić ten kod albo w /etc/apache2/sites-available/default (tak jest standardowo), albo jeśli mamy większą ilość projektów i chcemy zachowac porządek, możemy tworzyć dodatkowe pliki apache'a.
Najczęściej będziemy używali virtualhosta, czyli we wspomnianym pliku default napiszemy:
<VirtualHost *:80> ServerName jakas.tam.domena.com # w tym miejscu wstawiamy cały kod, który przytoczyłem powyżej </VirtualHost>
SetEnv DJANGO_SETTINGS_MODULE settings
PythonPath "['/path/to/project'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE app.settings
Dalej mamy
<Location "/media"> SetHandler None </Location>
oraz
<LocationMatch "\.(jpg|gif|png|ico)$"> SetHandler None </LocationMatch>
Te elementy w moim przekonaniu nie są w dokumentacji Django opisane wystarczająco jasno. Jest tak zapewne dlatego, że twórcy dokumentacji Django założyli, że czytelnik umie konfigurować Apache'a...
I to jest właśnie moment, od którego rozpocząłem i ku któremu zmierzam.
Jeśli ktoś konfigurację Apache'a zna, to zauważył na pewno, że w konfiguracji tego virtualhosta w ogóle nie ma dyrektywy DocumentRoot, a mimo to taka konfiguracja działa, z wyjątkiem... no właśnie: z wyjątkiem plików statycznych, bez których żaden serwis nie może przecież funkcjonować! Plikami statycznymi są przede wszystkim arkusze stylów i obrazki, mogą jednak być nimi inne pliki specyficzne dla danego serwisu - np. dokumenty pdf.
Żeby udostępniać pliki statyczne, trzeba wybrać katalog na dysku, który będzie je przechowywał (oczywiście może on zawierać podkatalogi). Załóżmy, że ten katalog, to /var/www/jakas.tam.domena.com (można wybrac dowolny katalog).
Przed znacznikiem wstawmy linię
Alias /media "/var/www/jakas.tam.domena.com"
Teraz już serwer wie skąd brać statykę - żądanie http://jakas.tam.domena.com/media będzie skierowane do katalogu /var/www/jakas.tam.domena.com. Do tego zdaje się zmierzać dokumentacja Django.
Wydaje się, że wszystko jest ok. Tym bardziej, że znacznik <LocationMatch "\.(jpg|gif|png|ico)$">
,
wraz z dyrektywą SetHandler None
powinien nam zapewnić, że nawet jeśli w głównym katalogu serwisu pojawi się jakiś obrazek, powiedzmy logo.jpg, to zostanie on poprawnie wyświetlony... Opsss! Zaraz! W głównym katalogu? A gdzie tu jest główny katalog?
No właśnie. Nie ma. Nie istnieje!
Dlatego ja jestem za utworzeniem dyrektywy:
DocumentRoot /var/www/jakas.tam.domena.com/
Wtedy wystarczy w katalogu /var/www/jakas.tam.domena.com/ utworzyć podkatalog media. Tworzenie aliasu nie jest nam potrzebne, a z katalogu głównego możemy np udostępniać plik favicon.ico ku radości tych co lubią robić dobrze robotom ;)
Całość konfiguracji wygląda ostatecznie tak:
<VirtualHost *:80> ServerName jakas.tam.domena.com DocumentRoot /var/www/jakas.tam.domena.com/ <Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE mysite.settings PythonPath "['/path/to/project'] + sys.path" </Location> <Location "/media"> SetHandler None </Location> <LocationMatch "\.(jpg|gif|png|ico)$"> SetHandler None </LocationMatch> </VirtualHost>
Odpowiedzi
Pączkowanie...
Sprawa miała być pierwotnie banalna, ale widzę, że trzeba było się trochę natrudzić.
Przy okazji jest oczywiście sporo dodatkowych zastosowań umieszczania obiektów (plików) w katalogu głównym (np. pliki weryfikacji wyszukiwarek - nie każdy lubi zaśmiecać kod strony dodatkowymi tagami meta).