1 Ekim 2008 Çarşamba

Django Şablonları İçin Özel Etiketler

Django Şablonları İçin Özel Etiketler

İçeriğinde forum, günlük, anket vb. uygulamaların olduğu bir projeniz olduğunu düşünün. Ve siz forum uygulamasındaki son eklenen konuları, günlük uygulaması içerisinde kullanmak istiyorsunuz. Bu durumda ne yaparsınız? Günlük uygulamasının views.py dosyası içerisinden forum uygulaması tablosuna bağlanarak son eklenen konuları almazsınız umarım. Çünkü Django şablon dosyaları içerisinde, kendi yazdığımız etiketleri kullanabiliyoruz. Bu yazıda şablon dosyaları için uygulamanıza özel etiketleri nasıl oluşturacağınızı göstermeye çalışacağım.


İlk olarak projemizi ve uygulamamızı oluşturalım. Oluşturacağımız templates klasörü şablon dosyalarımızı, templatetags klasörü ise özel etiketlerimizle ilgili dosyaları içerisinde barındıracak.



$ djangoadmin.py startproject mysite
$ cd mysite
$ python manage.py startapp ozeletiketler
$ mkdir ozeletiketler/templates ozeletiketler/templatetags


Ardından settings.py dosyamızdaki TEMPLATE_DIRS ve INSTALLED_APPS ayarlarını düzenleyelim. Burada şablon dosyaları için proje dizinimizi hedef gösterdik. Bu şekilde Django, uygulamalarımızın altında bulunan templates ve templatetags klasörlerini tanıyabilecektir.




TEMPLATE_DIRS = (
[...]
'/home/omer/django-projects/mysite'
[...]
)


INSTALLED_APPS = (
[...]
'mysite.ozeletiketler'
)


Şimdide urls.py dosyamızı düzenleyelim.

urlpatterns = patterns('',
[...]
(r'^ozeletiketler/','mysite.ozeletiketler.views.index'),
[...]
)


Bu yaptığımız değişiklikleri test etmek için ozeletiketler uygulaması içindeki views.py dosyasını aşağıdaki gibi düzenliyor ve ardından templates klasöründe index.html dosyasını oluşturup tarayıcıda boş sayfa(ya da içine bir şeyler yazdıysanız onların) çıkıp çıkmadığını kontrol ediyoruz.



#-*- coding: utf-8 -*-
from django.shortcuts import render_to_response

def index(request):
return render_to_response('ozeletiketler/templates/index.html',{})
return render_to_response('index.html',{})


Boş sayfayı gördük, işler yolunda. Bir sonraki aşamaya geçelim. templatetags klasörü altında __init__.py ve ozeletiketler.py adlı dosyaları oluşturalım. __init__.py dosyası içeriği boş kalırken, ozeletiketler.py dosyası içeriği aşağıdaki şekilde olmalı.



#-*- coding: utf-8 -*-
from django.template import Library,Node

register = Library()

def beniyaz(veri):
return veri
register.simple_tag(beniyaz)


class IslemNode(Node):
def __init__(self,nodelist,bits):
self.nodelist = nodelist
self.bits = bits

def render(self,context):
islem = self.nodelist.render(context)
sonuc = eval(islem)
if self.bits.__len__()>1:
if self.bits[1] == 'sadece_sonuc':
return sonuc
return u"Yapılan İşlem %s : %s" %(islem,sonuc)

def islem(parser,token):
nodelist = parser.parse(('islembitti',))
parser.delete_first_token()
bits = token.contents.split(' ')
return IslemNode(nodelist,bits)
register.tag(islem)


Şimdi bu oluşturduğumuz özel etiketlerimizi şablon dosyamız içerisinde (önceden oluşturmuştuk: index.html) kullanalım.

{% load ozeletiketler %}

{% beniyaz "merhaba dünya" %}


{% islem %} 20 + 5 {% islembitti %}


{% islem sadece_sonuc %} 11 - 4 {% islembitti %}


Bu işlemin ardından http://127.0.0.1:8000/ozeletiketler/ adresini ziyaret ettiğinizde aşağıdaki çıktı ile karşılaşacaksınız:



Son olarak yapılan işlemlerle ilgili bazı konulara açıklık getirelim.

Ozeletiketler.py Dosyası

Library ve Node sınıflarını dahil ettik. Etiketleri kaydetmek için register değişkenine Library sınıfını atadık. Library sınıfı etiketleri şablon dosyaları içerisinde kullanabilmek için kaydetmemizi sağlar. Node sınıfı ise etiketlerin kullanılması ile gelen veriyi yorumlayıp geri döndürmeyi sağlar.

#-*- coding: utf-8 -*-
from django.template import Library,Node

register = Library()


Gelen veriyi geri döndüren basit bir etiket oluşturduk. Ardından register değişkenini kullanarak etiketi kaydettik. register değişkenine Library sınıfını atamıştık. simple_tag Library sınıfının bir fonksiyonudur.

def beniyaz(veri):
return veri
register.simple_tag(beniyaz)


