Program
FastHTML ve MongoDB, modern web geliştirme için yüksek hızlı, Python-yerel bir yaklaşım sunar. Bu eğitimde, tek bir, bakımı kolay Python dosyası içinde tam bir CRUD (Create, Read, Update, Delete) yaşam döngüsünü gösteren, tepkisel ve gerçek zamanlı bir görev yöneticisi uygulaması oluşturacağız. Python’da MongoDB kullanımıyla ilgili uygulamalı deneyim kazanmak için Introduction to MongoDB in Python kursunu öneririm.
FastHTML nedir?
FastHTML, FastAPI temelleri üzerine inşa edilmiş minimalist ve yüksek performanslı bir çerçevedir. Geliştiricilerin geleneksel şablonlar yerine yeniden kullanılabilir Python işlevleriyle tüm ön yüzleri kurmasına imkân veren Pythonik bir HTML paradigması sunar.
Temel gücü, HTMX ile olan yerel entegrasyonundan gelir. Sunucu tarafı güncellemelerini yönlendirmek için basit HTML özniteliklerini kullanan HTMX, JavaScript ağırlıklı bir derleme yığınının karmaşıklığı olmadan dinamik, tek sayfalık uygulama deneyimleri oluşturmanıza olanak tanır.
MongoDB nedir?
MongoDB, genel amaçlı, belge tabanlı NoSQL veritabanlarının lideridir. Esnek şeması ve JSON benzeri BSON belgeleri, onu modern ve yinelemeli geliştirme için ideal kılar.
Python için, FastAPI ve FastHTML’in performans odaklı mimarisine mükemmel uyum sağlayan, engellemeyen bir arayüz sunan resmi asenkron sürücü Motor’u kullanıyoruz.
Bu Yığın Neden Üstün
Bu teknolojileri birleştirmek son derece üretken bir geliştirme ortamı yaratır:
- Pydantic ve MongoDB tür güvenliği: FastHTML, veri modelleme ve doğrulama için Pydantic’ten yararlanır. Bu modeller, MongoDB’nin belge yapısına doğal biçimde eşlenerek ağır nesne-ilişkisel eşleme (ORM) şablon koduna olan ihtiyacı ortadan kaldıran “koda-öncelik” bir deneyim sunar.
- Uçtan uca asenkron performans: Motor’u FastHTML’in asenkron çekirdeğiyle eşleştirerek veritabanı işlemlerinin olay döngüsünü asla engellememesini sağlarız. Bu da gerçek zamanlı, tepkisel uygulamalar için kritik olan yüksek eşzamanlılık ve düşük gecikme sunar.
- Azaltılmış bağlam değişimi: Geliştiriciler, veritabanı şemasını, arka uç mantığını ve ön uç bileşenlerini tek birleştirilmiş Python ekosistemi içinde yönetebilir, böylece teslimat hızını önemli ölçüde artırır.
Kurulum ve Bağlantı
Bu eğitimi adım adım takip edebilmek için bazı ön koşullar vardır:
- Python 3.8+
- MongoDB örneği: yerel bir kurulum veya MongoDB Atlas kümesi (gerçek zamanlı özellikler için önerilir)
- Temel bilgi: Python dekoratörleri ve temel HTML yapısına aşinalık.
Proje başlatma
Bu yığının verimliliğini göstermek için, veritabanı yapılandırması, veri modelleri ve tepkisel yönlendirmeler dâhil olmak üzere tüm uygulamayı tek bir app.py dosyası içinde uygulayacağız.
Kurulum
FastHTML çerçevesine, Motor’a (resmi asenkron MongoDB sürücüsü) ve ASGI sunucusu için Uvicorn’a ihtiyacımız var.
MongoDB bağlantı kurulumu
Engellemeyen bir bağlantı kurmak için AsyncIOMotorClient kullanıyoruz. Bu sayede uygulamanız veritabanı G/Ç’sini beklerken diğer eşzamanlı istekleri işlemeye devam edebilir.
import os
from motor.motor_asyncio import AsyncIOMotorClient
from fasthtml.common import *
from bson import ObjectId
from pydantic import Field, BaseModel
from pymongo.errors import ServerSelectionTimeoutError, ConnectionFailure
# configure MongoDB
MONGO_URI = os.environ.get("MONGO_URI", "mongodb://localhost:27017/") # your Mongo URI
DB_NAME = "fasthtml_tasks_db"
COLLECTION_NAME = "tasks"
# Initialize the async client and reference our collections
client = AsyncIOMotorClient(MONGO_URI)
db = client[DB_NAME]
collection = db[COLLECTION_NAME]
# FastHTML Application Initialization
app = FastHTML()
Veri modelini tanımlama
Belge odaklı bir iş akışında şema, uygulama kodunuzda yaşar. MongoDB’nin BSON ObjectId türü ile standart Python dizgileri arasındaki boşluğu kapatmak için Pydantic v2 kullanıyoruz. Bu, veritabanımıza giren veya çıkan her belgenin gereksinimlerimize göre doğrulanmasını sağlar.
Özel bir PyObjectId sınıfı tanımlıyoruz. Bu gereklidir çünkü Pydantic, MongoDB ObjectId türünü yerel olarak nasıl işleyeceğini bilmez. __get_pydantic_core_schema__ kullanarak, Pydantic’e bu türü JSON’da dizgi olarak ele almasını ancak veritabanı için BSON nesnesi olarak doğrulamasını söylüyoruz.
python
from pydantic import BaseModel, Field
from pydantic_core import core_schema
from pydantic.json_schema import JsonSchemaValue
class PyObjectId(ObjectId):
"""Custom type to bridge MongoDB ObjectId and Pydantic v2 validation."""
@classmethod
def __get_pydantic_core_schema__(cls, source_type, handler):
# Defines how Pydantic should validate this type
return core_schema.no_info_plain_validator_function(cls.validate)
@classmethod
def validate(cls, v):
if isinstance(v, ObjectId): return v
if isinstance(v, str) and ObjectId.is_valid(v): return ObjectId(v)
raise ValueError("Invalid ObjectId")
@classmethod
def __get_pydantic_json_schema__(cls, _core_schema, handler) -> JsonSchemaValue:
# Ensures the OpenAPI/JSON schema reflects this as a string
return {"type": "string"}
class Task(BaseModel):
"""Pydantic model representing the Task document schema."""
# Maps MongoDB's internal '_id' to a developer-friendly 'id' field
id: PyObjectId | None = Field(None, alias='_id')
title: str
description: str | None = None
completed: bool = False
model_config = ConfigDict(
arbitrary_types_allowed=True
)
Yerleşim ve ilk rota
Yerleşim bileşeni, görünümlerimizi saran, yeniden kullanılabilir üst düzey bir işlevdir. Bu, stillendirme için Tailwind CSS ve etkileşim için HTMX gibi temel bağımlılıkların tüm uygulama genelinde tutarlı olmasını sağlar.
FastHTML’in baş harfi büyük bileşenlerini (Main ve Div gibi) kullanarak, HTML ağacını yansıtan temiz ve Pythonik bir yapı koruruz.
# A responsive layout using Tailwind CSS and the HTMX CDN
def layout(*comps):
"""Wraps the application content in a consistent container."""
return Main(
Div(
H1('📝 Real-Time FastHTML Task Manager',
cls='text-3xl font-bold mb-8 text-center text-gray-800'),
*comps,
cls='container mx-auto p-6 max-w-2xl'
)
)
@app.get('/')
async def home():
"""Initial route rendering the core application layout."""
return layout(
await TaskList(), # Fetches and displays existing tasks (Read)
TaskForm() # Renders the entry form (Create)
)
Şimdi uygulamayı çalıştırırsanız, kullanıcı arayüzünüz şöyle görünecek:

