FA-TOOLS — Header Component
آموزش SQLite با پایتون — دیتابیس سبک

آموزش SQLite با پایتون — دیتابیس سبک

رفیق برنامه‌نویس، دنبال یه راه حل ساده و قدرتمند برای مدیریت داده‌ها توی پروژه‌هات هستی؟ SQLite و پایتون مثل آب و آتیش با هم جورن و ترکیبشون دنیایی از امکانات رو برات باز می‌کنه. اگه می‌خوای کد نویسی رو حرفه‌ای‌تر شروع کنی و ابزارت همیشه دم دست باشه، همین الان یه سر به
فروشگاه ابزارهای برنامه‌نویسی ما
بزن و بهترین اسنیپت‌ها و ابزارها رو برای خودت پیدا کن! برای مشاوره و راهنمایی هم می‌تونی با شماره
09202232789
تماس بگیری.

نقشه راه: SQLite و پایتون در یک نگاه

آموزش SQLite با پایتون — دیتابیس سبک — تصویر 1

۱. شروع کار 🚀

  • SQLite چیست؟
  • چرا پایتون و SQLite؟
  • نصب و آماده‌سازی

۲. اولین دیتابیس 📝

  • اتصال به دیتابیس
  • ساخت جدول
  • وارد کردن داده (INSERT)

۳. عملیات CRUD 🛠️

  • خواندن (SELECT)
  • بروزرسانی (UPDATE)
  • حذف (DELETE)

۴. ترفندهای حرفه‌ای

  • پارامترها و امنیت
  • مدیریت خطا
  • کاربردها

مقدمه: چرا SQLite برای پایتون‌کارها ضروریه؟

آموزش SQLite با پایتون — دیتابیس سبک — تصویر 2

اگه برنامه‌نویس پایتون باشی، حتماً بارها با نیاز به ذخیره‌سازی داده‌ها مواجه شدی. از یه اپلیکیشن کوچیک دسکتاپ گرفته تا یه اسکریپت که باید وضعیت خودش رو حفظ کنه، همه جا لازمه که اطلاعات رو یه جوری نگه داری. اینجاست که SQLite وارد میدون میشه. یه دیتابیس سبک، سریع و فوق‌العاده کاربردی که بدون دردسرهای نصب و کانفیگ یه سرور دیتابیس بزرگ (مثل PostgreSQL یا MySQL)، مستقیم توی فایل کار می‌کنه.

مزیت بزرگش اینه که چون خودش یه فایل دیتابیس هست، نه یه سرور جداگانه، خیلی راحت می‌تونی اپلیکیشن‌هات رو قابل حمل (portable) کنی. کافیه فایل دیتابیس رو با کدها همراه کنی و تمام! این ویژگی باعث شده SQLite انتخاب اول برای اپلیکیشن‌های موبایل، دسکتاپ، مرورگرهای وب و حتی پروژه‌های کوچیک بک‌اند باشه. حالا تصور کن این قدرت با انعطاف‌پذیری پایتون ترکیب بشه؛ یه زوج هنری واقعی!

SQLite چیست و چرا با پایتون؟

آموزش SQLite با پایتون — دیتابیس سبک — تصویر 3

SQLite یه سیستم مدیریت دیتابیس رابطه‌ای (RDBMS) هست که برخلاف دیتابیس‌های سنتی، نیازی به پروسس سرور مجزا برای اجرا نداره. در واقع، کل دیتابیس (تعریف جداول، داده‌ها و ایندکس‌ها) توی یه فایل دیسک معمولی ذخیره میشه. این یعنی نیازی به نصب و کانفیگ پیچیده نداری و می‌تونی مستقیماً از داخل اپلیکیشنت باهاش کار کنی.

