البرمجة

علاقة One-to-Many في فلاسک

استخدام علاقة One-to-Many مع إطار العمل Flask ومحرك قواعد البيانات SQLite

تُعد إدارة قواعد البيانات والتعامل مع العلاقات بين الجداول من الأمور الأساسية عند تطوير التطبيقات الحديثة، خصوصًا في تطبيقات الويب التي تتطلب تخزين البيانات بطريقة منظمة وفعالة. في هذا السياق، يُعتبر إطار العمل Flask من أشهر أُطُر تطوير تطبيقات الويب بلغة بايثون، وذلك لما يتميز به من بساطة وسهولة في الاستخدام، بالإضافة إلى مرونته الكبيرة التي تسمح للمطورين ببناء تطبيقات متقدمة. ومن ناحية أخرى، يظل محرك قواعد البيانات SQLite خيارًا شائعًا وفعالًا للعديد من التطبيقات الصغيرة والمتوسطة بسبب خفته وعدم حاجته لإعدادات معقدة، بالإضافة إلى تكامله السلس مع بايثون.

في هذا المقال، سنستعرض بشكل مفصل كيفية تصميم علاقة من نوع One-to-Many باستخدام Flask وSQLite، مع التركيز على المفاهيم الأساسية، إعداد البيئة، إنشاء الجداول، بناء العلاقات، بالإضافة إلى تنفيذ عمليات CRUD (الإنشاء، القراءة، التحديث، الحذف) التي تستفيد من العلاقة بين الجداول.


مفهوم علاقة One-to-Many في قواعد البيانات

علاقة One-to-Many هي نوع من العلاقات بين الجداول في قواعد البيانات حيث يُسمح لصف واحد في الجدول الأول بأن يرتبط بعدد من الصفوف في الجدول الثاني، لكن كل صف في الجدول الثاني مرتبط بصف واحد فقط في الجدول الأول.

على سبيل المثال، إذا كان لدينا جدول “المؤلفين” وجدول “الكتب”، فإن كل مؤلف يمكن أن يكون لديه عدة كتب، لكن كل كتاب مرتبط بمؤلف واحد فقط. هذا النوع من العلاقات مهم لتنظيم البيانات بطريقة تُعبر عن الطبيعة الحقيقية للكيانات المرتبطة.


مقدمة عن Flask وSQLite

إطار العمل Flask

Flask هو إطار عمل ويب صغير وخفيف الوزن مكتوب بلغة بايثون، يسمح ببناء تطبيقات ويب بسرعة ومرونة عالية. يعتمد Flask على مكتبة Werkzeug وأداة Jinja2 لتقديم الخدمات الأساسية والتعامل مع القوالب.

يمتاز Flask بكونه غير معقد ويوفر حرية كبيرة للمطور في اختيار الأدوات والمكتبات المناسبة، على عكس أُطُر أكبر مثل Django التي تأتي مع حلول جاهزة ومحددة.

محرك قواعد البيانات SQLite

SQLite هو محرك قواعد بيانات علائقية مدمج ضمن معظم أنظمة التشغيل، يتميز بأنه لا يحتاج إلى سيرفر مستقل لتشغيله، ويخزن البيانات في ملف واحد على القرص الصلب، ما يجعله مناسبًا للتطبيقات التي تحتاج إلى قاعدة بيانات صغيرة وخفيفة.

بايثون تأتي مع مكتبة sqlite3 مدمجة لتسهيل التعامل مع SQLite، وكذلك توفر أُطُر ORM مثل SQLAlchemy دعمًا متقدمًا لهذا المحرك.


إعداد البيئة للبدء في المشروع

للبدء بإنشاء تطبيق Flask يدعم علاقة One-to-Many مع قاعدة بيانات SQLite، يتطلب الأمر تثبيت بعض المكتبات الأساسية:

  • Flask: لبناء التطبيق.

  • Flask-SQLAlchemy: لتسهيل التعامل مع قواعد البيانات وعلاقات الجداول بطريقة ORM.

  • Flask-Migrate (اختياري): لإدارة عمليات الترحيل والتعديل على قاعدة البيانات.

تثبيت المكتبات باستخدام pip

bash
pip install Flask Flask-SQLAlchemy Flask-Migrate

إنشاء هيكل المشروع الأساسي

هيكل مشروع بسيط كالتالي:

