مُقدّمة:
بعد أن عرّفنا كلّا من جدول المقالات وجدول المُستخدمين، بقيت لنا خطوة الرّبط بينهما ليُشير كلّ مقال إلى كاتبه ونستطيع الوصول إلى مقالات كلّ مُستخدم، وسنقوم بهذا الأمر باستغلال خصائص قواعد بيانات SQL العلائقيّة لإنشاء علاقة واحد للعديد، بحيث يُمكن لكلّ مُستخدم أن يمتلك العديد من المقالات ويكون لكلّ مقال كاتب واحد فقط.
المُشكلة
عند تصفّحك لتطبيقات الوب في وقتنا الحالي، ستُلاحظ بأنّ المُستخدمين يمتلكون بياناتهم الخاصّة، مثلا يُمكن للمُستخدم الواحد أن يمتلك عدّة مقالات وتدرج تحت اسمه، ويُمكن أن يمتلك كذلك عدّة تعليقات باسمه، إذن كيف يُمكن أن نُدرج مقالات من جدول المقالات الخاصّ بنا إلى المُستخدم الذي يقوم بإضافتها؟ بمعنى آخر، كيف يُمكن للمُستخدم الواحد أن يمتلك عدّة مقالات مُندرجة باسمه؟
الحل الخاطئ
الطّريقة التّي يُمكن أن تُفكّر فيها هي بإدراج رقم مُعرّف كل مقال يُضيفه المُستخدم إلى عمود خاص به مع الفصل بينها بمسافة أو شيء من هذا القبيل، بعدها تحصل عليها وتقوم باستخراج مقالات كل مُستخدم.
الجدول سيكون كما يلي:
id | name | posts
1 | Ali | 1, 3, 5 ...
أهملت هنا عمودي البريد الإلكتروني وكلمة المرور لأنّها غير مُهمّة في مثالنا.
الآن إن نظرت إلى العمود posts
فستجد بأنّ المقالات ذات المُعرّفات 1 و 3 و 5 قد أضافها المُستخدم Ali
.
هذه الطّريقة فكرة سيّئة جدّا، فلو أردنا حذف مقال فحذف علاقته بالمُستخدم أمر مُعقّد، وهناك العديد من المشاكل مع استخدام هذه الطّريقة، وقد أشرت إليها لأنّها شائعة جدّا ويجب أن تحذفها من ذهنك قبل أن تحدث أمور أسوأ، فإن أردت أن تكون مُطوّر وب جيّدا فعليك تعلّم الطّرق الصّحيحة وعليك كذلك الإلمام بالطّرق الخاطئة في التّطوير.
الطّريقة الصّحيحة لربط سجلّ واحد بالعديد من السّجلّات في جدولين مُختلفين
علاقة الواحد-للعديد أو One-to-Many Relationship هي طريقة لربط جدولين أو أكثر بحيث يمتلك كلّ فرد في جدول العديد من السّجلّات في جدول آخر. في مثالنا، سيمتلك المُستخدم الواحد عدّة مقالات باسمه. للقيام بهذا الأمر، نقوم بوضع عمود آخر في الجدول الذي سيمتلك العديد من السّجلّات الخاصّة بفرد واحد من جدول آخر ليحمل قيمة رقم مُعرّف هذا الفرد، أي أننا سنُضيف عمودا آخر في جدول المقالات ليحمل رقم مُعرّف المُستخدم الذي أضاف المقال ليكون جدول المقالات كما يلي:
| id | title | user_id | 1 | Post 1 | 1 | 2 | Post 2 | 2 | 3 | Post 3 | 1 | 4 | Post 4 | 3
لنفترض بأنّ لدينا ثلاثة مُستخدمين في جدول المُستخدمين كما يلي:
| id | name
| 1 | Ali
| 2 | Abdelhadi
| 3 | Hassan
مُجدّدا، قمت بإهمال الأعمدة الأخرى لأنّها لا تهمّنا في هذا المثال، وكما تُلاحظ لكل مقال قيمة في عمود user_id
لتُشير إلى المُستخدم الذي أنشأ هذا المقال، وعند النّظر إلى جدولي المقالات والمُستخدمين والسّجلّات المتواجدة فيها حاليّا، يتبيّن لنا بأنّ المستخدم Ali
قد أضاف مقالين، المقال ذو رقم المُعرّف 1 و المقال ذو رقم المُعرّف 3، أمّا Abdelhadi
فهو صاحب المقال ذي المُعرّف 2 أمّا المقال الأخير فمن الواضح بأنّ المُستخدم Hassan
هو من أضافه.
هذه هي علاقة الواحد للعديد ببساطة، عندما يمتلك سجلّ واحد من جدول العديد من السّجلّات في جدول آخر، فإنّنا نُضيف عمودا إلى الجدول الذي يحمل العديد من السّجلات ليحمل كل سجلّ منه قيمة المفتاح الأولي Primary Key للسّجل الواحد في الجدول الآخر والذي يُسمّى فيه مفتاحا أجنبيا Foreign Key، أي أنّ العمود user_id
عبارة عن مفتاح أجنبي لأنّه يحمل قيمة المفتاح الأولي الخاصّ بالمُستخدم، وعندما نقوم بتحديد عمود على أنّه مفتاح أجنبي، فالعلاقة بين الجدولين تكون مفهومة بالنّسبة لقاعدة البيانات لدينا، كما يُساعدنا ذلك على تخطّي بعض المشاكل في حالة ما أضيفت قيمة خاطئة إلى العمود عوضا عن قيمة صحيحة.
في SQLAlchemy يُمكننا إنشاء علاقة واحد للعديد بسهولة وبساطة بإضافة سطرين فقط إلى الشفرة التّي حدّدناها سابقا، سطر في صنف (جدول) المقالات لإضافة عمود باسم author_id
والذي سيكون عبارة عن مفتاح أجنبي يُشير إلى قيمة المفتاح الأولي للمُستخدم، وسطر في صنف المُستخدم لنتمكّن من الوصول إلى مقالات كل مُستخدم ببساطة.
أضف هذا السّطر في آخر الصّنف Post
:
# project/models.py
author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
لتعريف مفتاح أجنبي، نستعمل الدّالة db.ForeignKey
مع تمرير اسم الجدول واسم المفتاح الأولي مفصولين بنُقطة (في هذا المثال users.id
) ونقوم كذلك بإضافة المُعامل nullable
وإسناد القيمة المنطقيّة False
له للتأكّد من أنّ الحقل الذي يربط بين المُستخدم والمقال الذي أضافه لا يحمل قيمة فارغة.
بعد إضافة المفتاح الأجنبي، حان الوقت لإخبار SQLAlchemy بأنّنا نريد الحصول على مقالات كلّ مُستخدم، والمُستخدم الذي أضاف كلّ مقال انطلاقا من العلاقة بين الجدولين، لذا أضف السّطر التّالي في آخر الصّنف User
:
# project/models.py
posts = db.relationship("Post", backref="author", lazy="dynamic")
في هذا السّطر، نقوم بتعريف العلاقة بين المُستخدم والمقال عن طريق الدّالّة db.relationship
مع تمرير ثلاثة مُعاملات، الأول عبارة عن اسم الصّنف الذي يشير لجدول المقالات، والمُعامل backref
يُمكّننا من الوصول إلى المُستخدم الذي كتب المقال عن طريق الاسم author
أمّا المعامل الأخير فهو لتحديد نوعيّة النّتيجة التّي سنحصل عليها عند طلب جميع المقالات التّي كتبها أحد المُستخدمين، وقد وضعنا القيمة dynamic
لتكون النّتيجة عبارة عن استعلام ديناميكي لجميع المقالات التّي كتبها المُستخدم، وهكذا سنحصل على مرونة أكثر عند طلب المقالات وسنتمكّن من التّعامل معها على أنّها كائنات يُمكننا استغلالها بجميع ما توفّره مكتبة SQLAlchemy من طرق ودوال مُساعدة، وسنرى تطبيقا لهذا الكلام فيما بعد.
سنُضيف كذلك عمود author_id
إلى التّابع __init__
الخاصّة بالصّنف Post
وبالتّالي سيُصبح التّابع كما يلي:
def __init__(self, title, content, author_id, created_date = None):
self.title = title
self.content = content
self.author_id = author_id
self.created_date = datetime.utcnow()
بعد تحديد العلاقة بين الجدولين، سنستطيع إضافة مقال وإسناد رقم مُعرّف المُستخدم أو المُستخدم ككاتب للمقال الذي أضافه لنتمكّن فيما بعد من الحصول على كاتب كل مقال بجميع معلوماته (بريده الإلكتروني، اسمه …)، وكذا المقالات التّي كتبها كلّ مُستخدم مع مرونة في التّعامل معها عبر ما تُوفّره لنا مكتبة SQLAlchemy من مُساعدة.
خاتمة
بعد أن تعرّفنا على طريقة ربط المُستخدم ومقالاته والمقالات وكاتبها، أصبحنا نستطيع تطبيق التّغييرات إلى قاعدة بياناتنا والتّعامل مع السّجلّات بعمليّات قواعد البيانات المعروفة اختصارا بـCRUD أو Create, Read, Update, Delete، أي الإضافة/الإنشاء، القراءة/العرض، التّعديل والحذف.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.