چرا پایتون با SQLite؟

  • ماژول داخلی: خبر خوب اینه که پایتون از نسخه‌ی 2.5 به بعد، ماژول sqlite3 رو به صورت پیش‌فرض همراه خودش داره. نیازی به نصب پکیج اضافی نیست! این یعنی می‌تونی فوراً شروع به کار کنی. اگر دنبال کدهای آماده پایتون می‌گردی، حتماً به بخش اسنیپت‌های ما سر بزن.
  • سادگی و سرعت: پایتون زبانی ساده و خواناست. ترکیب این سادگی با سادگی SQLite، فرآیند توسعه رو خیلی سریع‌تر می‌کنه. برای پروتوتایپینگ، پروژه‌های شخصی و اپلیکیشن‌های با حجم داده متوسط، بهترین گزینه هستن.
  • جامعیت: پایتون ابزارهای زیادی برای کار با داده‌ها (مثل Pandas) و ساخت UI (مثل PyQt/Tkinter) داره. SQLite به راحتی با این ابزارها ادغام میشه و یه راه حل کامل بهت میده.
  • قابل حمل بودن: همونطور که گفتیم، دیتابیس یه فایل هست. پس جابجایی و بک‌آپ گرفتن ازش خیلی آسونه.

نصب و راه‌اندازی (هیچ نیازی نیست!)

برخلاف سایر دیتابیس‌ها، برای SQLite نیازی به مرحله نصب خاصی نیست. همونطور که بالا گفتم، ماژول sqlite3 بخشی از کتابخانه استاندارد پایتونه. فقط کافیه پایتون روی سیستمت نصب باشه.

اتصال به دیتابیس

اولین قدم، ایجاد اتصال به دیتابیسه. اگه فایل دیتابیس وجود نداشته باشه، SQLite خودش یه فایل جدید می‌سازه.


import sqlite3

# اتصال به دیتابیس
# اگر فایل دیتابیس وجود نداشته باشد، ساخته می‌شود.
# اگر به جای 'mydb.db' از ':memory:' استفاده کنی، دیتابیس فقط در حافظه رم ایجاد شده و با پایان برنامه حذف می‌شود.
conn = sqlite3.connect('my_first_database.db')

# ایجاد یک شیء Cursor برای اجرای دستورات SQL
# Cursor مثل نشانگر یا پوینتریه که امکان اجرای دستورات و پیمایش نتایج رو میده
cursor = conn.cursor()

print("اتصال به دیتابیس با موفقیت برقرار شد!")

# فراموش نکن که در پایان کار، اتصال رو ببندی
# conn.close()
    

یه نکته مهم: همیشه یادت باشه که بعد از اتمام کار با دیتابیس، اتصال رو با conn.close() ببندی. این کار منابع رو آزاد می‌کنه و تضمین می‌کنه تغییراتت ذخیره میشن.

ساخت جدول

بعد از اتصال، باید جدول(ها)ی مورد نیازت رو بسازی. این کار با دستور SQL CREATE TABLE انجام میشه.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# ساخت یک جدول جدید به نام 'users'
# اگر جدول از قبل وجود داشته باشد، خطای دوباره ساخت نمی‌دهد (IF NOT EXISTS)
cursor.execute('''
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT NOT NULL UNIQUE,
        email TEXT NOT NULL,
        age INTEGER
    )
''')

# ذخیره تغییرات (commit) در دیتابیس
# بدون commit، تغییرات اعمال نمی‌شوند
conn.commit()

print("جدول 'users' با موفقیت ایجاد یا موجود بود!")

conn.close()
    

توی این کد، INTEGER PRIMARY KEY AUTOINCREMENT به این معنیه که ستون id یک عدد صحیح منحصر به فرد و خودکار افزایشی (مثل یه شماره سریال) برای هر ردیف جدید خواهد بود. TEXT NOT NULL UNIQUE هم یعنی ستون username باید متنی باشه، نمیتونه خالی باشه و مقدارش باید توی کل جدول منحصر به فرد باشه.

عملیات CRUD با پایتون و SQLite

CRUD مخفف Create (ساخت)، Read (خواندن)، Update (بروزرسانی) و Delete (حذف) هست که چهار عمل اصلی در مدیریت داده‌ها محسوب میشن.

