في هذا الدرس سنتعلم كيف نمنح المستخدم القدرة على:
🎯 الهدف من الدرس:
تعلم كيفية تنفيذ عمليات CRUD المتقدمة (تحديدًا Update وDelete) على قاعدة البيانات في Flask.
🧩 الخطوة 1: تحديث ملف app.py
سنضيف مسارين جديدين:
/edit/<int:id>
لتعديل الملاحظة./delete/<int:id>
لحذف الملاحظة.
إليك الكود الكامل المحدث:
from flask import Flask, render_template, request, redirect, url_for
import sqlite3
app = Flask(__name__)
def get_db_connection():
conn = sqlite3.connect('notes.db')
conn.row_factory = sqlite3.Row
return conn
@app.route('/')
def index():
conn = get_db_connection()
notes = conn.execute('SELECT * FROM notes').fetchall()
conn.close()
return render_template('index.html', notes=notes)
@app.route('/add', methods=['POST'])
def add_note():
title = request.form['title']
content = request.form['content']
conn = get_db_connection()
conn.execute('INSERT INTO notes (title, content) VALUES (?, ?)', (title, content))
conn.commit()
conn.close()
return redirect(url_for('index'))
# 🖊️ تعديل الملاحظة
@app.route('/edit/<int:id>', methods=['GET', 'POST'])
def edit_note(id):
conn = get_db_connection()
note = conn.execute('SELECT * FROM notes WHERE id = ?', (id,)).fetchone()
if request.method == 'POST':
new_title = request.form['title']
new_content = request.form['content']
conn.execute('UPDATE notes SET title = ?, content = ? WHERE id = ?', (new_title, new_content, id))
conn.commit()
conn.close()
return redirect(url_for('index'))
conn.close()
return render_template('edit.html', note=note)
# 🗑️ حذف الملاحظة
@app.route('/delete/<int:id>')
def delete_note(id):
conn = get_db_connection()
conn.execute('DELETE FROM notes WHERE id = ?', (id,))
conn.commit()
conn.close()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
🧩 الخطوة 2: تعديل ملف index.html
نضيف زرين جديدين بجانب كل ملاحظة:
- زر “تعديل” يوجه إلى صفحة
/edit/<id>
- زر “حذف” يقوم بحذف الملاحظة مباشرة
ضع هذا الجزء داخل الحلقة {% for note in notes %}
بدلاً من الكود القديم:
<div class="col-md-4 mb-3">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">{{ note['title'] }}</h5>
<p class="card-text">{{ note['content'] }}</p>
<a href="/edit/{{ note['id'] }}" class="btn btn-warning btn-sm">تعديل ✏️</a>
<a href="/delete/{{ note['id'] }}" class="btn btn-danger btn-sm" onclick="return confirm('هل أنت متأكد من حذف هذه الملاحظة؟')">حذف 🗑️</a>
</div>
</div>
</div>
🧩 الخطوة 3: إنشاء صفحة edit.html
في مجلد templates/
أضف ملفًا جديدًا باسم edit.html
وضع بداخله هذا الكود:
<!DOCTYPE html>
<html lang="ar">
<head>
<meta charset="UTF-8">
<title>تعديل الملاحظة</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<h2 class="text-center mb-4">✏️ تعديل الملاحظة</h2>
<form method="POST" class="shadow p-4 bg-white rounded">
<div class="mb-3">
<label class="form-label">العنوان:</label>
<input type="text" name="title" value="{{ note['title'] }}" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">المحتوى:</label>
<textarea name="content" rows="4" class="form-control" required>{{ note['content'] }}</textarea>
</div>
<button type="submit" class="btn btn-success">💾 حفظ التعديل</button>
<a href="/" class="btn btn-secondary">إلغاء</a>
</form>
</div>
</body>
</html>
🧠 شرح سريع:
- عند الضغط على “تعديل”، يتم عرض القيم القديمة في نموذج جاهز للتحرير.
- بعد حفظ التعديلات، يتم تنفيذ
UPDATE
في قاعدة البيانات. - زر “حذف” ينفذ
DELETE
للملاحظة المحددة بعد التأكيد.
🧪 تجربة العملية:
- شغل التطبيق بالأمر:
python app.py
- أضف ملاحظة جديدة.
- اضغط على "تعديل" وعدّل النص.
- جرّب حذف ملاحظة وتأكد من اختفائها فورًا.
🧭 تمرين الدرس الرابع:
قم بإضافة ميزة جديدة وهي:
عند تعديل الملاحظة، يتم تسجيل تاريخ آخر تعديل في قاعدة البيانات ويُعرض أسفل كل بطاقة ملاحظة في الصفحة الرئيسية.
💡 تلميح: أضف عمودًا جديدًا في الجدول باسم updated_at
وخزّن فيه datetime.now()
أثناء عملية التعديل.
✅ حل تمرين الدرس الرابع: إضافة "تاريخ آخر تعديل" لكل ملاحظة
🧱 الفكرة الأساسية:
سنضيف عمودًا جديدًا في قاعدة البيانات باسم updated_at
،
ونجعله يُحدّث تلقائيًا عند تعديل أي ملاحظة.
🧩 الخطوة 1: تعديل قاعدة البيانات
افتح ملف notes.db في أي أداة إدارة SQLite أو أنشئه من جديد عبر الكود التالي (تشغيله مرة واحدة فقط):
import sqlite3
conn = sqlite3.connect('notes.db')
conn.execute('''
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
updated_at TEXT
)
''')
conn.close()
print("✅ تم تحديث قاعدة البيانات بنجاح.")
🧩 الخطوة 2: تعديل كود Flask في app.py
سنضيف من مكتبة datetime
دالة لتسجيل الوقت الحالي عند كل تعديل،
ثم نحدّث المسار /edit/<id>
ليضيف تاريخ التعديل الجديد.
الكود المحدث الكامل:
from flask import Flask, render_template, request, redirect, url_for
import sqlite3
from datetime import datetime
app = Flask(__name__)
def get_db_connection():
conn = sqlite3.connect('notes.db')
conn.row_factory = sqlite3.Row
return conn
@app.route('/')
def index():
conn = get_db_connection()
notes = conn.execute('SELECT * FROM notes ORDER BY id DESC').fetchall()
conn.close()
return render_template('index.html', notes=notes)
@app.route('/add', methods=['POST'])
def add_note():
title = request.form['title']
content = request.form['content']
updated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
conn = get_db_connection()
conn.execute('INSERT INTO notes (title, content, updated_at) VALUES (?, ?, ?)',
(title, content, updated_at))
conn.commit()
conn.close()
return redirect(url_for('index'))
@app.route('/edit/<int:id>', methods=['GET', 'POST'])
def edit_note(id):
conn = get_db_connection()
note = conn.execute('SELECT * FROM notes WHERE id = ?', (id,)).fetchone()
if request.method == 'POST':
new_title = request.form['title']
new_content = request.form['content']
updated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
conn.execute('UPDATE notes SET title = ?, content = ?, updated_at = ? WHERE id = ?',
(new_title, new_content, updated_at, id))
conn.commit()
conn.close()
return redirect(url_for('index'))
conn.close()
return render_template('edit.html', note=note)
@app.route('/delete/<int:id>')
def delete_note(id):
conn = get_db_connection()
conn.execute('DELETE FROM notes WHERE id = ?', (id,))
conn.commit()
conn.close()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
🧩 الخطوة 3: تعديل واجهة العرض index.html
حتى نُظهر تاريخ آخر تعديل أسفل كل ملاحظة، أضف السطر التالي في بطاقة الملاحظة:
<p class="text-muted mt-2" style="font-size: 0.9em;">
🕒 آخر تعديل: {{ note['updated_at'] }}
</p>
الكود الكامل داخل الحلقة يصبح:
<div class="col-md-4 mb-3">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">{{ note['title'] }}</h5>
<p class="card-text">{{ note['content'] }}</p>
<p class="text-muted mt-2" style="font-size: 0.9em;">
🕒 آخر تعديل: {{ note['updated_at'] }}
</p>
<a href="/edit/{{ note['id'] }}" class="btn btn-warning btn-sm">تعديل ✏️</a>
<a href="/delete/{{ note['id'] }}" class="btn btn-danger btn-sm"
onclick="return confirm('هل أنت متأكد من حذف هذه الملاحظة؟')">حذف 🗑️</a>
</div>
</div>
</div>
🧠 التوضيح:
- كل مرة تضيف أو تعدّل ملاحظة، يتم حفظ الوقت الحالي بتنسيق واضح.
- يظهر هذا التاريخ تحت الملاحظة مباشرة ليعرف المستخدم متى كانت آخر مرة تم فيها تعديلها.
💡 تحسين إضافي (اختياري):
يمكنك تنسيق التاريخ ليظهر بشكل أكثر أناقة بالعربية باستخدام مكتبة Babel
:
pip install babel
ثم استبدل السطر:
from datetime import datetime
from babel.dates import format_datetime
واستخدم:
updated_at = format_datetime(datetime.now(), "EEEE، d MMMM y - h:mm a", locale='ar')
سيظهر مثل:
الجمعة، 11 أكتوبر 2025 - 9:30 مساءً