MongoDB’ye Giriş

MongoDB, RDBMS’ler gibi şemaya gerek duymaz. Yani bir tablo oluşturmak için önce şema yaratmanıza gerek yoktur. Dinamik bir yapıya sahip olduğundan yapıyı belirtmeden veri girebiliriz.
Mongo’da RDBMS sistemlerinde tablo adlandırılan yapılar kolleksiyon (collection), girilen her bir veri de doküman (document) olarak adlandırılır.
Dokümanlar yapı olarak liste (array) ve başka dokümanlar barındırabilir. MongoDB’yi RDBMS sistemlerinden ayıran en büyük unsur bence budur.
Normalde birkaç tablo ile yapabileceğiniz yapıyı MongoDB ile tek kolleksiyonda oluşturabilirsiniz.
Örnek vermek gerekirse; bir kişinin bilgilerini veritabanında saklamak istiyoruz. Kişinin bir adı ve bir soyadı olacağından kisiler isimli tabloda saklayabiliriz. Ancak birden fazla telefon numarası veya adresi varsa, ya her adres veya telefon için tabloda ayrı bir sütun açmamız gerekir. Peki kaç telefon numarası olabileceğini bilmiyorsak? O zaman ayrı bir tablo oluşturup telefon numaralarını bu tabloda saklayarak kişinin id’si ile bağlamamız gerekir. Ancak MongoDB’de buna gerek yoktur; bir kolleksiyonda bir kişinin tek bir telefonu da olabilir, onlarca telefonu da.
MongoDB, javascript yazımını kullanır. Bu sayede javascript ile döngüler yazıp çoklu veri girişi gibi şeyler yapabilirsiniz.

mongo shell’e girmek için konsolda “mongo” komutunu verelim. Mevcut olan veritabanlarını görmek için “show dbs” komutunu kullanabiliriz. Bir veritabanına komut vermek için “use” komutunu kullanıyoruz. Eğer olmayan bir veritabanına use derseniz yeni bir veritabanına geçmiş olursunuz. Seçtiğiniz veritabanını görmek için “db” komutunu verebilirsiniz. İlk veri girilene kadar veritabanı yaratılmış olmaz. O yüzden veri girmeden başka bir veritabanını seçerseniz önce seçtiğiniz veritabanı yaratılmamış olur.


{
"_id" : ObjectId("517297952d423a75b2b3c4b6"),
"isim" : "Bora",
"yas" : 33
}
{
"_id" : ObjectId("5172a996c45522b7d60bcb83"),
"isim" : "Yavuz",
"yas" : 32,
"telefon" : [
"5323232",
"5323233",
"5323234"
]
}
{
"_id" : ObjectId("5172aa8fc45522b7d60bcb84"),
"isim" : "Sedat",
"yas" : 40,
"telefon" : [
"5323232"
],
"adres" : [
{
"tip" : "ev",
"adres" : "adres1"
},
{
"tip" : "is",
"adres" : "adres2"
}
]
}

Yukarıdaki dokümanlar tek bir kolleksiyonda sorunsuzca oluşturulabilir. Bir dokümanın içinde liste, listenin içinde de başka alt dokümanlar olabilir.

Veritabanim adında yeni bir veritabanı yaratalım sonra da ilk verimizi girelim:

use veritabanim
db.kisiler.insert( { “isim”: “Bora”, “yas”: 33 })

Bu şekilde veri girebileceğimiz gibi verimizi bir değişkene atayarak da girebiliriz.

kisi = { “isim”: “Bora”, “yas”: 33}
db.kisiler.insert(kisi)

“Show collections” diyerek de veritabanı içindeki kolleksiyonları görebiliriz.

kisiler
system.indexes

Kisiler kolleksiyonuna girilmiş olan verileri de aşağıdaki komutla sorgulayalım.

db.kisiler.find()

Bu komut kisilerdeki bütün kayıtları getirecektir.

{ "_id" : ObjectId("517297952d423a75b2b3c4b6"), "isim" : "Bora", "yas" : 33 }