وارد کردن داده (Create – INSERT)

برای افزودن ردیف‌های جدید به جدول، از دستور INSERT INTO استفاده می‌کنیم.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# وارد کردن یک ردیف داده
cursor.execute("INSERT INTO users (username, email, age) VALUES ('ali_d', 'ali@example.com', 30)")

# وارد کردن چند ردیف داده به صورت همزمان (بهتر و ایمن‌تر)
users_data = [
    ('reza_kh', 'reza@example.com', 25),
    ('sara_mn', 'sara@example.com', 22),
    ('mina_z', 'mina@example.com', 28)
]
cursor.executemany("INSERT INTO users (username, email, age) VALUES (?, ?, ?)", users_data)

conn.commit()
print("داده‌ها با موفقیت وارد شدند.")
conn.close()
    

استفاده از ? به عنوان placeholder برای مقادیر، روش ایمن‌تری برای جلوگیری از SQL Injection هست که جلوتر بیشتر در موردش حرف می‌زنیم.

خواندن داده (Read – SELECT)

برای بازیابی اطلاعات از جدول، دستور SELECT کاربرد داره.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# خواندن همه داده‌ها از جدول
cursor.execute("SELECT * FROM users")
all_users = cursor.fetchall() # دریافت همه ردیف‌ها
print("همه کاربران:")
for user in all_users:
    print(user)

# خواندن ردیف‌های خاص با شرط WHERE
cursor.execute("SELECT username, email FROM users WHERE age > 25")
older_users = cursor.fetchall()
print("nکاربران بالای ۲۵ سال:")
for user in older_users:
    print(user)

# خواندن فقط یک ردیف
cursor.execute("SELECT * FROM users WHERE username = 'ali_d'")
single_user = cursor.fetchone() # دریافت یک ردیف
print("nکاربر ali_d:")
print(single_user)

conn.close()
    

توابع fetchall() همه ردیف‌ها را برمی‌گرداند، fetchone() تنها یک ردیف را و fetchmany(size) تعداد مشخصی ردیف را.

بروزرسانی داده (Update – UPDATE)

برای تغییر مقادیر موجود در ردیف‌ها، از دستور UPDATE استفاده می‌کنیم.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# بروزرسانی آدرس ایمیل یک کاربر
cursor.execute("UPDATE users SET email = 'ali.updated@example.com' WHERE username = 'ali_d'")

conn.commit()
print("کاربر 'ali_d' بروزرسانی شد.")

# برای مشاهده تغییر
cursor.execute("SELECT * FROM users WHERE username = 'ali_d'")
print(cursor.fetchone())

conn.close()
    

حذف داده (Delete – DELETE)

برای پاک کردن ردیف‌ها از جدول، دستور DELETE FROM کاربرد داره.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# حذف یک کاربر بر اساس username
cursor.execute("DELETE FROM users WHERE username = 'sara_mn'")

conn.commit()
print("کاربر 'sara_mn' حذف شد.")

# برای اطمینان از حذف، دوباره لیست کاربران را بخوانیم
cursor.execute("SELECT * FROM users")
print("nلیست کاربران پس از حذف:")
for user in cursor.fetchall():
    print(user)

conn.close()
    

اخطار: همیشه با دقت از WHERE در دستورات UPDATE و DELETE استفاده کن، در غیر این صورت ممکنه کل جدول رو حذف یا بروزرسانی کنی!

کمی پیشرفته‌تر: پارامترها و جلوگیری از SQL Injection

یکی از مهم‌ترین نکات امنیتی در کار با دیتابیس‌ها، جلوگیری از حملات SQL Injection هست. این حملات زمانی اتفاق میفتن که ورودی کاربر مستقیماً وارد دستور SQL میشه و مهاجم می‌تونه با تزریق کدهای مخرب، دیتابیس رو دستکاری کنه.

ماژول sqlite3 پایتون یه راه حل عالی و امن برای این مشکل داره: استفاده از placeholders (?) و ارسال مقادیر به صورت tuple یا list.