bash
/my_flask_app /app.py /models.py /config.py
  • app.py: يحتوي على إعداد التطبيق وتشغيله.

  • models.py: يحتوي على تعريفات الجداول والعلاقات.

  • config.py: يحتوي على إعدادات التطبيق وقاعدة البيانات.


إعداد التطبيق وقاعدة البيانات

في ملف config.py يتم تحديد إعدادات قاعدة البيانات SQLite:

python
import os BASE_DIR = os.path.abspath(os.path.dirname(__file__)) class Config: SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'app.db') SQLALCHEMY_TRACK_MODIFICATIONS = False

في ملف app.py يتم إعداد التطبيق وربطه بقاعدة البيانات:

python
from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import Config app = Flask(__name__) app.config.from_object(Config) db = SQLAlchemy(app)

تعريف الجداول والعلاقة One-to-Many

مفهوم الربط في Flask-SQLAlchemy

في ORM (Object-Relational Mapping)، تُعرف العلاقة بين الكائنات (الجداول) بطريقة برمجية، بدلاً من كتابة استعلامات SQL مباشرة.

لإنشاء علاقة One-to-Many، نستخدم في Flask-SQLAlchemy:

  • db.relationship: لتعريف العلاقة على جانب الـ “One”.

  • db.ForeignKey: لتعريف المفتاح الأجنبي على جانب الـ “Many”.

مثال عملي: المؤلفون والكتب

في ملف models.py:

python
from app import db class Author(db.Model): __tablename__ = 'authors' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) books = db.relationship('Book', backref='author', lazy=True) # books هو قائمة تحتوي على جميع الكتب المرتبطة بهذا المؤلف class Book(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(200), nullable=False) author_id = db.Column(db.Integer, db.ForeignKey('authors.id'), nullable=False) # author_id هو المفتاح الأجنبي الذي يربط الكتاب بالمؤلف

شرح تعريف العلاقة

  • في جدول Author، حقل books هو علاقة مع جدول Book، حيث يشير إلى مجموعة الكتب المرتبطة بالمؤلف.

  • في جدول Book، حقل author_id هو المفتاح الأجنبي الذي يرتبط بـ id في جدول Author.

خاصية backref في علاقة books تعني أن لكل كتاب يمكنك الوصول إلى المؤلف عبر الخاصية author بشكل تلقائي.


إنشاء قاعدة البيانات والجداول

يمكن إنشاء قاعدة البيانات والجداول باستخدام واجهة Flask-SQLAlchemy:

python
from app import app, db from models import Author, Book with app.app_context(): db.create_all()

يقوم هذا الكود بإنشاء جميع الجداول التي تم تعريفها في models.py ضمن قاعدة البيانات app.db.


إدخال بيانات باستخدام علاقة One-to-Many

لإضافة مؤلف مع مجموعة من الكتب مرتبطين به، يمكن تنفيذ التالي:

python
from app import app, db from models import Author, Book with app.app_context(): # إنشاء مؤلف جديد author = Author(name="جبران خليل جبران") # إنشاء كتب مرتبطة بالمؤلف book1 = Book(title="النبي", author=author) book2 = Book(title="دمعة وابتسامة", author=author) # إضافة المؤلف والكتب إلى الجلسة db.session.add(author) db.session.add(book1) db.session.add(book2) # حفظ التغييرات db.session.commit()

في هذا المثال، تم إنشاء كائن المؤلف وربط الكتب به عن طريق تمرير author=author أثناء إنشاء الكتب.


استرجاع البيانات باستخدام العلاقة

يمكن استرجاع المؤلف مع جميع كتبه بسهولة:

python
with app.app_context(): author = Author.query.filter_by(name="جبران خليل جبران").first() print(f"المؤلف: {author.name}") print("الكتب:") for book in author.books: print(f"- {book.title}")

وأيضًا يمكن استرجاع الكتاب ومعرفة مؤلفه:

python
with app.app_context(): book = Book.query.filter_by(title="النبي").first() print(f"الكتاب: {book.title}") print(f"المؤلف: {book.author.name}")

تحديث البيانات عبر العلاقة

لتحديث بيانات كتاب معين، يمكن استخدام العلاقة:

python
with app.app_context(): book = Book.query.filter_by(title="النبي").first() book.title = "النبي - الطبعة الجديدة" db.session.commit()

أو لتغيير المؤلف المرتبط بكتاب:

python
with app.app_context(): new_author = Author(name="أحمد شوقي") db.session.add(new_author) db.session.commit() book = Book.query.filter_by(title="النبي - الطبعة الجديدة").first() book.author = new_author db.session.commit()