“_id” adında bir alan daha girilmiş olduğunu görüyoruz. Bu alan sistem tarafından otomatik olarak girilen benzersiz bir alandır. Primary key gibi düşünebiliriz.

Şimdi bir döngü yardımı ile birçok veri girelim.

for (var i=0; i<1000; i++) db.notlar.insert({“ogrenci”: i, “not”: Math.floor(Math.random()*100)})
db.notlar.find().pretty()
{ "_id" : ObjectId("51729a1a72560375f9566a36"), "ogrenci" : 135, "not" : 9 }
{
"_id" : ObjectId("51729a1a72560375f9566a37"),
"ogrenci" : 136,
"not" : 46
}
{
"_id" : ObjectId("51729a1a72560375f9566a38"),
"ogrenci" : 137,
"not" : 19
}
{
"_id" : ObjectId("51729a1a72560375f9566a39"),
"ogrenci" : 138,
"not" : 73
}
{
"_id" : ObjectId("51729a1a72560375f9566a3a"),
"ogrenci" : 139,
"not" : 80
}

Yukarıda kullandığımız pretty komutu da çıktının daha okunabilir olmasını sağlar.
Gelen bütün sonuçların hepsini aynı anda ekrana yazdırmak mümkün olmadığından mongo sonucun bir kısmını ekrana basar. Açılmış olan cursor’ı ilerletmek için “it” komutunu kullanabiliriz.
Bir sorgu girdiğimizde MongoDB cursor nesnesi döndürür. Bu nesneyi bir döngü ile ilerletebiliriz.

var c = db.notlar.find()
while (c.hasNext()) printjson( c.next())

Bu sayede bütün sonuçları ekrana yazdırmış oluruz.
Bu komuttan sonra herhangi bir cursor nesnesine ulaşmak istediğimizde aşağıdaki gibi bir hata alırız:

printjson(c[3])
undefined

Cursor nesnesi iterasyonunu tamamladığından hafızadan çıkmıştır. Cursor’a bu şekilde ulaşmak yerine array şeklinde ulaştığımızda tek bir sonuç döndürebiliriz.

var c = db.notlar.find()
printjson(c[3])
{ "_id" : ObjectId("51729a1a72560375f95669b2"), "ogrenci" : 3, "not" : 42 }

Bu şekilde kolleksiyona ulaşıldığında cursor tarafından döndürülen bütün nesneler hafızaya atılır ve cursor hafızadan çıkar. Ancak array hafızada kalacağından RAM’i tüketebilir.

Şimdi de kolleksiyonlardaki dokümanları nasıl filtreleyeceğimize bakalım.

db.notlar.find({db.notlar.find({“ogrenci”: 55})
{ "_id" : ObjectId("51729a1a72560375f95669e6"), "ogrenci" : 55, "not" : 63 }

Şimdi de notu 50 olan öğrencileri bulalım:

db.notlar.find({“not”: 50})
{ "_id" : ObjectId("51729a1a72560375f95669bc"), "ogrenci" : 13, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f95669ec"), "ogrenci" : 61, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566a0a"), "ogrenci" : 91, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566a42"), "ogrenci" : 147, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566a89"), "ogrenci" : 218, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566b3d"), "ogrenci" : 398, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566bcb"), "ogrenci" : 540, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566ca4"), "ogrenci" : 757, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566cec"), "ogrenci" : 829, "not" : 50 }
{ "_id" : ObjectId("51729a1a72560375f9566d08"), "ogrenci" : 857, "not" : 50 }

Not: Bütün not değerleri random yaratıldığından sizin alacağınız sonuçların tamamen farklı olabileceğini unutmamakta fayda var.

Eğer sorgudan sadece tek bir doküman dönmesini istiyorsak findOne metodunu kullanabiliriz.

db.notlar.findOne({“not”: 50})
{ "_id" : ObjectId("51729a1a72560375f95669bc"), "ogrenci" : 13, "not" : 50 }

Gelen sonuçları sınırlamak veya sıralamak isteyebiliriz. Örneğin en yüksek not alan ilk 100 öğrenciyi bulalım.

db.notlar.find().limit(100).sort({“not”: -1})