import sqlite3

conn = sqlite3.connect('my_first_database.db')
cursor = conn.cursor()

# مثال ناامن (که نباید استفاده کنی!)
# user_input = "'; DROP TABLE users;--"
# cursor.execute(f"SELECT * FROM users WHERE username = '{user_input}'")

# مثال امن با استفاده از placeholder
user_to_find = 'reza_kh'
cursor.execute("SELECT * FROM users WHERE username = ?", (user_to_find,))
found_user = cursor.fetchone()
print(f"کاربر پیدا شده (امن): {found_user}")

# اضافه کردن یک کاربر جدید با ورودی امن
new_username = "javad_m"
new_email = "javad@example.com"
new_age = 35
cursor.execute("INSERT INTO users (username, email, age) VALUES (?, ?, ?)", (new_username, new_email, new_age))
conn.commit()
print(f"کاربر {new_username} به صورت امن اضافه شد.")

conn.close()
    

وقتی از ? استفاده می‌کنی، sqlite3 خودش مقادیر رو به درستی escape می‌کنه و از هرگونه تزریق SQL جلوگیری می‌شه. این کار باعث میشه کدهای تو در برابر حملات خیلی مقاوم‌تر بشن. همیشه از این روش برای وارد کردن مقادیر داینامیک استفاده کن. اگه دنبال اسنیپت‌های امن و کارآمد هستی، حتماً نگاهی به بخش اسنیپت‌های ما بنداز.

مدیریت خطاها و تراکنش‌ها

در برنامه‌نویسی حرفه‌ای، مدیریت خطاها یه بخش جدایی‌ناپذیره. ممکنه حین کار با دیتابیس خطاهای مختلفی مثل تکرار مقدار UNIQUE، خطای اتصال و … پیش بیاد.

استفاده از بلوک try...except...finally بهت کمک می‌کنه تا این خطاها رو به درستی مدیریت کنی. همچنین تراکنش‌ها (Transactions) نقش حیاتی در حفظ یکپارچگی داده‌ها دارن. اگه چند عملیات دیتابیسی (مثل انتقال پول از یک حساب به حساب دیگر) داری که باید همگی با موفقیت انجام بشن یا هیچ‌کدام، از تراکنش استفاده می‌کنی.


import sqlite3

conn = None # تعریف اولیه اتصال به عنوان None
try:
    conn = sqlite3.connect('my_first_database.db')
    cursor = conn.cursor()

    # شروع تراکنش
    conn.execute("BEGIN")

    # یک عملیات موفقیت آمیز
    cursor.execute("INSERT INTO users (username, email, age) VALUES (?, ?, ?)", ('maryam_a', 'maryam@example.com', 29))

    # یک عملیات ناموفق (تکرار username که UNIQUE است)
    # این خط باعث خطا می‌شود و تراکنش برمی‌گردد (rollback)
    cursor.execute("INSERT INTO users (username, email, age) VALUES (?, ?, ?)", ('ali_d', 'ali2@example.com', 31)) # ali_d قبلاً وجود دارد!

    conn.commit() # اگر خطایی رخ ندهد، تغییرات اعمال می‌شوند
    print("تراکنش با موفقیت انجام شد.")

except sqlite3.IntegrityError as e:
    print(f"خطای یکپارچگی داده: {e}")
    if conn:
        conn.rollback() # در صورت خطا، همه تغییرات تراکنش لغو می‌شوند
        print("تراکنش بازگشت (rollback) شد.")
except sqlite3.Error as e:
    print(f"یک خطای دیتابیس رخ داد: {e}")
    if conn:
        conn.rollback()
        print("تراکنش بازگشت (rollback) شد.")
finally:
    if conn:
        conn.close()
        print("اتصال به دیتابیس بسته شد.")

# برای بررسی اینکه آیا maryam_a اضافه شد یا نه (باید اضافه شده باشد اگر ali_d خطایی نداد)
# و ali_d با ایمیل تکراری اضافه نشد.
print("nبررسی وضعیت دیتابیس:")
conn_check = sqlite3.connect('my_first_database.db')
cursor_check = conn_check.cursor()
cursor_check.execute("SELECT * FROM users")
for user in cursor_check.fetchall():
    print(user)
