templates etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
templates etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

9 Mayıs 2009 Cumartesi

Google App Engine İçin Özel Şablon Yardımcıları

GAE ile bir uygulama geliştirirken şablon kısmında ekrana yazılan değeri biçimlendirmem gerekti. Bu konuyla alakalı daha önce Django için bir yazı yazmıştım. Google App Engine de ise durum Django dan biraz farklıymış. Özel şablon yardımcıları oluşturmak için ilk olarak ana dizinde ya da herhangi bir dizinde bir dosya oluşturuyoruz. Örneğin ana dizinde customfilters.py adında bir dosya oluşturalım:

Dosyaya öncelikle webapp modülünü dahil ediyoruz:

#-*- coding: utf-8 -*-
from google.appengine.ext import webapp


Ardından fonksiyonlarımızı şablon içinde kullanabilmemizi sağlayan kaydediciyi oluşturuyoruz.

register = webapp.template.create_template_register()


Sonrada fonksiyonumuzu yazıyoruz. Fonksiyon gelen bağlantıdaki boşlukları - karakteri ile değiştirip geriye sonucu döndürüyor.

def escape_url(url):
return url.replace(' ','-')


Son olarakta oluşturduğumuz fonksiyonu kaydediyoruz.

register.filter(escape_url)


Şimdi customfilters.py dosyamızı projemize tanıtmamız gerekiyor. Bunun içinde main fonksiyonunun içine aşağıdaki kodları ekliyoruz:

def main():
webapp.template.register_template_library('customfilters')
run_wsgi_app(application)

if __name__ == "__main__":
main()


Bu sayede customfilters.py dosyamızı projemize tanıtmış oluyoruz. Bu tanıtım işlemi ile birlikte artık escape_url yardımcısını şablon içerisinde kullanabilirsiniz:

<a href="/book/{{ data.name|escape_url }}/{{ data.key }}">{{ data.name }}</a>


register.filter ile fonksiyonumuzu yardımcı bir filtre olarak tanımladık. Eğer fonksiyonu bir etiket ile kullanmak istersek aşağıdaki yöntem işimizi görecektir. Bu yöntem için farklı bir fonksiyon geliştirelim. Mesela gelen parametreleri kullanıp geriye img kodunu göndersin:

def create_image(image,alt):
return '<img src="/media/images/%s" alt="%s" />' %(image,alt)

register.simple_tag(create_image)


register.simple_tag ile kaydettiğimiz fonksiyonumuzun şablon dosyasındaki kullanımı ise şöyle olmalı:

{% create_image "sample.png" "Örnek Açıklama" %}

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.

29 Eylül 2008 Pazartesi

Django ile Anket 3

Bundan önceki uygulamarımızda anket oluşturmak, düzenlemek ve yeni seçenekler eklemek gibi bir takım ayarları yapmayı öğrenmiştik. Ama bunları sadece admin paneli üzerinden yapıyorduk. Peki bu anketleri nasıl sayfamızda gösterebiliriz ?

Anketleri sayfamızda gösterebilmemiz için anket uygulaması içerisinde yer alan view.py dosyasında bir takım düzenlemeler yapmamız gerekiyor. View.py dosyasının içeriğini şu hale getirelim.

from django.template import Context, loader
from OrnekProje.anket.models import Anket
from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404

def index(request):
son_anketler = Anket.objects.all().order_by('-yayin_tarihi')[:5]
return render_to_response('anket/index.html',{'son_anketler':son_anketler })

def detail(request, anket_id):
p = get_object_or_404(Anket, pk=anket_id)
return render_to_response('anket/detail.html', {'anket': p})

def all(request):
anketler = Anket.objects.all().order_by('-yayin_tarihi')
return render_to_response('anket/all.html',{'anketler':anketler})

Ardından urls.py dosyanını şu şekilde düzenleyin. Bu arada yukarıda ki kodlar için acele etmeyin hepsini açıklayacağım ;)

urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
(r'^anket/$', 'OrnekProje.anket.views.index'), #[1]
(r'^anket/(?P\d+)/$','OrnekProje.anket.views.detail'),
(r'^anket/all/$','OrnekProje.anket.views.all'),


