Bottle Mikro Çerçevesini Kullanarak Python Web Uygulamaları Geliştirme Rehberi
Python ekosistemi, web geliştirme için zengin bir araç yelpazesi sunar. Django ve Flask gibi popüler çerçeveler genellikle karmaşık ve büyük ölçekli projeler için tercih edilirken, daha küçük, hızlı ve hafif çözümlere ihtiyaç duyulduğunda mikro çerçeveler devreye girer. Bu makalede, Python’ın en basit ve en etkili mikro çerçevelerinden biri olan Bottle’ı derinlemesine inceleyeceğiz. Bottle ile web uygulamaları geliştirmenin temel prensiplerini, ileri seviye özelliklerini ve en iyi uygulamalarını adım adım keşfedeceğiz.
Giriş: Bottle Mikro Çerçevesi Nedir ve Neden Tercih Edilmelidir?
Bottle, tek bir Python dosyası olarak dağıtılan, hızlı, basit ve hafif bir WSGI mikro web çerçevesidir. Harici bir kütüphaneye bağımlılığı yoktur (sadece Python Standart Kütüphanesi’ni kullanır) ve bu özelliği onu inanılmaz derecede taşınabilir ve öğrenmesi kolay kılar. Bottle’ın felsefesi “her şeyi yapmaya çalışma” üzerine kuruludur; bunun yerine, web uygulamaları oluşturmak için gerekli temel işlevleri (yönlendirme, şablonlama, statik dosya sunumu vb.) minimalist bir şekilde sağlar.
Bottle’ın Temel Özellikleri
* Tek Dosya: Bottle, tek bir .py dosyasından oluşur, bu da onu kurmayı ve dağıtmayı son derece basit hale getirir.
* Bağımlılıksız: Python standart kütüphanesi dışında hiçbir harici bağımlılığı yoktur.
* Hızlı ve Hafif: Minimum bellek ve işlemci kullanımıyla yüksek performans sunar.
* WSGI Uyumluluğu: Gunicorn, uWSGI, CherryPy gibi popüler WSGI sunucularıyla sorunsuz çalışır.
* Yerleşik Şablon Motoru: Basit ve hızlı bir şablon motoruna sahiptir, ancak Jinja2 veya Mako gibi diğer motorlarla da entegre edilebilir.
* URL Yönlendirme: Dinamik URL’ler, HTTP metotları ve düzenli ifadelerle güçlü yönlendirme yetenekleri sunar.
* Esneklik: İhtiyaç duyulan her şeyi kendi başına sağlamak yerine, geliştiricilere üçüncü taraf kütüphaneleri (veritabanı ORM’leri, kimlik doğrulama, form doğrulama vb.) entegre etme özgürlüğü verir.
Neden Bottle Kullanmalısınız?
* Hızlı Prototipleme: Hızla bir API veya küçük bir web uygulaması oluşturmanız gerektiğinde idealdir.
* Öğrenme Kolaylığı: Python’a yeni başlayanlar veya web çerçevelerine giriş yapmak isteyenler için mükemmel bir başlangıç noktasıdır.
* Küçük ve Orta Ölçekli Projeler: Karmaşık bir veritabanı şemasına veya kullanıcı yönetimine ihtiyaç duymayan projeler için uygundur.
* Mikroservisler: Hafif ve bağımsız mikroservisler geliştirmek için harika bir seçenektir.
* Gömülü Sistemler: Kaynak kısıtlı ortamlarda web arayüzleri sağlamak için kullanılabilir.
Başlangıç: Bottle Kurulumu ve İlk Uygulamanız
Bottle ile web uygulaması geliştirmeye başlamak oldukça basittir. İlk adım, Bottle’ı Python ortamınıza kurmaktır.
Bottle Kurulumu
Python yüklü bir sistemde, terminalinizi açın ve aşağıdaki komutu çalıştırın:
pip install bottle
Bu komut, Bottle kütüphanesini sanal ortamınıza veya sisteminize kuracaktır.
“Merhaba Dünya!” Uygulaması
Şimdi, Bottle ile ilk web uygulamanızı oluşturalım. app.py adında bir dosya oluşturun ve içine aşağıdaki kodu yapıştırın:
from bottle import route, run, template
@route('/')
def index():
return "Merhaba, Dünya!"
@route('/hello/')
def hello(name):
return template('Merhaba {{name}}!', name=name)
if __name__ == '__main__':
run(host='localhost', port=8080, debug=True, reloader=True)
Bu kod parçası, Bottle ile temel bir web uygulamasının nasıl oluşturulacağını göstermektedir.
* from bottle import route, run, template: Bottle kütüphanesinden gerekli fonksiyonları içe aktarıyoruz.
* @route('/'): Bu dekoratör, ana URL (/) için bir yönlendirme tanımlar. Kullanıcı bu adrese gittiğinde, index() fonksiyonu çalışır.
* index(): Bu fonksiyon, tarayıcıya “Merhaba, Dünya!” metnini döndürür.
* @route('/hello/: Bu, dinamik bir URL yönlendirmesidir. kısmı, URL’den alınan bir parametreyi temsil eder. Örneğin, /hello/Ali adresine gidildiğinde name parametresi “Ali” olacaktır.
* hello(name): Bu fonksiyon, alınan name parametresini kullanarak bir şablonu işler ve tarayıcıya döndürür. Bottle’ın yerleşik template fonksiyonunu kullanarak HTML çıktısı oluşturuyoruz.
* if __name__ == '__main__':: Bu blok, betiğin doğrudan çalıştırıldığında Bottle sunucusunu başlatır.
* run(host='localhost', port=8080, debug=True, reloader=True): Bottle’ın geliştirme sunucusunu başlatır.
* host='localhost': Uygulamanın sadece yerel makineden erişilebilir olmasını sağlar.
* port=8080: Uygulamanın 8080 portunda çalışmasını sağlar.
* debug=True: Hata ayıklama modunu etkinleştirir. Hatalar tarayıcıda görüntülenir ve daha fazla bilgi sağlar.
* reloader=True: Dosyalarda yapılan değişiklikleri otomatik olarak algılar ve sunucuyu yeniden başlatır. Geliştirme sürecinde çok kullanışlıdır.
Uygulamayı Çalıştırma
Terminalinizde app.py dosyasının bulunduğu dizine gidin ve aşağıdaki komutu çalıştırın:
python app.py
Tarayıcınızı açın ve http://localhost:8080/ adresine gidin. “Merhaba, Dünya!” mesajını görmelisiniz.
Şimdi http://localhost:8080/hello/Ahmet adresine gidin. “Merhaba Ahmet!” mesajını görmelisiniz.
Tebrikler, ilk Bottle uygulamanızı başarıyla çalıştırdınız!
Temel Kavramlar: Bottle’ın İnşa Taşları
Bottle’ın gücü, basit ama etkili temel kavramlarında yatar. Bu bölümde, yönlendirme, istek ve yanıt nesneleri, şablonlar ve statik dosyalar gibi temel yapı taşlarını ayrıntılı olarak inceleyeceğiz.
Yönlendirme (Routing)
Yönlendirme, gelen HTTP isteklerini belirli Python fonksiyonlarına eşleme işlemidir. Bottle’da @route() dekoratörü ile yönlendirme tanımlanır.
Basit Yönlendirmeler
from bottle import route, run
@route('/about')
def about():
return "Bu bir 'Hakkımızda' sayfasıdır."
@route('/contact')
def contact():
return "İletişim bilgilerimiz burada."
run(host='localhost', port=8080)
Dinamik Yönlendirmeler ve Parametreler
URL’den parametre almak için sözdizimini kullanırız.
@route('/users/')
def show_user(user_id):
return f"Kullanıcı ID: {user_id}"
@route('/posts///')
def show_post_by_date(year, month, day):
return f"Yıl: {year}, Ay: {month}, Gün: {day} tarihli gönderi."
Yukarıdaki örnekte:
* : user_id adında bir parametre alır. Varsayılan olarak, parametreler string olarak kabul edilir.
* , , : Bu, parametre türünü belirtir. int (tam sayı), float (kayan noktalı sayı), path (eğik çizgiler dahil tüm yolu alır) gibi yerleşik türler veya özel türler kullanılabilir.
HTTP Metotları
Bir rota, belirli HTTP metotlarına (GET, POST, PUT, DELETE vb.) yanıt verecek şekilde yapılandırılabilir.
from bottle import route, request, run
@route('/login', method='GET')
def login_form():
return '''
'''
@route('/login', method='POST')
def login_submit():
username = request.forms.get('username')
password = request.forms.get('password')
if username == 'admin' and password == 'password':
return "Giriş başarılı!
"
else:
return "Kullanıcı adı veya şifre yanlış.
"
run(host='localhost', port=8080)
Bu örnekte, /login rotası hem GET (formu göstermek için) hem de POST (form verilerini işlemek için) metotlarını destekler.
İstek ve Yanıt Nesneleri (Request and Response Objects)
Bottle, gelen HTTP isteğine (request) ve gönderilen HTTP yanıtına (response) erişim sağlayan global nesneler sunar.
request Nesnesi
request nesnesi, istemciden gelen tüm bilgileri içerir:
* request.query: URL sorgu parametreleri (?key=value).
* request.forms: POST isteklerinden gelen form verileri.
* request.params: Hem sorgu hem de form parametrelerini birleştirir.
* request.headers: İstek başlıkları.
* request.cookies: İstemciden gelen çerezler.
* request.files: Yüklenen dosyalar.
* request.json: JSON formatındaki istek gövdesi.
* request.url, request.path, request.method: İstek URL’si, yolu ve metodu.
Örnek:
from bottle import route, request, run
@route('/search')
def search():
query = request.query.get('q', 'arama terimi belirtilmedi')
return f"Arama sonuçları: '{query}'"
@route('/upload', method='POST')
def upload_file():
upload = request.files.get('upload')
if upload:
name, ext = os.path.splitext(upload.filename)
if ext not in ('.png', '.jpg', '.jpeg'):
return "Sadece resim dosyalarına izin verilir."
save_path = f"/tmp/{upload.filename}" # Güvenli bir dizine kaydedin!
upload.save(save_path)
return f"Dosya '{upload.filename}' başarıyla yüklendi."
return "Dosya yüklenemedi."
run(host='localhost', port=8080)
response Nesnesi
response nesnesi, istemciye gönderilecek yanıtı yapılandırmak için kullanılır:
* response.status: HTTP durum kodu (örn. 200, 404, 500).
* response.headers: Yanıt başlıkları.
* response.set_cookie(): İstemciye çerez gönderme.
* response.delete_cookie(): İstemciden çerez silme.
* response.redirect(): Yönlendirme yapma.
Örnek:
from bottle import route, response, redirect, run
@route('/set_cookie')
def set_cookie():
response.set_cookie('my_cookie', 'some_value', max_age=3600)
return "Çerez ayarlandı."
@route('/get_cookie')
def get_cookie():
cookie_value = request.get_cookie('my_cookie')
return f"Çerez değeri: {cookie_value}" if cookie_value else "Çerez bulunamadı."
@route('/go_to_home')
def go_home():
redirect('/') # Ana sayfaya yönlendir
return "Yönlendiriliyor..." # Bu satır aslında çalışmayacak
run(host='localhost', port=8080)
Şablonlar (Templates)
Bottle, varsayılan olarak basit bir şablon motoruyla gelir, ancak Jinja2 veya Mako gibi popüler şablon motorlarıyla da kolayca entegre edilebilir.
Yerleşik Şablon Motoru Kullanımı
template() fonksiyonu, bir şablon dosyasını veya şablon dizesini işlemek için kullanılır.
views adında bir klasör oluşturun ve içine hello_page.tpl adında bir dosya ekleyin:
views/hello_page.tpl:
Merhaba Sayfası
Bu, Bottle ile oluşturulmuş bir şablon örneğidir.
app.py:
from bottle import route, run, template
@route('/greet/')
def greet(name):
return template('hello_page', name=name)
run(host='localhost', port=8080)
template('hello_page', name=name) ifadesi, views klasöründeki hello_page.tpl dosyasını arar ve name değişkenini şablona aktarır.
Diğer Şablon Motorlarıyla Entegrasyon (Örn: Jinja2)
Önce Jinja2’yi kurun: pip install jinja2
app.py:
from bottle import route, run, Jinja2Template
from jinja2 import Environment, FileSystemLoader
Jinja2 ortamını yapılandır
jinja2_env = Environment(loader=FileSystemLoader('./views'))
Jinja2Template.defaults = {'env': jinja2_env}
@route('/jinja_greet/')
def jinja_greet(name):
return Jinja2Template('hello_page.html').render(name=name)
run(host='localhost', port=8080)
views/hello_page.html:
Jinja2 Merhaba Sayfası
Bu, Jinja2 ile oluşturulmuş bir şablon örneğidir.
Statik Dosyalar (Static Files)
CSS, JavaScript, resimler gibi statik dosyaları sunmak için static_file() fonksiyonu kullanılır.
from bottle import route, run, static_file
import os
Statik dosyalarınızın bulunduğu dizin
STATIC_ROOT = './static'
@route('/static/')
def serve_static(filepath):
return static_file(filepath, root=STATIC_ROOT)
@route('/')
def index():
return '''
Statik Dosya Örneği
'''
run(host='localhost', port=8080)
static adında bir klasör oluşturun ve içine style.css, script.js ve logo.png gibi dosyalar koyun.
./static/style.css:
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
color: #333;
}
h1 {
color: #0056b3;
}
./static/script.js:
document.addEventListener('DOMContentLoaded', function() {
console.log('JavaScript dosyası yüklendi!');
});
Bu yapılandırma, /static/ ile başlayan tüm istekleri STATIC_ROOT dizinindeki dosyalara yönlendirir.
Veritabanı Entegrasyonu
Bottle, herhangi bir veritabanı soyutlama katmanı (ORM) veya veritabanı sürücüsü ile gelmez. Bu, Bottle’ın minimalist felsefesinin bir parçasıdır. Geliştiriciler, projelerinin ihtiyaçlarına en uygun veritabanı kütüphanesini seçmekte özgürdür. SQLite, PostgreSQL, MySQL gibi ilişkisel veritabanları veya MongoDB, Redis gibi NoSQL veritabanları ile çalışabilirsiniz.
SQLite ile Basit Bir Örnek
SQLite, Python ile varsayılan olarak gelen hafif, dosya tabanlı bir veritabanıdır ve küçük projeler için harikadır.
from bottle import route, run, template, request
import sqlite3
DB_PATH = 'mydatabase.db'
def get_db_connection():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row # Kolon isimleriyle verilere erişim sağlar
return conn
Veritabanı tablosunu oluştur
def init_db():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'açık'
)
''')
conn.commit()
conn.close()
Uygulama başlamadan önce veritabanını başlat
init_db()
@route('/todos')
def todo_list():
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("SELECT id, task, status FROM todos")
rows = cursor.fetchall()
conn.close()
return template('todo_list', todos=rows)
@route('/new_todo', method=['GET', 'POST'])
def new_todo():
if request.method == 'POST':
task = request.forms.get('task')
if task:
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute("INSERT INTO todos (task) VALUES (?)", (task,))
conn.commit()
conn.close()
return "Görev eklendi!"
return "Görev boş olamaz."
else:
return '''
'''
run(host='localhost', port=8080)
views/todo_list.tpl:
Yapılacaklar Listesi
% for todo in todos:
- {{ todo['task'] }} (Durum: {{ todo['status'] }})
% end
Bu örnek, bir SQLite veritabanı ile basit bir “yapılacaklar” listesi uygulamasını gösterir. get_db_connection() fonksiyonu, her istekte yeni bir veritabanı bağlantısı oluşturmak için kullanılır. Büyük uygulamalarda bağlantı havuzları veya ORM’ler (SQLAlchemy, Peewee) kullanmak daha iyi bir yaklaşımdır.
Form İşleme ve Dosya Yükleme
Web uygulamalarının önemli bir parçası, kullanıcıdan veri almak ve bu verileri işlemektir. Bottle, form verilerini ve dosya yüklemelerini kolayca yönetmenizi sağlar.
Form Verilerini İşleme
GET istekleri için request.query, POST istekleri için request.forms kullanılır.
from bottle import route, request, run
@route('/register', method=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.forms.get('username')
email = request.forms.get('email')
password = request.forms.get('password')
if not username or not email or not password:
return "Lütfen tüm alanları doldurun."
# Burada veritabanına kaydetme veya başka işlemler yapılabilir
return f"Kullanıcı '{username}' başarıyla kaydedildi! E-posta: {email}"
else:
return '''
'''
run(host='localhost', port=8080)
Dosya Yükleme
request.files nesnesi, yüklenen dosyalara erişim sağlar.
from bottle import route, request, run
import os
UPLOAD_DIR = './uploads'
os.makedirs(UPLOAD_DIR, exist_ok=True) # Yükleme dizinini oluştur
@route('/upload_file', method=['GET', 'POST'])
def upload_view():
if request.method == 'POST':
upload = request.files.get('my_file')
if upload:
name, ext = os.path.splitext(upload.filename)
if ext not in ('.png', '.jpg', '.jpeg', '.gif', '.pdf'):
return "Sadece resim ve PDF dosyalarına izin verilir."
# Güvenli bir dosya adı oluşturmak önemlidir
# Örneğin, dosya adını hashleyebilir veya UUID kullanabilirsiniz.
# Şimdilik basitçe kaydedelim:
save_path = os.path.join(UPLOAD_DIR, upload.filename)
try:
upload.save(save_path)
return f"Dosya '{upload.filename}' başarıyla yüklendi ve kaydedildi: {save_path}"
except Exception as e:
return f"Dosya yüklenirken bir hata oluştu: {e}"
return "Dosya yüklenemedi. Lütfen bir dosya seçin."
else:
return '''
'''
run(host='localhost', port=8080)
Güvenlik Notu: Dosya yükleme işlemleri sırasında her zaman dikkatli olunmalıdır. Yüklenen dosyaların türünü, boyutunu doğrulamak ve sunucuda güvenli bir şekilde saklamak (örneğin, rastgele oluşturulmuş dosya adları kullanarak) kötü niyetli saldırıları önlemek için hayati öneme sahiptir.
Hata Yönetimi
Bottle, uygulamanızda meydana gelen hataları yakalamak ve özel hata sayfaları sunmak için @error() dekoratörünü kullanmanıza olanak tanır.
from bottle import route, run, error, template
@error(404)
def error404(error):
return template('error_page', code=error.status_code, message="Aradığınız sayfa bulunamadı.")
@error(500)
def error500(error):
return template('error_page', code=error.status_code, message="Sunucuda beklenmeyen bir hata oluştu.")
@route('/bad_route')
def bad_route():
# Bilerek bir hata oluşturalım
raise ValueError("Bu bir test hatasıdır!")
@route('/')
def index():
return "Ana sayfa."
run(host='localhost', port=8080)
views/error_page.tpl:
Hata {{code}}
{{message}}
Bu örnekte, bir 404 (Sayfa Bulunamadı) veya 500 (Dahili Sunucu Hatası) hatası meydana geldiğinde, error_page.tpl şablonu kullanılarak özelleştirilmiş bir hata sayfası gösterilir. error nesnesi, hata kodu ve mesajı gibi bilgilere erişim sağlar.
Middleware ve Eklentiler (Plugins)
Bottle’ın esnek mimarisi, HTTP istek/yanıt döngüsüne ek işlevsellik eklemek için middleware veya eklentiler kullanmanıza olanak tanır.
Eklentiler
Eklentiler, Bottle uygulamanızın davranışını değiştirmek veya genişletmek için güçlü bir yoldur. Bottle, veritabanı bağlantı yönetimi gibi yaygın görevler için yerleşik eklentilere sahiptir ve kendi özel eklentilerinizi de yazabilirsiniz.
Yerleşik Eklenti Örneği: SQLite Eklentisi
Bottle’ın sqlite eklentisi, her istek için bir veritabanı bağlantısı açıp kapatma yükünü ortadan kaldırır.
from bottle import route, run, template
from bottle_sqlite import SQLitePlugin
import sqlite3
Eklentiyi uygulamanıza kurun
app = Bottle()
app.install(SQLitePlugin(dbfile='my_plugin_database.db'))
@app.route('/plugin_todos')
def plugin_todo_list(db): # db parametresi eklenti tarafından sağlanır
cursor = db.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, task TEXT NOT NULL)")
cursor.execute("SELECT id, task FROM todos")
rows = cursor.fetchall()
return template('plugin_todo_list', todos=rows)
@app.route('/add_plugin_todo', method='POST')
def add_plugin_todo(db):
task = request.forms.get('task')
if task:
db.execute("INSERT INTO todos (task) VALUES (?)", (task,))
return "Görev eklendi (plugin ile)!"
return "Görev boş olamaz."
run(app, host='localhost', port=8080)
views/plugin_todo_list.tpl:
Eklenti ile Yapılacaklar
% for todo in todos:
- {{ todo[1] }}
% end
Bu örnekte, SQLitePlugin‘i kurduktan sonra, rota fonksiyonlarına db adında bir parametre ekleyerek veritabanı bağlantısına erişebiliriz. Eklenti, bağlantıları otomatik olarak yönetir.
Dağıtım (Deployment)
Geliştirme sunucusu (bottle.run()) sadece geliştirme amaçlıdır ve üretim ortamında kullanılmamalıdır. Üretim ortamında Bottle uygulamalarını dağıtmak için WSGI uyumlu bir sunucuya ihtiyacınız vardır.
Popüler WSGI Sunucuları
* Gunicorn: Python için sağlam ve hızlı bir WSGI HTTP sunucusu.
* uWSGI: Çok yönlü ve yüksek performanslı bir uygulama sunucusu.
* CherryPy: Bottle’ın kendisi de CherryPy sunucusuyla çalışabilir.
* Waitress: Saf Python’da yazılmış, kullanımı kolay bir WSGI sunucusu.
Gunicorn ile Dağıtım Örneği
1. Gunicorn’ı Kurun: pip install gunicorn
2. Uygulama Dosyası (app.py):
from bottle import Bottle, route, run
app = Bottle()
@app.route('/')
def index():
return "Merhaba, Gunicorn!"
# Geliştirme sunucusunu kaldırmayı unutmayın veya sadece test için kullanın
# if __name__ == '__main__':
# run(app, host='localhost', port=8080, debug=True, reloader=True)
3. Gunicorn ile Çalıştırın: Terminalde app.py dosyasının bulunduğu dizinde aşağıdaki komutu çalıştırın:
gunicorn -w 4 app:app
* -w 4: 4 adet worker (işçi) süreci başlatır.
* app:app: app.py dosyasındaki app adlı Bottle uygulamasını belirtir.
Artık uygulamanız http://localhost:8000/ adresinde (Gunicorn’ın varsayılan portu) Gunicorn tarafından sunulacaktır. Gerçek dünya dağıtımlarında, Gunicorn’ın önüne Nginx veya Apache gibi bir ters proxy sunucu eklemek yaygın bir uygulamadır.
En İyi Uygulamalar ve İleri Konular
Bottle’ın basitliği, geliştiricilere büyük bir esneklik sunar, ancak bu esneklikle birlikte bazı en iyi uygulamaları takip etmek, uygulamanızın daha sürdürülebilir ve ölçeklenebilir olmasını sağlar.
Proje Yapısı
Küçük uygulamalar için tek bir app.py dosyası yeterli olabilir, ancak uygulamanız büyüdükçe daha modüler bir yapıya ihtiyacınız olacaktır.
my_bottle_app/
├── app.py
├── views/
│ ├── index.tpl
│ └── error.tpl
├── static/
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── script.js
├── models.py
├── controllers.py
├── config.py
└── requirements.txt
* app.py: Ana uygulama tanımı ve ana rotalar.
* views/: Şablon dosyaları.
* static/: Statik dosyalar (CSS, JS, resimler).
* models.py: Veritabanı modelleri (ORM kullanılıyorsa).
* controllers.py: İş mantığı ve rota fonksiyonları.
* config.py: Uygulama yapılandırması.
Modüler Uygulamalar (Bottle.mount())
Bottle, daha büyük uygulamaları yönetmek için alt uygulamaları (sub-applications) veya modülleri birleştirmenize olanak tanır.
# admin_app.py
from bottle import Bottle, route
admin_app = Bottle()
@admin_app.route('/')
def admin_home():
return "Admin Paneli Ana Sayfası"
@admin_app.route('/users')
def admin_users():
return "Admin Kullanıcı Yönetimi"
main_app.py
from bottle import Bottle, route
from admin_app import admin_app # admin_app'i içe aktarın
main_app = Bottle()
@main_app.route('/')
def home():
return "Ana Uygulama Ana Sayfası"
'/admin' yolu altındaki tüm istekleri admin_app'e yönlendir
main_app.mount('/admin', admin_app)
if __name__ == '__main__':
main_app.run(host='localhost', port=8080)
Bu örnekte, admin_app adında ayrı bir Bottle uygulaması tanımlanır ve main_app içine /admin önekiyle monte edilir. Bu, uygulamanızı daha düzenli tutmanıza yardımcı olur.
Güvenlik
Bottle, güvenlik açıklarını otomatik olarak kapatmaz, ancak bazı temel önlemleri uygulamanız gerekir:
* XSS (Cross-Site Scripting): Şablon motorunuzun otomatik kaçış (auto-escaping) özelliğini kullandığından emin olun. Bottle’ın yerleşik şablon motoru ve Jinja2 gibi popüler motorlar bunu varsayılan olarak yapar.
* CSRF (Cross-Site Request Forgery): POST formları için CSRF jetonları kullanın. Bottle’ın yerleşik bir çözümü yoktur, ancak harici kütüphaneler (örneğin, bottle-csrf) entegre edilebilir.
* SQL Enjeksiyonu: Veritabanı sorgularında parametreli sorguları (prepared statements) kullanın. Yukarıdaki SQLite örneğinde ? kullanarak bunu zaten yaptık. Asla kullanıcı girdisini doğrudan SQL sorgularına eklemeyin.
* Kimlik Doğrulama ve Yetkilendirme: Kendi kimlik doğrulama sisteminizi uygulayabilir veya bottle-auth gibi kütüphaneleri kullanabilirsiniz.
* Oturum Yönetimi: Bottle’ın yerleşik bir oturum yönetimi yoktur. bottle-session gibi eklentiler veya Redis gibi harici bir oturum deposu kullanabilirsiniz.
Test Etme
Uygulamanızın doğru çalıştığından emin olmak için testler yazmak önemlidir. unittest veya pytest gibi Python test çerçevelerini kullanabilirsiniz. Bottle uygulamalarını test etmek için HTTP isteklerini simüle edebilirsiniz.
from bottle import Bottle
import unittest
Test edilecek uygulama
app = Bottle()
@app.route('/')
def index():
return "Test Ana Sayfa"
@app.route('/hello/')
def hello(name):
return f"Merhaba, {name}!"
class TestMyApp(unittest.TestCase):
def test_index_route(self):
# Uygulamayı test modunda çalıştırın
response = app.get('/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.text, "Test Ana Sayfa")
def test_hello_route(self):
response = app.get('/hello/World')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.text, "Merhaba, World!")
def test_404_route(self):
response = app.get('/nonexistent')
self.assertEqual(response.status_code, 404)
if __name__ == '__main__':
unittest.main()
Bu, Bottle uygulamanızı test etmek için temel bir yaklaşımdır. Daha karmaşık testler için WebTest gibi kütüphaneler kullanılabilir.
Sonuç
Bottle, Python web geliştirme dünyasında minimalist, ancak şaşırtıcı derecede güçlü bir araçtır. Tek dosya yapısı, bağımlılıksız doğası ve öğrenme kolaylığı, onu hızlı prototipleme, mikroservisler ve küçük/orta ölçekli web uygulamaları için mükemmel bir seçim haline getirir. Bottle, “az daha çoktur” felsefesini benimseyerek, geliştiricilere çekirdek işlevsellik sunar ve geri kalanını kendi ihtiyaçlarına göre şekillendirme özgürlüğü verir.
Bu makalede, Bottle’ın kurulumundan başlayarak, yönlendirme, istek/yanıt yönetimi, şablonlar, statik dosyalar, veritabanı entegrasyonu, form işleme, hata yönetimi, eklentiler ve dağıtım gibi temel ve ileri düzey konuları ele aldık. Bottle’ın nasıl çalıştığını ve web uygulamalarınızı geliştirmek için onu nasıl kullanabileceğinizi artık daha iyi anlamış olmalısınız.
Bottle’ı seçmek, projeniz üzerinde daha fazla kontrol sahibi olmak ve gereksiz karmaşıklıktan kaçınmak anlamına gelir. İhtiyaçlarınız basitse ve projenizi sıfırdan inşa etmenin keyfini çıkarmak istiyorsanız, Bottle sizin için doğru çerçeve olabilir. Kendi web uygulamalarınızı Bottle ile geliştirmeye başlamaktan çekinmeyin!