conn_check.close()
    

در این مثال، چون سعی کردیم یک username تکراری (ali_d) وارد کنیم، دستور دوم با خطای IntegrityError مواجه میشه و بخش except اجرا میشه. سپس conn.rollback() تمام عملیات انجام شده در این تراکنش (حتی وارد کردن maryam_a) رو لغو می‌کنه. این تضمین می‌کنه که دیتابیس شما همیشه در وضعیت سازگار باقی میمونه.

مقایسه SQLite و دیتابیس‌های بزرگ‌تر (مثلاً PostgreSQL)

هر ابزاری برای کار خاصی ساخته شده. SQLite هم همینطوره و نمیشه اون رو با دیتابیس‌های سطح سازمانی مقایسه کرد، اما هر کدوم کاربردهای خاص خودشون رو دارن.

جدول مقایسه SQLite و PostgreSQL
ویژگی SQLite
معماری فایل‌محور، بدون نیاز به سرور
نصب و راه‌اندازی نیاز به نصب ندارد (با پایتون همراه است)
کاربرد اصلی اپلیکیشن‌های دسکتاپ/موبایل، پروژه‌های کوچک، توسعه لوکال، کش‌کردن داده
همزمانی (Concurrency) فقط یک عملیات Write در یک زمان
مقیاس‌پذیری محدود، برای حجم بالای داده و تعداد زیاد کاربر مناسب نیست

اگه پروژه‌ات نیاز به دیتابیس قوی‌تر برای وب‌سایت‌های پربازدید یا اپلیکیشن‌های سازمانی داره، PostgreSQL یا MySQL گزینه‌های بهتری هستن. اما برای شروع، نمونه‌سازی سریع و پروژه‌های مستقل، SQLite یک شاهکار به تمام معناست.

موارد استفاده عملی SQLite

حالا که با اصول کار آشنا شدی، بیا چند مورد استفاده واقعی و کاربردی SQLite رو با هم مرور کنیم:

  • اپلیکیشن‌های دسکتاپ: برنامه‌هایی مثل مرورگرهای وب (Chrome, Firefox)، کلاینت‌های ایمیل و حتی نرم‌افزارهای مدیریت فایل از SQLite برای ذخیره‌سازی تنظیمات، تاریخچه و سایر داده‌های کاربر استفاده می‌کنن.
  • توسعه محلی و تست: توی مراحل توسعه وب‌اپلیکیشن‌ها، استفاده از SQLite برای محیط لوکال خیلی راحت‌تر از راه‌اندازی یه سرور دیتابیس کامله.
  • کش‌کردن داده: برای ذخیره موقت داده‌ها از APIها یا وب‌سایت‌ها، SQLite می‌تونه به عنوان یه کش کارآمد عمل کنه و سرعت برنامه‌ات رو بالا ببره.
  • پروژه‌های شخصی و اسکریپت‌ها: اگه یه اسکریپت پایتون می‌نویسی که نیاز به ذخیره وضعیت یا لاگ داره، SQLite بهترین انتخابه. مثلاً برای اسکریپت‌های پایتونی که داده‌ها رو جمع‌آوری می‌کنن و می‌خوان ذخیره‌اش کنن.
  • اینترنت اشیا (IoT): با توجه به منابع محدود در دستگاه‌های IoT، SQLite به دلیل سبکی و عدم نیاز به سرور، گزینه مناسبی برای ذخیره‌سازی داده‌ها در خود دستگاه‌هاست.

عیب‌یابی سریع: مشکلات رایج و راه‌حل‌ها