Sort metoduna sıralamak istediğimiz alanı -1 parametresini vererek çağırdığımızda azalan şeklinde bir sıralama yapacaktır.

{ "_id" : ObjectId("51729a1a72560375f95669e4"), "ogrenci" : 53, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566a99"), "ogrenci" : 234, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566aa6"), "ogrenci" : 247, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566ac0"), "ogrenci" : 273, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566ac8"), "ogrenci" : 281, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566ae6"), "ogrenci" : 311, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566b03"), "ogrenci" : 340, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566b1b"), "ogrenci" : 364, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566b96"), "ogrenci" : 487, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566c26"), "ogrenci" : 631, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566cdb"), "ogrenci" : 812, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566cf2"), "ogrenci" : 835, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566d04"), "ogrenci" : 853, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f9566d51"), "ogrenci" : 930, "not" : 99 }
{ "_id" : ObjectId("51729a1a72560375f95669c1"), "ogrenci" : 18, "not" : 98 }
{ "_id" : ObjectId("51729a1a72560375f95669e8"), "ogrenci" : 57, "not" : 98 }
{ "_id" : ObjectId("51729a1a72560375f9566a16"), "ogrenci" : 103, "not" : 98 }
{ "_id" : ObjectId("51729a1a72560375f9566a87"), "ogrenci" : 216, "not" : 98 }
{ "_id" : ObjectId("51729a1a72560375f9566a98"), "ogrenci" : 233, "not" : 98 }
{ "_id" : ObjectId("51729a1a72560375f9566ac7"), "ogrenci" : 280, "not" : 98 }

Varsayılan olarak böyle bir sorgu bütün alanları getirecektir. Sadece istediğimiz alanları getirmek için dönmesini istediğimiz alanları aşağıdaki gibi belirtebiliriz.

db.notlar.find({“not”: 50}, {“not”: true, “_id”: false})

Gelmesini istediğimiz alanları belirterek true, gelmesini istemediğimiz alanlara da false parametresini vermemiz gerekir. _id alanı false olarak belirtmediğimiz sürece dönecektir.
Bu kolleksiyondan sadece öğrencileri getirmek istersek ama filtre uygulamak istemezsek:

db.notlar.find({},{“ogrenci”: true, “_id”: false})

İlk olarak boş bir JSON nesnesi koyabiliriz. Ogrenci alanına true derken _id alanı her zaman döneceğinden ona da false dememiz gerekir.

Şimdi de notu 40’ın altında olan öğrencileri bulalım:

db.notlar.find({“not”: { $lt: 40 }})

Notu 60 ile 90 arasındaki öğrenciler:

db.notlar.find({“not”: {$gt: 60, $lt:90}})

Genelde yapılan bir hata da şöyledir:

db.notlar.find({ “not”: {$gt:60}, “not”: {$lt: 90}})

Bu yazım sadece notları 90’dan aşağı olan öğrencileri getirir. İlk girdiğimiz filtre dikkate alınmaz.

Şimdi de update metoduna bakalım. MongoDB’de update metodu aşağıdaki gibi kullanıldığında güncellenen dokümanı olduğu gibi değiştirir.
Önce bir doküman oluşturalım:

db.kisiler.insert({“isim”: “Bora”, “yas”: 33, “adres”: “İstanbul”})
db.kisiler.insert({“isim”: “Ahmet”, “yas”: 30, “adres”: “İzmir”})
db.kisiler.insert({“isim”: “Onur”, “yas”: 23: “adres”: “İstanbul”})

db.kisiler.update({“isim”: “Bora”}, {“adres”: “İzmir”})
db.kisiler.find()
{ "_id" : ObjectId("5172c6af3cfd9a893f0ce1ce"), "adres" : "İzmir" }
{ "_id" : ObjectId("5172c6d03cfd9a893f0ce1cf"), "isim" : "Ahmet", "yas" : 30, "adres" : "İzmir" }
{ "_id" : ObjectId("5172c6e93cfd9a893f0ce1d0"), "isim" : "Onur", "yas" : 23, "adres" : "İstanbul" }