Görsel: kurulum sonrası ekran görüntüsü
Henüz hiç görev yok. Bir sonraki bölümde görev ekleme ve güncelleme üzerinde çalışacağız.
Tam CRUD Uygulaması
Read: Görevleri görüntüleme (GET /)
Görevleri görüntülemek için tüm belgeleri alır ve bir bileşen içinde işleriz. Ancak gerçek dünyada veritabanı çevrimdışı olabilir. Güncellenmiş TaskList bileşenimiz, sorun giderme adımlarını doğrudan UI içinde sunarak bu durumu zarifçe ele alır.
Dayanıklı veri getirme
Belgeleri asenkron şekilde almak için collection.find().to_list(length=None) kullanıyoruz. Bunu bir try/except bloğuna alarak MongoDB’nin bağlantısının kesilip kesilmediğini tespit edip kullanıcıya anında geri bildirim sağlayabiliriz.
async def TaskList():
"""Fetches documents from MongoDB and hydrates the Task list view with error handling."""
try:
tasks_data = await collection.find().to_list(length=None)
tasks = [Task(**doc) for doc in tasks_data]
except (ServerSelectionTimeoutError, ConnectionFailure, Exception) as e:
# Catch MongoDB connection errors and provide troubleshooting tips
return Div(
H2('Current Tasks', cls='text-xl font-semibold mb-4'),
Div(
P('⚠️ MongoDB is not running.', cls='text-red-600 font-semibold mb-2'),
P('To start MongoDB:', cls='text-gray-600 mb-1'),
P('1. brew install mongodb-community', cls='text-gray-500 text-sm ml-4'),
P('2. brew services start mongodb-community', cls='text-gray-500 text-sm ml-4'),
cls='p-4 bg-yellow-50 border border-yellow-200 rounded'
),
id='task-list'
)
return Div(
H2('Current Tasks', cls='text-xl font-semibold mb-4'),
*[TaskItem(task) for task in tasks] if tasks else P('No tasks yet. Add one below!', cls='text-gray-500 italic p-4'),
id='task-list',
cls='bg-white rounded-lg shadow-sm border border-gray-200'
)
Create: Yeni bir görev ekleme
Oluşturma akışı, HTMX öznitelikleriyle güçlendirilmiş bir HTML formu kullanır. Güncellenmiş sürümde, form verilerini açıkça Request nesnesinden çıkarır ve MongoDB’ye ekleme için belgeyi hazırlamak üzere model_dump kullanırız.
@app.post('/add-task')
async def add_task(req: Request):
"""Create: Inserts a task and returns the refreshed list."""
try:
form_data = await req.form()
task = Task(
title=form_data.get('title', ''),
description=form_data.get('description') or None
)
# model_dump(by_alias=True) ensures 'id' is converted back to '_id' for Mongo
task_dict = task.model_dump(exclude_none=True, by_alias=True)
# Remove _id if it's None so MongoDB can generate its own unique ID
if '_id' in task_dict and task_dict['_id'] is None:
del task_dict['_id']
await collection.insert_one(task_dict)
return await TaskList()
except Exception as e:
return Div(P(f'Error: {str(e)}', cls='text-red-500 p-4'), id='task-list')
Aşağıdaki kodu terminalde çalıştırırsak:
curl -X POST http://localhost:8000/add-task -d "title=Complete FastHTML MongoDB integration" -d "description=Verify that tasks can be created, updated, and deleted successfully" -H "Content-Type: application/x-www-form-urlencoded"
Bu yeni görevin eklendiğini görebilirsiniz:
Görsel: bir görev eklendikten sonra ekran görüntüsü
Update: Tamamlanma durumunu değiştirme
Güncellemeleri ele almak için bir PATCH isteği kullanırız. Bu, yalnızca tek bir görev satırının veritabanında güncellendiği ve belirli kimliği kullanılarak UI’da yeniden oluşturulduğu bir “mikro yenileme”yi gösterir.
@app.patch('/toggle-task/{task_id}')
async def toggle_task(task_id: str):
"""Update: Toggles completion status and returns the single row fragment."""
task_doc = await collection.find_one({"_id": ObjectId(task_id)})
if not task_doc: raise HTTPException(404, "Task not found")
await collection.update_one(
{"_id": ObjectId(task_id)},
{"$set": {"completed": not task_doc['completed']}}
)
# Return only the updated TaskItem for a surgical DOM update
updated_doc = await collection.find_one({"_id": ObjectId(task_id)})
return TaskItem(Task(**updated_doc))
Delete: Bir görevi kaldırma
Silme işlemi HTMX tarafından tetiklenir. MongoDB silmeyi onayladığında, sunucu bir Empty() yanıtı döndürür. HTMX, bu boş yanıtı hedef öğeyi (en yakın div) DOM’dan kaldırma işareti olarak yorumlar.
@app.delete('/delete-task/{task_id}')
async def delete_task(task_id: str):
"""Delete: Removes a task from MongoDB."""
await collection.delete_one({"_id": ObjectId(task_id)})
# Signal HTMX to remove the element
return Empty()
Şunu yaparsak…
curl -X DELETE http://localhost:8000/delete-task/695968244236010c04f313fa
…görev silinir.