Daha gelişmiş bir etiket oluşturduk ve bunu register.tag ile (tag Library sınıfının bir fonksiyonudur) kaydettik. islem fonksiyonu içerisinde ise nodelist değişkenine etiketin ilk ve son kısımları arasındaki içeriği aldık. Etiketimizin bitiş kısmını burada islembitti değeri ile belirledik. Yani {% islem %} ... {% islembitti %} arasındaki içerik bu etiketin alanı olacak. bits değişkenine de etiket açılışında tanımlanan verileri aktardık ( örn: {% etiket_adi veri1 veri2 ...% } deki veri1, veri2 vb. değerleri). Ardından bu değişkenleri(nodelist,bits), işlenip geri dönmesi için IslemNode sınıfına aktardık.

def islem(parser,token):
nodelist = parser.parse(('islembitti',))
parser.delete_first_token()
bits = token.contents.split(' ')
return IslemNode(nodelist,bits)
register.tag(islem)


Eğer oluşturmuş olduğumuz islem etiketi şablon dosyasında kullanılırsa, bu etiketin yorumlanması sırasında IslemNode sınıfı içerisindeki render fonksiyonu devreye girecektir. Bu fonksiyon devreye girdiğinde, önce {% islem %} {% islembitti %} arasındaki verileri yorumlayacak, ardından bunu icerik değişkenine aktaracak. islem etiketi ile gelen verilere göre(bits) kontrol yapılıp geriye sonucu döndürecektir.

Tabi bu bizim aşağıdaki sınıf için geçerli. Siz render fonksiyonu içerisinde kendi etiketinize göre işlemleri yaptırmalısınız. Bilmeniz gereken render fonksiyonu içerisinde bulunan self.nodelist.render(context) ile etiketinizin içeriğinin görüntülenebilir halini alabilmenizdir.

class IslemNode(Node):
def __init__(self,nodelist,bits):
self.nodelist = nodelist
self.bits = bits

def render(self,context):
icerik = self.nodelist.render(context)
sonuc = eval(icerik)
if self.bits.__len__()>1:
if self.bits[1] == 'sadece_sonuc':
return sonuc
return u"Yapılan İşlem %s : %s" %(icerik,sonuc)


Index.html Dosyası

Yazdığımız ozeletiketler.py dosyamızı şablon dosyası içerisine dahil ettik. Böylelikle bu dosya içerisindeki özel etiketleri kullanabildik. Buradaki ozeletiketler dosyamızın ismidir. templatetags içerisinde dosyaları herhangi bir isimde oluşturabilirsiniz. load ile kullanım sırasında ise oluşturduğunuz dosya ismini belirtmelisiniz.

{% load ozeletiketler %}


beniyaz isimli etikete bir değer vererek, değeri ekrana yazdırdık.

{% beniyaz "merhaba dünya" %}


İşlemin, açıklamalı olarak ekrana yazdırılmasını sağladık.

{% islem %} 20 + 5 {% islembitti %}


İşlemin sadece sonucunun ekrana yazdırılmasını sağladık.

{% islem sadece_sonuc %} 11 - 4 {% islembitti %}


Açıklamalar belki kafa karıştırıcı olabilir. Bunu en aza indirmeye çalıştım. Aklınıza bir kaç soru gelebilir. Belki bunları tahmin edebilirim düşüncesiyle kendi kendime bir kaç soru sorup cevaplarını vermeye çalışacağım.

1 - Etiket isimlerini nasıl belirliyoruz?
Etiket ismi, özel etiket dosyanızda belirlediğiniz fonksiyon ismidir. Eğer farklı bir isim kullanmak isterseniz register.tag fonksiyonunu aşağıdaki gibi kullanmalısınız. register.simple_tag için böyle bir özellik bulunmuyor.


register.tag("yeni_etiket_adi",fonksiyon_adi)


2 - Etiket açılışında tanımlanan verileri ayırma işlemini ne şekilde yapabilirim?

Bu işlemi token.contents.split(' ') bölümünden gerçekleştirebilirsiniz. Örneğin boşluk yerine tırnak ile verileri ayırmak isteyebilirsiniz. Bunun için aşağıdaki gibi bir kullanım işinizi görecektir.


def islem(parser,token):
[...]
bits = token.contents.split('\"')
[...]



[...]
{% islem "sadece_sonuc" ... %}
[...]


3 - Daha fazlası için?

django/template/defaulttags.py dosyasını inceleyebilirsiniz.

2 yorum:

  1. çok güzel bir anlatım olmuş. Öznitelikler uygulamasının içindeki views.py dosyasında "index.html" sayfasının yolu ('ozeletiketler/templates/index.html',{})
    değilde;
    ('index.html',{})
    olması gerekiyor galiba.

    YanıtlaSil
  2. Evet o şekilde oluyormuş ve TEMPLATE_DIRS ile ilgili bir ayar yapmayada gerek yokmuş.

    Teşekkürler yorum için, düzenlemeleri yaptım yazıda.

    YanıtlaSil