Gördüğünüz gibi update işlemi ismi Bora olan dokümanda adres alanını güncellemek yerine sadece bizim girdiğimiz adres alanı olan yeni bir doküman yarattı (object id aynı kalmak koşulu ile). Aslında işlem bu hali ile dokümanı bizim yeni girdiğimiz verilerle güncelliyor. Yani sadece adres alanını belirttiğimiz için sadece adres alanı olan bir doküman olarak güncelliyor.
Eğer sadece istediğimiz alanı güncellemek istersek set komutunu kullanmamız gerekir.

db.kisiler.update({“isim”: “Onur”},{$set: {“adres”: “İzmir”}})
db.kisiler.find()
{ "_id" : ObjectId("5172c6af3cfd9a893f0ce1ce"), "adres" : "İzmir" }
{ "_id" : ObjectId("5172c6d03cfd9a893f0ce1cf"), "isim" : "Ahmet", "yas" : 30, "adres" : "İzmir" }
{ "_id" : ObjectId("5172c6e93cfd9a893f0ce1d0"), "adres" : "İzmir", "isim" : "Onur", "yas" : 23 }

Şimdi de çoklu bir güncelleme deneyelim. Notu 45 – 49 arasındaki bütün öğrencilerin notunu 50 yapalım.

db.notlar.update({“not”: {$gte: 45, $lte:49}}, {$set: {“not”: 50}}, {multi: true})

İstersek notu 10 ve altındaki öğrencilere de 20 puan fazladan verebiliriz.

db.notlar.update({“not”: {$lte:10}}, {$inc: {“not”: 20}}, {multi: true})

Kolleksiyonda olmayan bir dokümanıu güncellemek istediğimizde kolleksiyonda herhangi bir değişiklik olmaz. Ancak güncellenmesi istenen doküman olmadığında eklemek istersek upsert flag’ini kullanmamız gerekir.

db.notlar.update({“orgenci”: 1000}, {$set: {“not”:100}}, {upsert: true})

Oluşturduğumuz kolleksiyonda 1000 numaralı bir öğrenci yok. Yukarıdaki komut ile notu 100 olan 1000 numaralı bir öğrenci ekledik. Aynı komutu aşağıdaki şekilde çalıştırırsak bu sadece bu öğrencinin notunu güncelleyecektir.

db.notlar.update({“orgenci”: 1000}, {$set: {“not”:99}}, {upsert: true})

MondoDB’de or ve and deyimlerini de kullanabiliriz. Aslında yukarıdaki örneklerde and kullandık.

db.notlar.find({“not”: {$gt:20,$lt:30}})

deyimi bize 20 ve 30 arasındaki değerleri getirecektir. Bunu şu şekilde de yazabilirdik:

db.notlar.find({ $and: [ {“not”: {$gt:10}},{“not”: {$lt:20}}]})

Notu 1 veya 99 olan öğrencileri de şu şekilde getirebiliriz:

db.notlar.find({ $or: [ {“not”: 1},{“not”: 99}]})

Dokümandan kaldırmak istediğimiz bir alan olursa unset metodunu kullanmamız gerekir.
100 nolu öğrencinin not alanını kaldırmak için:

db.notlar.update({“ogrenci”:100},{$unset:{“not”:1}})
db.notlar.find({“ogrenci”:100})
{ "_id" : ObjectId("51729a1a72560375f9566a13"), "ogrenci" : 100 }

Tümden silmek istediğimiz dokümanlar için de remove metodunu kullanabiliriz.
Kolleksiyondan notu 1 olan öğrencileri silelim.

db.notlar.remove({“not”:1})
db.notlar.find(“not”:1})

Sonuç döndürmeyecektir.

Django’da signals kullanımı

Django’da signals kullanımı
Django’nun admin paneli çoğu durum için yeterli olsa da biraz değişik bir şey yapmak istediğinizde tutorial’da bahsedilenden farklı bir işlem yapmanız gerekiyor. Sinyaller (signals), Django’nun bu durumda yardımcı olabilecek bir özelliği.

