AzLearn

مقدمة SQLAlchemy

Intro to SQLAlchemy

مفهوم ~22 دقيقة

مقدمة SQLAlchemy — Intro to SQLAlchemy

في الدروس السابقة كتبنا SQL مباشرةً: INSERT INTO users ...، SELECT * FROM contacts .... هذا النهج يمنحك تحكماً كاملاً ويُعلّمك الأساسيات — وهو ما يجب أن تفعله أولاً.

في المشاريع الكبيرة يبرز نهج مختلف: ORM (Object-Relational Mapper). بدلاً من كتابة SQL تعمل مع كائنات Python عادية، والـORM يُحوّل عملياتك إلى SQL في الخلفية.

SQLAlchemy هو أشهر ORM في عالم Python وأقواه.

ما هو ORM؟

ORM هو طبقة تُرجمة بين كائنات Python وجداول قاعدة البيانات:

كلاس Python  ←→  جدول SQL
كائن Python  ←→  صف في الجدول
خاصية كائن  ←→  عمود في الجدول

بدلاً من:

# SQL مباشر
cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ("أحمد", 28))

تكتب:

# ORM (SQLAlchemy)
session.add(User(name="أحمد", age=28))
session.commit()

والـORM يُولّد SQL في الخلفية تلقائياً.

النموذج التعريفي — Declarative Model

في SQLAlchemy تُعرّف جداولك كـكلاسات Python ترث من Base. كل خاصية في الكلاس تُقابل عموداً في الجدول.

هذا كود SQLAlchemy حقيقي يمكن تشغيله على جهازك بعد pip install sqlalchemy:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, Session

# المحرك — Engine (الاتصال بقاعدة البيانات)
engine = create_engine("sqlite:///myapp.db")

# الأساس التعريفي — Declarative base
Base = declarative_base()

# النموذج — Model (يُقابل جدول users)
class User(Base):
    __tablename__ = "users"   # اسم الجدول — table name

    id   = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String,  nullable=False)
    age  = Column(Integer, nullable=False)

    def __repr__(self):
        return f"User(id={self.id}, name={self.name!r}, age={self.age})"

# إنشاء الجداول — Create tables
Base.metadata.create_all(engine)

لاحظ: الكلاس User هو تعريف النموذج، لا كائن بيانات. SQLAlchemy يقرأ هذا الكلاس ويُنشئ الجدول عند استدعاء create_all.

الجلسة — Session

الجلسة (Session) هي الوحدة الأساسية للتعامل مع قاعدة البيانات في SQLAlchemy. تُتتبّع الكائنات المُضافة والمُعدّلة وتُرسل التغييرات دفعةً واحدة عند commit():

with Session(engine) as session:
    # إضافة مستخدم — Add user
    ahmed = User(name="أحمد", age=28)
    session.add(ahmed)
    session.commit()   # يُولّد: INSERT INTO users ...

    # إضافة عدة مستخدمين — Add multiple users
    session.add_all([
        User(name="فاطمة", age=24),
        User(name="عمر",   age=32),
    ])
    session.commit()

الاستعلام والفلترة — Query & Filter

with Session(engine) as session:
    # جلب الكل — Fetch all
    all_users = session.query(User).all()

    # فلترة — Filter
    young = session.query(User).filter(User.age < 30).all()

    # فلترة بالاسم — Filter by name
    ahmed = session.query(User).filter_by(name="أحمد").first()

    # ترتيب — Order
    sorted_users = session.query(User).order_by(User.age.desc()).all()

    # عدد — Count
    count = session.query(User).count()

التحديث والحذف — Update & Delete

with Session(engine) as session:
    # تحديث — Update
    user = session.query(User).filter_by(name="أحمد").first()
    user.age = 29           # تعديل الخاصية مباشرةً — modify attribute directly
    session.commit()        # SQLAlchemy يُولّد UPDATE تلقائياً

    # حذف — Delete
    user_to_delete = session.query(User).filter_by(name="عمر").first()
    session.delete(user_to_delete)
    session.commit()        # SQLAlchemy يُولّد DELETE تلقائياً

SQLAlchemy في المتصفح؟

SQLAlchemy لا يُتاح مباشرةً في Pyodide (البيئة التفاعلية في هذا الدرس). التمارين التفاعلية أدناه تستخدم sqlite3 مع تعليقات تُشير لما يُقابلها في SQLAlchemy — حتى تُطبّق المفاهيم وأنت تتعلمها، ثم تنتقل لـSQLAlchemy على جهازك.

مقارنة: sqlite3 مقابل SQLAlchemy

main.go

متى تستخدم sqlite3 ومتى تستخدم SQLAlchemy؟

الموقفالأنسب
تعلّم SQL والأساسياتsqlite3 مباشر
نماذج أولية سريعةsqlite3 مباشر
استعلامات معقدة + أداء حرجsqlite3 أو SQLAlchemy Core
مشروع متوسط إلى كبيرSQLAlchemy ORM
فريق يعمل معاًSQLAlchemy (عقد واضح عبر النماذج)
تغيير قاعدة البيانات مستقبلاًSQLAlchemy (تبديل create_engine فقط)

الفائدة الكبرى: قابلية التبديل

مع SQLAlchemy يمكنك كتابة نفس الكود ثم تبديل قاعدة البيانات بسطر واحد:

# SQLite للتطوير
engine = create_engine("sqlite:///dev.db")

# PostgreSQL في الإنتاج
engine = create_engine("postgresql://user:pass@localhost/prod")

لا يتغير شيء في كود النماذج أو الجلسات — فقط سلسلة الاتصال.

الاستعلام كـكائنات Python — ORM كاملاً

main.go

تثبيت SQLAlchemy وتجربته محلياً

بعد انتهاء هذا الدرس جرّب SQLAlchemy على جهازك:

pip install sqlalchemy

ثم انسخ الأمثلة من هذا الدرس وشغّلها. ستلاحظ أن السلوك مطابق — لكن الكود أوضح وأقل تكراراً.

تحدي — Challenge