Django ile hazırladığınız projenizde bütün view'larda kullanmak (şablonlara göndermek) istediğiniz değişkenler olabilir. Django'da bunu sağlayan mekanizmaya context processors deniyor.

Örneğin bir blog projeniz varsa ve yazı etiketlerini (Tags), listelemek üzere tüm sayfalarda göstermek istiyorsanız, bütün view'lar içinde tek tek yazı etiketlerini çekip şablona (template) göndermek yerine context processor kullanmalısınız.

Context Nedir?

Context, anahtar - değer şeklinde değer tutan bir değişken, yani aslında bildiğimiz dictionary. Bir context'i template'e gönderdiğimizde anahtarlar (keys) değişkene dönüşüp, değerler (values) de bu değişkenlerin değerleri haline geliyorlar.

Ardından gönderdiğimiz değişkenleri şablonlar içerisinde {{ degisken_adi }} şeklinde gösterebiliyoruz. Django şablon motoru bizim için bu notasyonu değişkenlerin gerçek değerleriyle dolduruyor.

Örneğin aşağıdaki gibi bir anasayfamız varsa:


from django.shortcuts import render


def home(request):
    context = {
        'name': 'Umut',
        'language': 'Türkçe',
    }
    return render(request, 'home.html', context)

Gönderdiğimiz değişkenleri home.html içinde aşağıdaki gibi gösterebiliriz:


Merhaba, benim adım {{ name }} ve benim anadilim {{ language }}.

Muhtemelen çoğunuzun bildiği bu konuyu kısaca açıkladıktan sonra asıl konumuza dönebiliriz sanırım.

Context Processor Nedir?

İçerik işleyiciler, (context processors'u içerik işleyiciler olarak çevirip çevirmeme konusunda çok kararsız kaldım) context şablona döndürülmeden önce araya girerler ve kendi döndürdükleri context'i, kullanıcının (bu durumda geliştirici) döndürdüğü context ile birleştirirler.

Bu da demektir ki, her zaman döndüreceğiniz değişkenler için bir context processor oluşturarak, her defasında aynı değeri context içine eklemekle uğraşmamıza gerek kalmıyor.

Örneğin; settings.py dosyanızda varsayılan olarak gelen request içerik işleyicisi, view içindeki request nesnesine şablonlar içinden erişebilmenize olanak veriyor.


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
            ],
        },
    },
]

Eğer yazdığınız bir içerik işleyiciyi çalışır hale getirmek istiyorsanız settings.py içindeki yukarıdaki bölümdeki context_processors içine eklemelisiniz.

Şimdi sıra geldi kendi içerik işleyicimizi yazmaya. Hangi uygulamada kullanmak istiyorsanız* o uygulama içine context_processors.py oluşturun.

* Tabii ki, içerik işleyiciler içinden farklı uygulamalara erişebilirsiniz. Ancak projenin hiyerarşik bütünlüğü açısından, hangi uygulama içinde kullanacaksanız orada oluşturmanızı öneriyorum.

İçerik işleyiciler esasında bir fonksiyondan ibarettirler. Parametre olarak request nesnesini alırlar ve geriye, şablona gönderilmek istenen veriyi dictionary olarak döndürürler.

Örneğin aşağıda, settings.py içinden aldığı değerleri şablonlara gönderen bir içerik işleyici görüyorsunuz.


from django.conf import settings


def constants(request):
    return {
        'BASE_TITLE': settings.BASE_TITLE,
        'BASE_URL': settings.BASE_URL,
    }

Bu içerik işleyicinin ismi constants ve şablonlarda kullanılmak üzere site ana başlığı (BASE_TITLE) ve sitenin kök adresini (BASE_URL) döndürüyor.

Elbette, bu içerik işleyiciyi aktif hale getirmek için settings.py içine eklememiz gerekiyor.


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                # ...
                'blog.context_processors.constants',
            ],
        },
    },
]

Benim uygulamamın adı blog olduğu için böyle ekledim. Sizin de oradaki ismi kendi uygulamanızla değiştirmeniz gerekiyor.

Şimdi, başka bir örnek yapacağız ve yazının ilk başında bahsettiğim gibi, yazı etiketlerinin (Tags) tüm şablonlardan erişilebilir olmasını sağlayacağız.


from blog.models import Tag


def tags(request):
    published_tags = Tag.objects\
        .filter(is_published=True, posts__is_published=True)\
        .exclude(posts=None)\
        .order_by('name')\
        .distinct()
    return {'tags': published_tags}

Tag modelimde Post modelime bir back reference var. Yani Post modelimde, bir ManyToManyField var ve bu alan Tag modeline bağlı. Tag modelinin posts özelliği ile ona bağlı blog yazılarını görebiliyorum.

Yukarıdaki sorguda, tüm etiketler içinden, yayınlanmış olanları ve posts özelliği boş olmayanları name(etiket ismi) alanına göre sıralayıp çekiyorum. Etiket içindeki posts alanına çekilecek yazıların da yayınlanmış olma şartını koyuyorum. Son olarak distinct ile aynı etiketin, içindeki yazı sayısına bağlı olarak birden fazla defa gelmesini engelliyorum.

Ardından, bir öncekinde olduğu gibi yazdığım fonksiyonu settings.py içine eklemeliyim.


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
            	# ...
                'blog.context_processors.constants',
                'blog.context_processors.tags',
            ],
        },
    },
]

Şablon içinde ise çektiğim verileri normal şekilde view'dan döndürmüş gibi yazdırıyorum.


<div class="article-list">
<ul>
  {% for tag in tags %}
    <h1>{{ tag.name }}</h1>
    {% for post in tag.posts.all %}
      <li>
        <a href="{{ BASE_URL }}{{ post.get_absolute_url }}">
          {{ post.title }}
        </a>
      </li>
    {% endfor %}
  {% endfor %}
</ul>
</div>

İşte hepsi bu kadar. Django'da varsayılan olarak gelen içerik işleyicileri incelemek için -ki şiddetle öneririm-buraya tıklayabilirsiniz.

Kolay gelsin. :)