Sinyaller, uygulamada belirlenen alıcıların göndericilerin yaptığı işlemlerden haberdar olmasını sağlar. Bu ne demek biraz açalım; mesela bir modeliniz var ve bu model save edildiği zaman başka bir fonksiyon çağırmak istiyorsunuz. Modelinizi gönderici (sender) olarak belirleyip olurturduğunuz diğer bir fonksiyonu da alıcı (receiver) olarak gösterebilirsiniz.

Django’da kendiniz sinyal fonksiyonlarınızı oluşturabileceğiniz gibi hazırda bulunan sinyaller de mevcut. Modellerin kaydedilme esnasında (öncesinde ve sonrasında) tetiklenen sinyaller ve http isteği başlarken ve biterken tetiklenen sinyaller gibi.

Bir örnek vermek gerekirse:

Ekipman isimli bir modelimiz olsun. Bu modelde her değişiklik yapıldığında bunu ayrı bir tabloda tutmak istiyoruz. Böylelikle ekipmanda yapılan her değişikliği kayıt altında tutabileceğiz.

class Ekipman(models.Model):
    seri_no = models.CharField(max_length=20)
    bulundugu_yer = models.CharField(max_length=20)
    tamirde = models.BooleanField()
    notlar = models.TextField(blank=True)

Gecmis isimli bir de tablomuz var. Buna da yapılan değişiklikleri kaydedeceğiz.

class Gecmis(models.Model):
    ekipman = models.ForeignKey(Ekipman)
    seri_no = models.CharField(max_length=20)
    bulundugu_yer = models.CharField(max_length=20)
    tamirde = models.BooleanField()
    notlar = models.TextField(blank=True)

Şimdi de kayıt işlemini gerçekleştirecek fonksiyonumuzu oluşturalım.

def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()

Alıcı fonksiyonu her zaman sender ve kwargs parametrelerini almalıdır. sender parametresi göndericinin sınıfını (instance’ını değil) tutar. Oluşturduğumuz modelin kendisini (instance’ını) almak için kwargs içindeki instance anahtarını kullanmamız gerekir.

Bu fonksiyonu iki şekilde gönderici ile bağlayabiliriz. Model kaydedildikten sonra alıcının çağırılmasını istediğimize göre:

from django.models.signals import post_save

def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()
 
post_save.connect(GecmisTut, sender=Gecmis)

Veya fonksiyonu bir decorator ile kullanalım:

from django.models.signals import post_save

@receiver(post_save, sender=Ekipman)
def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()

şeklinde kullanabiliriz.

Flask Rehberi

Kurulum

Flask’ı kurmak için pip kullanmanızı tavsiye ederim. Aşağıdaki komutu kullanabilirsiniz:
pip install flask
Diğer paket kurulumlarında olduğu gibi bunu da virtualenv ile kullanmanız şart olmasa da oldukça gerekli.

Basit Bir Flask Uygulaması

Basit bir Flask uygulaması aşağıdaki gibi olabilir:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def merhaba():
    return 'Merhaba dunya!'

if __name__ == '__main__':
    app.run()

Bu kadar kod web sunucusunu çalıştırmaya ve bir satır yazı döndürmeye yeterli. Dosyayı merhaba.py olarak kaydedin. Sunucuyu çalıştırmak için:

python merhaba.py

Running on http://127.0.0.1:5000/ şeklinde bir satır dönmesi gerekiyor. Bu sayfayı ziyaret ederek “Merhaba dunya!” yazısını görebilmelisiniz. Kodlarda her değişiklik yaptığınızda sunucuyu durdurup tekrar başlatmak yerine
app.run(debug=True) ile sunucuyu başlatabilirsiniz. Elbette debug seçeneğini gerçek sunucunuzda asla kullanmamanız gerekiyor.

Routing

Flask’ta route için decorator’lar kullanılıyor.

@app.route('/')
@app.route('/anasayfa')
def anasayfa():
    return 'Ana sayfa'

şeklindeki bir örnekte kök dizine (yukarıdaki adres) ve index sayfasına ziyaretler aynı fonksiyonu (anasayfa) çağıracaktır.
Adreslere değişken eklemek için aşağıdaki yol izlenebilir:

