🎯 هدف الدرس:
أن نتعلم كيف نضيف نظام تسجيل دخول (Login) للمستخدمين بحيث:
- لا يمكن لأي شخص الوصول للملاحظات إلا بعد تسجيل الدخول.
- كل مستخدم يرى ملاحظاته الخاصة فقط.
- حماية التطبيق من الوصول غير المصرح به.
⚙️ الأدوات المطلوبة:
- Flask
- Flask-Login (مكتبة لإدارة الجلسات والمستخدمين)
- SQLite
تثبيت Flask-Login:
pip install flask-login
🧱 الخطوة 1: تحديث قاعدة البيانات
سنضيف جدولًا جديدًا للمستخدمين باسم users يحتوي على:
- id
- username
- password (سيتم حفظه مشفرًا)
افتح الملف database_setup.py أو أنشئه إذا لم يكن موجودًا، وضع فيه الكود التالي:
import sqlite3
conn = sqlite3.connect('notes.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
)
''')
conn.commit()
conn.close()
print("✅ تم إنشاء جدول المستخدمين بنجاح!")
ثم شغّل الملف مرة واحدة لإنشاء الجدول.
🧩 الخطوة 2: تحديث ملف app.py
أضف في الأعلى الاستيرادات الجديدة:
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
ثم أضف إعداد Flask-Login:
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
🧱 الخطوة 3: إنشاء كائن المستخدم User
class User(UserMixin):
def __init__(self, id, username, password):
self.id = id
self.username = username
self.password = password
ثم حمّل المستخدم من قاعدة البيانات عند تسجيل الدخول:
@login_manager.user_loader
def load_user(user_id):
conn = sqlite3.connect('notes.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM users WHERE id=?', (user_id,))
user = cursor.fetchone()
conn.close()
if user:
return User(id=user[0], username=user[1], password=user[2])
return None
🧱 الخطوة 4: إنشاء صفحات التسجيل وتسجيل الدخول
صفحة التسجيل (/register)
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = generate_password_hash(request.form['password'])
conn = sqlite3.connect('notes.db')
cursor = conn.cursor()
try:
cursor.execute('INSERT INTO users (username, password) VALUES (?, ?)', (username, password))
conn.commit()
flash('تم التسجيل بنجاح! يمكنك الآن تسجيل الدخول.')
return redirect('/login')
except:
flash('اسم المستخدم موجود بالفعل!')
finally:
conn.close()
return render_template('register.html')
صفحة تسجيل الدخول (/login)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
conn = sqlite3.connect('notes.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM users WHERE username=?', (username,))
user = cursor.fetchone()
conn.close()
if user and check_password_hash(user[2], password):
login_user(User(id=user[0], username=user[1], password=user[2]))
flash('تم تسجيل الدخول بنجاح!')
return redirect('/')
else:
flash('بيانات الدخول غير صحيحة!')
return render_template('login.html')
🧱 الخطوة 5: حماية صفحات التطبيق
أضف @login_required فوق الصفحات التي تريد حمايتها مثل الصفحة الرئيسية:
@app.route('/')
@login_required
def index():
...
وأضف زر لتسجيل الخروج:
@app.route('/logout')
@login_required
def logout():
logout_user()
flash('تم تسجيل الخروج بنجاح.')
return redirect('/login')
🧱 الخطوة 6: إنشاء القوالب HTML
ملف templates/login.html
{% extends 'base.html' %}
{% block content %}
<h2>تسجيل الدخول</h2>
<form method="POST">
<input type="text" name="username" placeholder="اسم المستخدم" class="form-control mb-2" required>
<input type="password" name="password" placeholder="كلمة المرور" class="form-control mb-2" required>
<button type="submit" class="btn btn-primary w-100">دخول</button>
</form>
<p class="mt-3">ليس لديك حساب؟ <a href="/register">سجّل الآن</a></p>
{% endblock %}
ملف templates/register.html
{% extends 'base.html' %}
{% block content %}
<h2>تسجيل حساب جديد</h2>
<form method="POST">
<input type="text" name="username" placeholder="اسم المستخدم" class="form-control mb-2" required>
<input type="password" name="password" placeholder="كلمة المرور" class="form-control mb-2" required>
<button type="submit" class="btn btn-success w-100">تسجيل</button>
</form>
<p class="mt-3">هل لديك حساب؟ <a href="/login">تسجيل الدخول</a></p>
{% endblock %}
💡 النتيجة النهائية:
- المستخدم يمكنه التسجيل بحساب جديد.
- بعد تسجيل الدخول، يظهر له فقط ملاحظاته الخاصة.
- المستخدمون الآخرون لا يمكنهم الوصول لملاحظات غيرهم.
- الجلسة تستمر حتى يقوم المستخدم بتسجيل الخروج.
🧠 التمرين العملي:
أضف ميزة جديدة:
عند إنشاء ملاحظة جديدة، خزّن أيضًا اسم المستخدم في الجدول، بحيث لا يرى كل مستخدم إلا ملاحظاته الخاصة.
🎯 هدف التمرين
إنشاء نظام تسجيل الدخول (Login) وتسجيل الخروج (Logout)، وربط كل مستخدم بملاحظاته الخاصة فقط.
🧱 الهيكل العام للمشروع بعد التعديل
flask_notes_app/
│
├── app.py
├── templates/
│ ├── index.html
│ ├── add_note.html
│ ├── edit_note.html
│ ├── login.html
│ ├── register.html
│
└── notes.db
🪄 الخطوة 1: تعديل قاعدة البيانات لإضافة المستخدمين
افتح ملف app.py وأضف جداول المستخدمين:
from flask import Flask, render_template, request, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.secret_key = 'super_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///notes.db'
db = SQLAlchemy(app)
# نموذج المستخدم
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
notes = db.relationship('Note', backref='owner', lazy=True)
# نموذج الملاحظة
class Note(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(150), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
with app.app_context():
db.create_all()
🧾 الخطوة 2: إنشاء صفحة التسجيل
📄 templates/register.html
<!DOCTYPE html>
<html lang="ar">
<head>
<meta charset="UTF-8">
<title>تسجيل مستخدم جديد</title>
<style>
body { font-family: "Cairo"; text-align:center; background:#fafafa; }
form { background:#fff; padding:20px; border-radius:10px; display:inline-block; box-shadow:0 0 10px #ccc; }
input { padding:10px; margin:5px; width:200px; border-radius:5px; border:1px solid #ddd; }
button { padding:10px 20px; background:#007bff; color:#fff; border:none; border-radius:5px; cursor:pointer; }
</style>
</head>
<body>
<h2>تسجيل مستخدم جديد</h2>
<form method="POST">
<input type="text" name="username" placeholder="اسم المستخدم" required><br>
<input type="password" name="password" placeholder="كلمة المرور" required><br>
<button type="submit">تسجيل</button>
</form>
<p>هل لديك حساب؟ <a href="{{ url_for('login') }}">تسجيل الدخول</a></p>
</body>
</html>
📜 الكود في app.py:
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
existing_user = User.query.filter_by(username=username).first()
if existing_user:
flash('اسم المستخدم موجود بالفعل!')
return redirect(url_for('register'))
hashed_pw = generate_password_hash(password)
new_user = User(username=username, password=hashed_pw)
db.session.add(new_user)
db.session.commit()
flash('تم التسجيل بنجاح! يمكنك الآن تسجيل الدخول.')
return redirect(url_for('login'))
return render_template('register.html')
🔑 الخطوة 3: صفحة تسجيل الدخول
📄 templates/login.html
<!DOCTYPE html>
<html lang="ar">
<head>
<meta charset="UTF-8">
<title>تسجيل الدخول</title>
<style>
body { font-family: "Cairo"; text-align:center; background:#f8f9fa; }
form { background:#fff; padding:20px; border-radius:10px; display:inline-block; box-shadow:0 0 10px #ccc; }
input { padding:10px; margin:5px; width:200px; border-radius:5px; border:1px solid #ddd; }
button { padding:10px 20px; background:#28a745; color:#fff; border:none; border-radius:5px; cursor:pointer; }
</style>
</head>
<body>
<h2>تسجيل الدخول</h2>
<form method="POST">
<input type="text" name="username" placeholder="اسم المستخدم" required><br>
<input type="password" name="password" placeholder="كلمة المرور" required><br>
<button type="submit">دخول</button>
</form>
<p>مستخدم جديد؟ <a href="{{ url_for('register') }}">إنشاء حساب</a></p>
</body>
</html>
📜 الكود في app.py:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password, password):
session['user_id'] = user.id
flash('تم تسجيل الدخول بنجاح!')
return redirect(url_for('index'))
else:
flash('اسم المستخدم أو كلمة المرور غير صحيحة!')
return render_template('login.html')
🚪 الخطوة 4: تسجيل الخروج
@app.route('/logout')
def logout():
session.pop('user_id', None)
flash('تم تسجيل الخروج بنجاح!')
return redirect(url_for('login'))
🧠 الخطوة 5: حماية الصفحات الخاصة بالملاحظات
أضف هذا التحقق في صفحة الملاحظات:
@app.route('/')
def index():
if 'user_id' not in session:
flash('يرجى تسجيل الدخول للوصول إلى ملاحظاتك.')
return redirect(url_for('login'))
user_id = session['user_id']
notes = Note.query.filter_by(user_id=user_id).all()
return render_template('index.html', notes=notes)
وعند إضافة ملاحظة جديدة:
@app.route('/add', methods=['GET', 'POST'])
def add_note():
if 'user_id' not in session:
return redirect(url_for('login'))
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
new_note = Note(title=title, content=content, user_id=session['user_id'])
db.session.add(new_note)
db.session.commit()
flash('تمت إضافة الملاحظة بنجاح!')
return redirect(url_for('index'))
return render_template('add_note.html')
✅ النتيجة النهائية
الآن كل مستخدم يمكنه:
- التسجيل وتسجيل الدخول.
- رؤية ملاحظاته فقط.
- الخروج بأمان.