حذف البيانات مع مراعاة العلاقة

لحذف كتاب معين:

python
with app.app_context(): book = Book.query.filter_by(title="النبي - الطبعة الجديدة").first() db.session.delete(book) db.session.commit()

لحذف مؤلف مع جميع كتبه المرتبطة، يجب الحذر من حذف البيانات المرتبطة:

تفعيل الحذف المتسلسل (Cascade)

يمكن تفعيل حذف متسلسل عند تعريف العلاقة:

python
class Author(db.Model): __tablename__ = 'authors' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) books = db.relationship('Book', backref='author', lazy=True, cascade="all, delete-orphan")

مع تفعيل cascade="all, delete-orphan"، عند حذف المؤلف سيتم حذف جميع الكتب المرتبطة به تلقائيًا.

مثال حذف:

python
with app.app_context(): author = Author.query.filter_by(name="أحمد شوقي").first() db.session.delete(author) db.session.commit()

تهيئة API بسيط لاستعراض البيانات

لبناء واجهة برمجية تعرض بيانات المؤلفين وكتبهم، يمكن استخدام Flask مع RESTful:

python
from flask import jsonify @app.route('/authors') def get_authors(): authors = Author.query.all() output = [] for author in authors: author_data = { 'id': author.id, 'name': author.name, 'books': [{'id': book.id, 'title': book.title} for book in author.books] } output.append(author_data) return jsonify(output)

يمكن تشغيل التطبيق وزيارة /authors لعرض جميع المؤلفين وكتبهم بصيغة JSON.


مقارنة بين استخدام SQLite و قواعد بيانات أخرى مع Flask

على الرغم من أن SQLite خيار ممتاز للتطبيقات البسيطة والمتوسطة، فإنه لا يدعم بعض الخصائص المتقدمة التي توفرها قواعد بيانات أخرى مثل PostgreSQL أو MySQL، خصوصًا في بيئات الإنتاج التي تتطلب تعدد المستخدمين والعمليات المعقدة.

في حالة تطوير تطبيقات كبيرة أو تحتاج إلى عمليات ترانزكشن متقدمة، من الأفضل النظر إلى قواعد بيانات أكثر قوة مع Flask، مع الحفاظ على نفس مفاهيم العلاقة One-to-Many.


جدول يوضح أهم خواص العلاقة One-to-Many في Flask-SQLAlchemy

الخاصية الوصف مثال
db.relationship تعريف العلاقة على جانب الـ “One”، يسمح بالوصول إلى مجموعة الـ “Many” المرتبطة books = db.relationship('Book', backref='author')
db.ForeignKey تعريف المفتاح الأجنبي في جدول الجانب “Many” author_id = db.Column(db.Integer, db.ForeignKey('authors.id'))
backref يسمح بالوصول العكسي من جدول “Many” إلى جدول “One” book.author للوصول إلى المؤلف
lazy يحدد طريقة تحميل البيانات المرتبطة (مثلاً ‘select’, ‘joined’) lazy=True أو lazy='dynamic'
cascade يحدد قواعد الحذف أو التحديث المتسلسل cascade="all, delete-orphan"

خلاصة

علاقة One-to-Many من العلاقات الأساسية في تصميم قواعد البيانات العلائقية، وتوظيفها بشكل صحيح مع Flask وSQLite يتيح بناء تطبيقات ويب قوية ومرنة قادرة على التعامل مع بيانات مترابطة بفعالية.

باستخدام Flask-SQLAlchemy، يصبح التعامل مع هذه العلاقات بسيطًا ومباشرًا من خلال تعريف العلاقات كعناصر منطقية داخل الكائنات البرمجية، مما يقلل الحاجة لكتابة استعلامات SQL معقدة ويوفر طريقة برمجية عالية المستوى لإدارة البيانات.

SQLite، كمحرك قاعدة بيانات مدمج وخفيف، يُكمل هذه البيئة بتوفير حل تخزين سهل الإعداد ومناسب للتطبيقات التي لا تحتاج لتعامل مع قواعد بيانات معقدة أو متعددة المستخدمين.

هذا الجمع بين Flask وSQLite وSQLAlchemy يشكل بيئة متكاملة لبناء تطبيقات ويب مع دعم متين للعلاقات مثل One-to-Many، مع إمكانية التوسع مستقبلاً إلى قواعد بيانات أكبر أو استخدام ميزات إضافية في ORM.


المصادر والمراجع