مشکلات متداول در SQLite با پایتون

  1. خطای sqlite3.OperationalError: database is locked:

    علت: این خطا زمانی رخ می‌دهد که دو یا چند پروسه سعی کنند همزمان روی یک دیتابیس SQLite عملیات Write (نوشتن) انجام دهند. SQLite فقط یک عملیات Write در هر لحظه را پشتیبانی می‌کند. گاهی اوقات هم اتصال قبلی به درستی بسته نشده.

    راه‌حل:

    • مطمئن شوید که همیشه پس از اتمام کار با دیتابیس، conn.close() را فراخوانی می‌کنید.
    • برای عملیات‌های Write، از conn.commit() استفاده کنید.
    • اگر در محیط چند رشته‌ای (multithreaded) کار می‌کنید، استفاده از لاک (threading.Lock) برای همگام‌سازی دسترسی به دیتابیس یا استفاده از دیتابیس‌های چند-پردازشی (multiprocess) مثل PostgreSQL توصیه می‌شود.
    • گاهی اوقات یک کلاینت دیگر (مثل DB Browser for SQLite) فایل دیتابیس را باز نگه داشته است؛ آن را ببندید.
  2. خطای sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 3, and there are 1 supplied.:

    علت: تعداد ? (placeholders) در دستور SQL با تعداد مقادیری که در tuple یا list به متد execute داده‌اید، مطابقت ندارد.

    راه‌حل:

    • دوباره دستور SQL و tuple مقادیر را بررسی کنید و مطمئن شوید تعدادشان برابر است.
    • اگر فقط یک مقدار دارید، حتماً آن را به صورت یک tuple با کامای انتهایی (مثلاً (value,)) ارسال کنید.
  3. خطای sqlite3.OperationalError: no such table: your_table_name:

    علت: سعی کرده‌اید روی جدولی عملیات انجام دهید که هنوز ساخته نشده یا نام آن اشتباه است.

    راه‌حل:

    • مطمئن شوید که دستور CREATE TABLE قبل از هرگونه عملیات روی آن جدول اجرا شده باشد.
    • املای نام جدول را در تمام دستورات خود بررسی کنید.
    • بررسی کنید که آیا فایل دیتابیس صحیح را باز کرده‌اید.
  4. داده‌ها ذخیره نمی‌شوند (پس از اجرای INSERT/UPDATE/DELETE):

    علت: پس از اجرای دستورات تغییردهنده داده (مثل INSERT، UPDATE، DELETE)، باید تغییرات را به دیتابیس commit کنید.

    راه‌حل:

    • همیشه پس از اجرای عملیات تغییردهنده داده، conn.commit() را فراخوانی کنید.
    • اگر فراموش کردید commit کنید و برنامه بسته شد، تغییرات از دست می‌روند.

نتیجه‌گیری: قدرت در سادگی

آموزش SQLite با پایتون یه سفر هیجان‌انگیز به دنیای دیتابیس‌های سبک و کارآمده. دیدی که چقدر راحت و بدون دردسر می‌تونی داده‌هات رو مدیریت کنی. از ایجاد دیتابیس و جدول گرفته تا انجام عملیات CRUD و مدیریت خطاها، همه و همه با چند خط کد پایتون قابل انجام هستن.

به یاد داشته باش که SQLite یه ابزار فوق‌العاده برای شروع، نمونه‌سازی سریع و اپلیکیشن‌های کوچیک و مستقل محسوب میشه. توانایی اون در جایگذاری به عنوان یک دیتابیس فایل‌محور و بدون سرور، اون رو به انتخابی ایده‌آل برای توسعه‌دهندگانی تبدیل می‌کنه که دنبال سادگی و قابلیت حمل هستن.

حالا نوبت توئه! این مفاهیم رو با پروژه‌های کوچیک خودت تمرین کن و ببین چطور می‌تونی از این ترکیب قدرتمند در کارهات استفاده کنی. اگه سوالی داشتی، فراموش نکن که همیشه می‌تونی به بخش اسنیپت‌های ما سر بزنی و از منابع موجود استفاده کنی. کد نویسی رو ادامه بده و از هر لحظه‌اش لذت ببر!

— پایان مقاله —

Table of Contents

آخرین نوشته‌ها