@app.route('/kullanici/<kullaniciadi>')
def welcome(kullaniciadi):
    return 'Merhaba %s' % kullaniciadi

Tarayıcınıza /kullanici/bora yazdığınızda “Merhaba bora” yazısını döndürecektir.

URL Yapılandırma

Uygulamanızda tanımladığınız url’leri uygulamanızda başka yerlerde kullanırken olduğu gibi yazmak uygulamanın genişletilebilirliği ve yönetilebilirliği açısından ileride zorluk çıkmasına neden olabilir. Tanımladığınız url’de değişiklik yaptığınız zaman bütün kodda gerekli yerleri bulup düzeltmeniz gerekecektir. Bunun yerine bunları üreterek tek bir yerden yönetimini sağlayabilirsiniz.

from flask import Flask, url_for, redirect
app = Flask(__name__)

@app.route('/kullanici')
def kullanici():
    return 'Kullanici sayfasi'

@app.route('/yonetici')
def yonetici():
    return 'Yonetici sayfasi'

@app.route('/giris/<kullanici>')
def giris(kullanici):
    if kullanici == 'yonetici':
        return redirect(url_for('yonetici'))
    else:
        return redirect(url_for('kullanici'))

if __name__ == '__main__':
    app.run(debug=True)

Yukardaki kodu bir dosyaya kaydedip çalıştırırsanız, tarayıcıda /giris/yonetici adresini ziyaret ettiğinizde yönetici sayfasını, diğer herhangi bir kullanıcı adı (/giris/kullanici veya /giris/bora) ile ziyaret ettiğinizde kullanıcı sayfasını göreceksiniz. Bu işlemin faydası, daha sonra bir nedenle adresi değiştirmek istediğinizde diğer kullandığınız yerlerde değişiklik yapmaya gerek kalmaması.

HTTP Metotları

Varsayılan olarak route’lar GET metotunu destekler. Form göndermek istediğinizde POST metotunu da desteklenen metotlar arasına eklemeniz gerekebilir.

@app.route('/giris', methods=['GET', 'POST'])
def giris():
    if request.method == 'POST':
        #login işlemleri
    else:
        #form göster

Statik Dosyalar

Css ve javascript dosyaları gibi statik dosyaları kullanabilmek için uygulama klasörünüzde static isimli bir klasör yaratmanız gerekir. Bu statik dosyalara aşağıdaki şekilde url yaratabilirsiniz:

url_for('static', filename='style.css')

Template Renderlama

Flask varsayılan olarak Jinja2 template sistemini kullanır. Htmldosyalarını render etmek için render_template metotunden yararlanılır. Yarattığınız html dosyalarını uygulama klasörü içinde template klasörü altında saklayabilirsiniz.

from flask import render_template

@app.route('/giris/<ad>')
def giris(ad):
    return render_template('giris.html', ad=ad)

Çağırılan html sayfası da aşağıdaki şekilde olabilir:

<h1>Merhaba {{ ad }}</h1>
Jinja2 template sistemi hakkında daha fazla bilgi için sitesini ziyaret edebilirsiniz.

Git’te Yapılan Commit’i Geri Alma

Git’te yaptığınız bir commit’i geri almak için iki yol kullanabilirsiniz.

Örneğin log’da yaptığımız 3 commit olsun.

commit 754514206d99fb32307ff79ec37a4e6b28bfad31
Author: Bora Aymete
Date:   Mon Oct 22 15:38:08 2012 +0300

    undo2

commit d24fb55ee8888f40c59f277c9bbc7c8c8c8dc8bf
Author: Bora Aymete
Date:   Mon Oct 22 15:37:51 2012 +0300

    undo1

commit ef359c43cde842fa9e4705ca5753a265c6935eeb
Author: Bora Aymete
Date:   Mon Oct 22 14:10:31 2012 +0300

    added comments

git reset–soft d24fb55ee8888f40c59f277c9bbc7c8c8c8dc8bf komutu durumu undo1 commit’ine geri döndürür. Yapılan değişiklikler staged durumdadır.

