اذهب إلى المحتوى

مُقدّمة:

بعد أن عرّفنا كلّا من جدول المقالات وجدول المُستخدمين، بقيت لنا خطوة الرّبط بينهما ليُشير كلّ مقال إلى كاتبه ونستطيع الوصول إلى مقالات كلّ مُستخدم، وسنقوم بهذا الأمر باستغلال خصائص قواعد بيانات 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، أي الإضافة/الإنشاء، القراءة/العرض، التّعديل والحذف.
 


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...