Django Static Files

Static files

Merhaba, Django framework’ü ile web uygulaması geliştirirken font, CSS ve Javascript dosyaları gibi birçok static dosya kullanmaktayız. Django ortalama 15 senedir durmadan geliştirildiğinden ve piyasa tarafından oldukça benimsendiğinden static dosyaların projelerde kullanışı oldukça yaygın. Şimdi isterseniz static dosyaların local’de nasıl kullanıldığını, ve ardından projeyi production’a alırken ne gibi ayarlamalar yapıldığına birlikte atalım.

Local üzerinde

Normal bir Django projesinde birden fazla application oluşturulmaktadır. Her bir app static dosya kullanılacağı zaman, Django ilgili app’in içerisinde static dizinden gerekli dosyaları bulur ve kullanır. Hâlbuki çoğu Django projesinde bütün app’lerin ortak kullanması gereken bazı static dosyalar da bulunabilir. Böyle bir durum için en üst dizinde static isimli bir klasör oluşturulur. Aşağıdaki kodla en üst dizinde bir static dizinini oluşturduğumuzu varsayalım:

$ mkdir static

Proje oluşturulduğunda settings.py içerisinde STATIC_URL değişkenine otomatik olarak atanmış şöyle bir değer bulunmaktadır:

# settings.py
STATIC_URL = '/static/'

Bu değer, static dosyaların http://127.0.0.1:8000/static/ veya http://localhost:8000/static/ adresinde bulunduğunu ifade etmektedir. Oluşturduğumuz static dizine Django’nun ulaşabilmesi için aşağıdaki yeni satırı settings.py dosyasına dâhil etmeliyiz. Bu değişken list türünde olduğundan içerisine birden fazla dizin yolu yazabilirsiniz. Ben daha önceden oluşturduğum static dizinini ekleyeceğim:

# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),) # yeni satır

Ardından oluşturduğumuz static dizini içerisine css, js ve img dizinlerini de oluşturarak içerisine ilgili dosyalar yerleştirebiliriz.

$ mkdir static/css
$ mkdir static/js
$ mkdir static/img

Ardından bu dosyaları hemen iki adımda html template’leri içerisinde şu şekilde kullanabilirsiniz.

  1. Template dosyasının en tepesine {% load static %} konulur
  2. Ardından template içerisinde gerekli yerde {% static %} tag’i içerisinde ilgili dosya linki belirtilir

Örneğin base.html içerisinde base.css dosyasının kullanılışı şu şekilde olmaktadır:

<!-- templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html>
<head>
  <title>Learn Django</title>
  <link rel="stylesheet" href="{% static 'css/base.css' %}">
</head>
<body>
..
<img src="{% static 'img/path_to_img' %}">
..
<script src="{% static 'js/base.js' }"></script>
</body>
</html>

collectstatic

Local Django serveri üzerinde static dosyaların kullanılması yukarıda gösterildiği gibi olacaktır, ancak Gunicorn veya uWSGI gibi server’lar üzerinde static dosyaların kullanılması bu şekilde olmamaktadır. Bu server’lar üzerinde static dosyaları kullanabilmek için collectstatic dediğimiz komutu kullanarak tüm static dosyalar tek bir dizin içerisine toplarız. Bu dizinin yolu settings.py içerisinde STATIC_ROOT değişkenine atanır (aşağıdaki kodda staticfiles olarak belirtilmiştir). collectstatic komutu çalıştırıldığında STATICFILES_STORAGE isimli dosya motoru kullanılarak tüm static dosyalar belirtilen STATIC_ROOT dizinine toplanır ve dosyalar production ortamına hazır hâle gelmiş olurlar.

Özetle python manage.py collectstatic her çalıştırıldığında aşağıdaki dört değişken kullanılmaktadır. staticfiles isimli bir klasör oluşturularak dosyalar bu dizinin içerisine alınır. Static dizinine yeni bir dosya eklendiğinde tekrar bu komutun çalıştrılması gerekmektedir, bu yüzden projelerin deployment pipeline’ına dâhil edilir; örneğin bu işlem Heroku’da otomatik yapılmaktadır.

# settings.py 
STATIC_URL = '/static/' 
STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),) # yeni satır
STATIC_ROOT = str(BASE_DIR.joinpath('staticfiles')) # yeni satır
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'  # yeni satır

Not 1: staticfiles dosyası oluşturulduğunda içerisinde admin için gerekli olan static dosyaları da admin dizini içerisine konur
Not 2: STATIC_ROOT değişkeni sadece deployment ortamı için geçerlidir, development için yazmaya gerek yok çünkü Django oluşturulan her app içerisinde static dizinini zaten arayacaktır.

Production üzerinde

Projenin static dosyalarını production ortamına hazır hâle getirebilmek için son bir ayar daha yapmamız gerekmektedir. WhiteNoise isimli kütüphaneyi projemize dâhil etmemiz gerekmektedir. İlk olarak pip komutuyla kütüphaneyi environment içerisine dâhil edelim:

(venv) $ pipenv install whitenoise

Ardından settings.py içerisinde aşağıdaki değişiklikleri yaparak kütüphaneyi projeye katalım:

  • INSTALLED_APPS içerisinde staticfiles’ın üstünde olacak şekilde herhangi bir yere whitenoise’i ekleyin
  • MIDDLEWARE içerisine ikinci satıra WhiteNoiseMiddleware ekleyin
  • STATICFILES_STORAGE ayarını WhiteNoise şeklinde değiştirin
# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'whitenoise.runserver_nostatic',   # ekleyin
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',   # ekleyin
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

...

STATIC_URL = '/static/'
STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),)
STATIC_ROOT = str(BASE_DIR.joinpath('staticfiles')) 
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'   # değiştirin

Son olarak collectstatic komutunu tekrar çalıştırıp ardından deployment edebilirsiniz.

Kaynak:
https://learndjango.com/tutorials/django-static-files
https://help.pythonanywhere.com/pages/DjangoStaticFiles/