# On branch master
# Changes to be committed:
#   (use “git reset HEAD <file>…” to unstage)
#
#       modified:   app/models/post.rb
#

Dilenirse git reset HEAD app/models/post.rb komutu verilerek unstaged alanına çekilebilir.

D app/models/post.rb
Unstaged changes after reset:
M       app/models/post.rb

Kodu undo1 commit’indeki haline git checkout app/models/post.rb komutu ile geri döndürebilirsiniz.

git status

# On branch master
nothing to commit (working directory clean)

git log

commit d24fb55ee8888f40c59f277c9bbc7c8c8c8dc8bf
Author: Bora Aymete
Date:   Mon Oct 22 15:37:51 2012 +0300

    undo1

commit ef359c43cde842fa9e4705ca5753a265c6935eeb
Author: Bora Aymete
Date:   Mon Oct 22 14:10:31 2012 +0300

    added comments
   
Bunu sıra ile yapmanız gerekmez, added comments commit’ine direkt olarak geri döndürebilirsiniz.

Yukarıdaki işlemleri daha hızlı bir şekilde yapmak isterseniz git reset –hard HEAD^ komutunu kullanabilirsiniz. Dikkatli olmanızı tavsiye ederim, geri döndüğünüz commit’ten sonraki commit’ler kaybolacaktır.

git log
 
commit 1e38ea2658667aa3443bce980f494895bc1e5ed9
Author: Bora Aymete
Date:   Mon Oct 22 15:46:09 2012 +0300

    undo2

commit d24fb55ee8888f40c59f277c9bbc7c8c8c8dc8bf
Author: Bora Aymete
Date:   Mon Oct 22 15:37:51 2012 +0300

    undo1

commit ef359c43cde842fa9e4705ca5753a265c6935eeb
Author: Bora Aymete
Date:   Mon Oct 22 14:10:31 2012 +0300

    added comments

git reset –hard ef359c43cde842fa9e4705ca5753a265c6935eeb

git log

commit ef359c43cde842fa9e4705ca5753a265c6935eeb
Author: Bora Aymete
Date:   Mon Oct 22 14:10:31 2012 +0300

    added comments

Django’da Admin panelinde modelleri Türkçe çoğul yapma

Django’da admin panelinde modeller verdiğiniz ad ne olursa olsun çoğul yapılırken sonuna ‘s’ takısı alır (örneğin Personels). Oysa ki biz Personel modelini admin panelinde Personeller olarak görmek isteyebiliriz.

Bu durumda Personel modeline aşağıdaki sınıfı eklemeniz yeterli olacaktır:

class Personel(models.Model):
    .......
    class Meta:
        verbose_name_plural = "Personeller"

Python ile listeleri sıralamak

Python’da listeleri sıralamak için iki yol izlenebilir. Birincisi sort() metodu. Bu metod üzerinde uygulanan listeyi sıralar. Ancak none döndürdüğüne dikkat edilmelidir.

liste = [6,3,9]
liste.sort()
liste
[3, 6, 9]

Yani aşağıdaki şekilde bir atama yapamazsınız.

sirali_liste = liste.sort()
Bunun yerine sorted fonksiyonunu kullanabilirsiniz.

sirali_liste = sorted(liste)
Sorted fonksiyonu ayrıca argümanlarla özelleştirilebilir.

liste = ["google", "android", "java"]
sorted(liste, reverse=True)
['java', 'google', 'android']

Bence sorted fonksiyonunun en güzel tarafı, listeleri sıralamak için custom fonksiyon yazılabilmesidir.

sorted(liste, key=len)
['java', 'google', 'android']

Len gibi hazır bir fonksiyon kullanılabilir veya yazılan bir fonksiyon kullanılabilir.

def Fonk(a):
    return a(-1)
sorted(liste, key=Fonk) ['java', 'android', 'google']

Django’da QuerySet’ler 2 – Filtreleme

Queryset’lerde alınan veri üzerinde filtreleme işlemi aşağıdaki örnekte olduğu gibi yapılabilir.

kisiler = Kisi.objects.all()
kisiler.filter(isim='Ahmet')