Öncelikle urls.py dosyasından başlayalım. #[1] ile biten satıra bakalım. Bu satırda djangoya /anket/ adresine gelen bir istek olursa OrnekProje/anket/views dosyasından index fonksiyonun çalıştırılması isteniyor. ( url tanımı yapılırken kullanılan düzenli ifadelerden gökmen ve mirat daha önceki yazılarında bahsettikleri için uzun uzun değinmiyorum.) Şimdi gelelim index fonksiyonuna. İlk satırda son_anketler isimli değişkene veri tabanındaki son 5 anketi tarih sırasına göre atıyoruz. 2. satırda ise render_to_response nesnesini kullanarak
anket dizini içerisindeki index.html dosyanı son_anketler ile verilen değerleri kullanarak bir değer döndürmesini istiyoruz. (Sanki biraz karışık bir cümle oldu :/)

Ama sanki bir şey unuttuk ? anket/index.html diye bir dizin ve dosya yaratmadık. Şimdi OrnekProje dizini içerisinde Templates diye bir dizin oluşturalım. Burada tüm templatelerimizi saklayalım. İyi bir gruplandırma olması açısından her uygulama için ayrı bir dizin kullanalım. Yani onunda içerisinde bir anket dizini oluşturalım.

Bu dizinleri oluşturduktan sonra bunlardan djangoyu haberdar etmeye geldi sıra. Bunun için settings.py dosyasındaki TEMPLATE_DIRS satırını şu şekilde değiştirmemiz gerekiyor.

TEMPLATE_DIRS = ("/home/Deniz/OrnekProje/templates" # dizini kendi dizininizle değiştirmeri unutmayın :)
)


Şimdi tekrar templates/anket klasörüne gidip index.html dosyasını oluşturup içeriğini şu şekilde dolduralım.

{% if son_anketler %}
<ul>
{% for anket in son_anketler %}
<li>{{ anket.soru }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}



İlk satırda ki if sorgusu ile eğer son_anketler değeri var ise aşağıdaki işlemleri yapmasını söylüyoruz.

for döngüsü ise anket olduğu sürece anket sorularını ekrana bastırmamıza yarıyor.

Eğer if sorgusu False değeri döndürürse (yani hiç anket yoksa) else bloğu işletiliyor.

Burada sadece anket sorularını ekrana yazdırdık.

Şimdi urls.py dosyamızın 2. satırını ve detail fonksiyonunu açıklayalım. 2. satırda "/anket/2" "/anket/3" gibi sayfalara gelen isteklerde anket numarasına göre o anketi kullanmamızı için anket_id değerini parametre olarak detail fonksiyonuna gönderiyor.


def detail(request, anket_id):
p = get_object_or_404(Anket, pk=anket_id)
return render_to_response('anket/detail.html', {'anket': p})


Burda da farklı olarak get_object_or_404 nesnesini kullandık. Bu nesne eğer anket_id değeri ile gelen bir değer yoksa ekrana sayfa bulunamadı yazdırmamızı sağlıyor.

Bu da detail.html dosyamızın içeriği

<h1>{{ anket.soru }}</h1>
<ul>
{% for secim in anket.secim_set.all %}
<li>{{ secim.secenek }}</li>
{% endfor %}
</ul>


Burada 3 numaralı anketimizi görüntüledik.

Son fonksiyomuz olan all ve urls.py dosyasındaki ona ait olan satırı uzun uzun anlatmayacağım. Önceki bilgilerimiz ile neyin ne olduğunu anlayabiliriz :) Burada da tüm anketlerimizi ve şıklarını aynı anda sayfaya yazdırıyoruz.

all.html dosyasının içeriği;


{% for anket in anketler %}
<h3> {{anket.soru}} </h3>
{% for secim in anket.secim_set.all %}
<li> {{secim.secenek}} </li>
{% endfor %}
{% endfor %}




Yine template dosyaları aracılığıyla bu yazdıklarımızı özelleştirmek sizin elinizde ;)