Görsel: silme işleminden sonra ekran görüntüsü
Tüm betiği GitHub’da bulabilirsiniz.
Sonuç
Modern, Python merkezli bir yığından yararlanarak, istemci tarafı JavaScript çerçevelerinin geleneksel karmaşıklığından kaçınan tepkisel bir uygulama oluşturdunuz. Bu özel mimari, modern web geliştirme için birkaç temel avantaj sağlar. FastHTML’in bileşen tabanlı UI’ı ile MongoDB’nin esnek belge modeli arasındaki uyum, iş mantığını, veri bütünlüğünü ve sunumu tek ve uyumlu bir ekosistemde sürdürmenize olanak tanır. Bu “tamamen Python ile” yaklaşım, geliştirme yükünü ve dağıtım karmaşıklığını önemli ölçüde azaltır.
Okuyucular için sonraki adımlar
- Kullanıcı kimlik doğrulama: Görev listelerini belirli kullanıcılara kısıtlamak için FastAPI bağımlılıklarını kullanın; görev belgesinde user_id saklayın.
- Gelişmiş sorgular: MongoDB’nin biriktirme (aggregation) çerçevesini veya basit filtreleri kullanarak UI’ınıza “Aktif” ve “Tamamlandı” görünümleri ekleyin.
- Dağıtım: app.py dosyanızı üretim düzeyinde performans için bir NGINX ters proxy arkasında Uvicorn ile dağıtın.
FAQs
FastHTML ile MongoDB Change Streams kullanarak "push" güncellemeleri yapmak mümkün mü?
Evet! Hem Motor hem de FastHTML asenkron olduğu için, bir MongoDB değişim akışını dinlemek üzere Python async for döngüsünü kullanabilirsiniz. Ardından bunu, veritabanındaki bir belge değiştiğinde her bağlı kullanıcıya gerçek zamanlı güncellemeler göndermek için FastHTML’in EventStream’i (Sunucu Taraflı Olaylar) ile eşleştirebilirsiniz.
Neden MongoDB ile ham Python sözlükleri yerine Pydantic modelleri kullanmalıyım?
MongoDB ham sözlükleri kabul etse de Pydantic sizin "uygulama şemanız" olarak görev yapar. Veri doğrulama, tür ipuçları ve (örneğin completed alanını otomatik olarak False yapma gibi) varsayılan değerler sağlar. Bu, "kirli verinin" koleksiyonunuza girmesini önler ve kodunuz büyüdükçe hata ayıklamayı çok daha kolay hâle getirir.
Bu yığınla veritabanı göçlerini (migrations) nasıl ele alırım?
MongoDB’nin en büyük güçlerinden biri esnek şemasıdır. Geleneksel SQL anlamında "göçlere" ihtiyacınız yoktur. Task modelinize yeni bir alan eklerseniz, Pydantic’te yalnızca bir varsayılan değer sağlayabilirsiniz. MongoDB’de bu alanı olmayan mevcut belgeler, uygulamanıza yüklendiklerinde varsayılan değerle "hidrate" edilir.
Bu görev yöneticisine karmaşık arama özellikleri ekleyebilir miyim?
Kesinlikle. MongoDB güçlü bir $text dizinine ve Lucene tabanlı daha da gelişmiş bir Atlas Search’e sahiptir. FastHTML’de, kullanıcı yazdıkça anahtar kelimelere göre görevleri filtrelemek için bir MongoDB biriktirme hattını tetikleyen hx-get kullanarak kolayca bir arama çubuğu oluşturabilirsiniz.
Bu yığın, Django veya Flask ile karşılaştırıldığında yüksek eşzamanlılığı nasıl yönetir?
FastHTML, FastAPI’den esinlenen ayrı bir çerçevedir. ASGI standardını kullanır ve tek bir süreçte binlerce eşzamanlı bağlantıyı yönetebilir. Motor’un engellemeyen bağlantı havuzu ile eşleştirildiğinde, uygulamanız veritabanı yanıtlarını beklerken "takılı kalmaz"; bu da yüksek trafikli, gerçek zamanlı uygulamalar için çok daha verimli olmasını sağlar.
Karen, ölçeklenebilir veri platformları kurma tutkusu olan bir Veri Mühendisidir. Terraform ile altyapı otomasyonu konusunda deneyime sahiptir ve öğrendiklerini blog yazıları ve eğitimlerde paylaşmaktan heyecan duyar. Karen bir topluluk geliştiricisidir ve veri profesyonelleri arasında bağlantılar kurmaya tutkuyla bağlıdır.