Zincirleme filtre de aşağıdaki gibidir.

kisiler = kisiler.filter(yas=20)
kisiler = kisiler.filter(isim__startswith='A')


Dikkat edilmesi gereken nokta bu query’ler çalıştırıldığında veritabanı ile herhangi bir bağlantı kurulmamasıdır (şu ana kadar sadece veriyi çekecek olan query’i oluşturduğumuzu düşünebilirsiniz). Bağlantı queryset’ler içerisindeki bilgiye ulaşılmaya çalışıldığında kurulur.

kisiler = Kisi.objects.filter(isim__startswith='A')
kisiler = kisiler.filter(soyad__contains='E')
for kisi in kisiler:
print kisi.isim


Yukarıdaki kod çalıştırıldığında belirtilen filtreler ile getirilen sonuçları ekrana yazar. Bu sırada veritabanı ile sadece bir kere bağlantı kurulur.

Django’da QuerySet’ler 1

Django’da QuerySetler

Django’da queryset’ler çağırıldığında cache’de tutulurlar. Böylece çağırılan queryset tekrar kullanılarak database üzerindeki yük azaltılmış olur.

Aşağıdaki query’ler çalıştırıldıklarında veritabanı ile iki kere bağlantı kurarak toplamda iki ayrı sorgu çalıştırır.

q = kisi.isim for kisi in Kisi.objects.all()
q = kisi.yas for kisi in Kisi.objects.all()


Bunun yerine daha az kaynak tüketen aşağıdaki yol izlenebilir.

kisiler = Kisi.objects.all()
kisi.isim for kisi in kisiler
kisi.yas for kisi in kisiler

Bu şekilde veritabanı ile sadece bir defa bağlantı kurularak queryset cache’e alınır.

Google Python Class string2.py Çözümü

Google’ın Python alıştırmaları veren sınıfında ödevlerden biri olan string2.py’nin front_back alıştırmasını aşağıdaki şekilde çözdüm. Bu alıştırmada verilen iki string’in uzunluklarına göre bölünmesi ve tek bir string haline getirilmesi isteniyor. Eğer string uzunluğu çift ise ortadan ikiye bölünecek, tekse yine ortadan ikiye bölünecek ancak artan (yani string’in ortasındaki) harf baştaki parçaya eklenecek. Bundan sonra istenen ise ilk string’i a1 ve a2 olarak, ikincisini de b1 ve b2 olarak bölmüşsek hepsinin a1+b1+a2+b2 şeklinde tek string halinde döndürülmesi.

def front_back(a, b):
a1 = a[:len(a)/2+len(a)%2]
a2 = a[len(a)/2+len(a)%2:]
b1 = b[:len(b)/2+len(b)%2]
b2 = b[len(b)/2+len(b)%2:]
print a1,a2,b1,b2
return a1+b1+a2+b2

Python’da liste kopyalama

Python’da listeleri aşağıdaki eşitlikle kopyalamaya çalıştığınızda liste içerisindeki değerler kopyalanmaz; listenin referans değeri kopyalanır. Bu durumda bir listede yapılan değişiklikler diğerinde de geçerli olur.

liste1=["deger1","deger2","deger3"]
liste2=liste1
liste2.append("deger4")
print liste1,liste2
['deger1', 'deger2', 'deger3', 'deger4'] ['deger1', 'deger2', 'deger3', 'deger4']

Bunun yerine değerleri kopyalamak için aşağıdakiler kullanılabilir:

liste1=["deger1","deger2","deger3"]
liste2=list(liste1)
liste2.append("deger4")
print liste1,liste2
['deger1', 'deger2', 'deger3'] ['deger1', 'deger2', 'deger3', 'deger4']

Veya:
liste1=["deger1","deger2","deger3"]
liste2=liste1[:]
liste2.append("deger4")
print liste1,liste2
['deger1', 'deger2', 'deger3'] ['deger1', 'deger2', 'deger3', 'deger4']

Son iki örnekte verilen kodlarda sadece değerler kopyalanır; bir listede yapılan değişiklik diğerini etkilemez.