البحث في الموقع
المحتوى عن 'orm'.
-
مقدّمة بعد أن تعرّفنا على كيفيّة تجهيز جدولي المقالات والمُستخدمين اللّذين سيُشكّلان أساس بيانات تطبيقنا، وبعد أن تعرّفنا في الدّرس السّابق على كيفيّة الرّبط بين الجدولين ليكون لكلّ كاتب مقالاته ولكل مقال كاتب خاص به، حان الوقت لإنشاء الجدولين في قاعدة البيانات والتّعرّف على كيفيّة استغلال كلّ من مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy للتّعامل مع البيانات. لماذا الدّروس القادمة أساسيّة؟ هذا الدّرس والدّروس القادمة مُهمّة لك إن كنت ترغب بالاعتماد على قواعد بيانات SQL ومكتبة SQLAlchemy في تطوير تطبيقاتك، وما ستتعلّمه من هذه الدروس سيُفيدك في حالات كثيرة، وستتمكّن من القيام بأكثر العمليّات شيوعا باستخدام SQLAlchemy عوضا عن لغة SQL ما سيبقي شفرتك نظيفة وسيُمكّنك من العمل مع بياناتك بأريحيّة أكثر. ورغم أنّنا لن نستعمل الكثير من الأشياء التّي سأذكرها في تطبيق “كلمة”، إلّا أنّ الإلمام بها مهم جدّا، وعندما أقول بأنّ هذه المفاهيم مهمّة فأنا لا أعني أن تحفظها عن ظهر قلب، إذ يُمكنك أن تعود إلى درس مُعيّن في كلّ مرّة تُريد أن تتذكّر كيفيّة القيام بعمليّة معيّنة باستخدام مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy، وأشجّعك على توظيف كل ما ستتعلّمه لإضافة ميّزات جديدة إلى التّطبيق الذي سنبنيه سويّا (مثلا إضافة جزء لعرض مقال عشوائي في كلّ مرّة يُعاد فيها تحميل الصّفحة)، وإن أردت أن تعرف كيفيّة القيام بعمليّة أخرى من عمليّات SQL التّقليديّة باستخدام SQLAlchemy فعد أولا إلى التّوثيق الرّسمي للمكتبة أو ضع سؤالا مصاغا بوضوح ولغة سليمة في قسم الأسئلة والأجوبة للحصول على إجابة كافيّة. إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات بعد أن أنشأنا الصّنفين المسؤولين عن إنشاء الجدولين في ملفّ models.py الذي يقع تحت مُجلّد project أصبح بإمكاننا إنشاء الجدولين عن طريق مكتبة SQLAlchemy اعتمادا على محتويات ملفّ models.py والكائن db الذي سبق لنا وأنشأناها بمُساعدة إضافة Flask-SQLAlchemy. بعد إنشاء الجدولين، ستُطبّق التّغييرات مُباشرة إلى خادوم PostgreSQL الذي نُصّب بجهازك المحلي، ما يعني بأنّك ستتمكّن من التّعامل مع قاعدة البيانات باستخدام لغة SQL والميّزات التي تُوفّرها قاعدة البيانات PostgreSQL. لإنشاء الجدولين في قاعدة بياناتنا، سنقوم أولا بإنشاء ملف باسم create_db.py في المجلّد الرّئيسي kalima وسنضع به ثلاثة أسطر فقط: # create_db.py from project import db from project.models import Post, User db.create_all() تأكّد فقط من أنّ إعداد SQLALCHEMY_DATABASE_URI يُشير إلى قاعدة بيانات PostgreSQL التّي أنشأناها سابقا باسم kalima وأنّ اسم المُستخدم وكلمة المرور صحيحان في ذات الإعداد، وللمزيد أعد إلقاء نظرة على درس تجهيز قاعدة البيانات PostgreSQL ودرس إنشاء جداول البيانات. كما تُلاحظ، الشّفرة بسيطة، أولا نستدعي الكائن db من حزمة المشروع، ثمّ نستدعي كلّا من الصّنف Post وUser لإعلام SQLAlchemy بأنّنا قد حدّدنا هذه الجداول والأعمدة الأساسيّة فيها، وبعد ذلك نقوم بإنشاء الجداول في قاعدة البيانات باستعمال الدّالة db.create_all. وبنفس الطّريقة لو أردت حذف الجداول يُمكنك استدعاء الدّالة db.drop_all عوضا عن db.create_all. وإن أمكنك الوصول إلى سطر أوامر PostgreSQL عن طريق أداة psql فيُمكنك الاتّصال بقاعدة البيانات kalima وعرض الجداول فيه، بالأمرين التّاليين: postgres=# \c kalima You are now connected to database "kalima" as user "postgres". kalima=# \d No relations found. الأمر الأول للاتّصال بقاعدة البيانات الخاصّة بتطبيقنا، وذلك لأنّ الخادوم يحتوي على أكثر من قاعدة بيانات واحدة، أمّا الأمر الثّاني فهو لعرض الجداول المُتواجدة بقاعدة البيانات، وبما أنّنا لم ننفّذ ملفّ create_db.py بعد فالنّتيجة هي بطبيعة الحال أنّنا لا نمتلك أية جداول أو علاقات كما تُلاحظ من الرّسالة No relations found. الآن، نفّذ الملفّ عبر الأمر: python create_db.py إن لم تلاحظ أية رسالة، فهذا يعني بأنّ كل شيء بخير، ولو عدت إلى سطر أوامر psql وأعدت تنفيذ الأمر \d للاحظت ما يلي: List of relations Schema | Name | Type | Owner --------+--------------+----------+---------- public | posts | table | postgres public | posts_id_seq | sequence | postgres public | users | table | postgres public | users_id_seq | sequence | postgres ربّما تختلف قيمة العمود Owner لديك لأنّها تُشير إلى اسم المُستخدم الذي أنشأ الجداول أو مالكها، وهذا الاسم هو نفسه الذي تُحدّده في إعداد قاعدة البيانات الذي سبق وأن أشرنا إليه، لاحظ معي فقط كلّا من الجدول posts و الجدول users: public | posts | table | postgres public | users | table | postgres بما أنّ نوع العلاقة هو table (جدول)، فهذا يعني بأنّنا استطعنا إنشاء الجدولين بنجاح، ونستطيع الآن التّعامل معه بلغة SQL مباشرة من أداة psql. في ما يلي استعلامان يُمكنك تنفيذهما للحصول على جميع السّجلات في كلّ جدول: select * from posts; select * from users; بالطّبع، لأنّنا لم نُضف أية سجلّات بعد، فالمُخرج سيكون كما يلي في كلتا الحالتين: Posts Table: id | title | content | created_date | author_id ----+-------+---------+--------------+----------- (0 rows) Users Table: id | name | email | password | created_date ----+------+-------+----------+-------------- (0 rows) وكما تُلاحظ، جميع الأعمدة التّي سبق وأن حدّدناها في ملفّ models.py باستعمال db.Column متواجدة في هذين الجدولين. يُمكنك بالطّبع إضافة بعض السّجلّات بلغة SQL إن أردت ذلك بالاعتماد على جملة INSERT INTO وكذا التّعامل مع البيانات بمُختلف الطّرق التّي تُتيحها PostgreSQL، ولكنّنا لن نستعمل لغة SQL لأنّنا نمتلك أداة SQLAlchemy وإضافة فلاسك الخاصّة به. ختاما تعرّفنا في هذا الدّرس على كيفيّة إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات مُباشرة باستعمال الدّالة db.create_all() التّي توفّرها لنا إضافة Flask-SQLAlchemy. في الدّرس القادم، سنتعرّف على كيفيّة استعمال مُفسّر لغة بايثون للتعامل مع قاعدة البيانات بمُساعدة من مكتبة SQLAlchemy، وبذلك سنتمكّن من التواصل مع قاعدة البيانات وإدارة سجلات الجداول فيها.
-
- jinja2
- sqlalchemy
-
(و 1 أكثر)
موسوم في:
-
سنتابع في هذا الدرس من سلسلة تعليم إطار العمل Ruby on Rails حيث سنتعرف على Active Record. 1 ما هو Active Record؟ Active Record هو جزء من النمط البرمجي MVC -شرحها بأسفل المقال- و هو المسئول عن جزء البيانات. حيث إن Active Record هو الجزء المسؤول عن عرض البيانات و خوارزميتها. فيسهل Active Record صنع و إستخدام عناصر البيانات التي تتطلب مساحة دائمة في قاعدة البيانات database. إن تطبيق نمط Active Record يُعتبر نفسه وصف و جزء من الـ ORM – يوجد تعريف بالأسفل- . ** MVC- Model View Controller - هو نمط تم اعتماده كطريقة للبرمجة حيث يعتمد هذا النمط في الاساس على عزل ما هو مرأي للمستعمل (user interface) عن ما يتعلق بالبيانات(data) و طرق استخدامها، حيث ينفصل الجزء المختص بالبيانات عن الواجهة و يمكن عمل أكتر من مطور على المشروع بسلاسة و دون تعارض. من مثال المنصات التي تعمل بتلك الطريقة هي Laravel ** ORM Object- Relational- Object هو تكنيك برمجي مستخدم لتحويل البيانات بين الأنظمة غير المتوافقة عن طريق تحويل الصفوف و الأعمدة إلى كائنات بإستخدام البرمجة الشيئية. 1.1 نمط Active Record لقد عرف مارتن فويلر Active Record في كتابه Patterns of Enterprise Application Architecture وفي هذا التعريف أوضح ماهيته. في Active Record، يحمل الكائن object كلاً من البيانات الدائمة و العمليات التي ستتم عليها. Active Recordيعمل على ربط منطق الولوج إلى البيانات بالكائن بحيث يُعلم المُستخدمين كيفية إدخال و إخراج البيانات من قاعدة البيانات. 1.2 رسم العلاقات بين الكائنات Object Relational Mapping يُرمز إلى هذا المصطلح بالإختصار ORM ، وهو تقنية تربط بين الكائنات المُختصة بتطبيقٍ ما مع جداول في نظام إدارة قواعد البيانات المتصلة. بإستعمال ORM يمكن تخزين و إستخدام خصائص و علاقات الكائنات في التطبيق بدون الحاجة إلى كتابة أوامر SQL بل بطريقة مُباشرة و بإستخدام أكواد أقل. 1.3 Active Record كمنصة ORM Active Record يوفر لنا العديد من الإمكانيات، أهمها: تمثيل النماذج models و بياناتها تمثيل الروابط بين تلك النماذج تمثيل البيانات الموروثة بين نماذج البيانات المُتصلة توثيق النماذج قبل تثبيتها بقواعد البيانات تطبيق عمليات قواعد البيانات بإستخدام إسلوب البرمجة الشيئية 2 سهولة إستيراد الأكواد من اللغات الأخرى عند كتابة أحد التطبيقات بلغةٍ ما أو منصةٍ أخرى لإستعمالها في منصة ORM فإن هذه الأكواد تحتاج إلى الكثير من التهيئة configuration . و لكن هذا الأمر قد تم حله في Rails حيث ستحتاج إلى كتابة أكواد قليلة جداً لعمل التهيئة (وفي بعض الأحيان لن تحتاج إلى التهئية على الإطلاق) عند صنع نماذج Active Record. طريقة عمل هذه التهيئة تعتمد على الإستناد إلى تهيئة التطبيقات بالطريقة نفسها في معظم الأوقات بطريقة رئيسية. ومع ذلك، في بعض الأحيان ستحتاج إلى كتابة أكواد التهيئة عندما لا تتناسب التطبيقات التي تستوردها مع الطريقة الرئيسية للتهيئة في Rails. 2.1 طريقة التسمية Naming إن Active Record يستعمل قواعد تسمية تُساعد على صُنع الروابط بين النماذج و جداول قواعد البيانات. Rails ستقوم بتحويل أسماء الأصناف classes إلى صيغة الجمع لتناسب جدول قاعدة البيانات المناسب لها. على سبيل المثال، إذا كان لديك فئة تُسمى book فستحصل على جدول قاعدة بيانات يُسمى books. و إن Rails تستعمل آلية قوية لذلك تُمكنها من جمع الأسماء المنتظمة و الشاذة. و عند إستعمال فئة إسمها مكون من كلمتين، فإن قواعد التسمية تميل إلى طريقة CamelCase حيث سيحتوي جدول قاعدة البيانات على الكلمتين ذاتهم مفصولتين بإستخدام “_”. على سبيل المثال، فئة تُسمي BookClub فإن جدول قاعدة البيانات الخاص بها سيسمى book_clubs، و يجب أن نلاحظ أن الإسم المفرد تبدأ كلماته بحروف استهلالية Capital. Model / Class Table / Schema Article articles LineItem line_items Deer deers Mouse Mice Person people 2.2 طريقة تنظيم قاعدة البيانات و تخطيطها إن Active Record يستعمل طريقة التسمية التي تحدثنا عنها لتسمية العواميد columns في جداول قواعد البيانات، إعتمادًا على غرض هذه العواميد. المفاتيح الأجنبية Foreign Keys هي مفاتيح أساسية في جداول أخرى و يتم إستخدامها للربط بين قواعد البيانات ببعضها البعض. طريقة تسميتها تتبع النمط الآتي singularized_table_name_id مثال على ذلك item_id, order_id المفاتيح الأساسية Primary Keys: إن Active Record يقوم بعمل عامود مكون من أرقام integers يُسمى id و مهمته هو تمييز الجدول و عناصره، فعند إستخدام خاصية التهجير Active Record Migration لعمل جداول جديدة، سيتم عمل عامود المفاتيح الأساسية تلقائيًا. هُناك أيضًا بعض العواميد الإختيارية التي تُضيف مميزات جديدة لـ Active Record: مفتاح created_at يقوم بتخزين وقت صُنع السجل مع مراعاة الوقت الحالي. مفتاح updated_at يقوم بتخزين وقت تحديث السجل مع مراعاة الوقت الحالى. مفتاح lock_version يضيف خاصية الإغلاق المتفائل لقاعدة البيانات مفتاح type يُحدد إذا ما كانت خاصية Single Table Inheritance أم لا مفتاح (association_name)_type يستخدم لتخزين النوع الخاص بـ polymorphic associations. مفتاح (table_name)_count يُستخدم لتخزين عدد الكائنات أو الأشياء objects الموجودة داخل علاقة ما، و على سبيل المثال: إذا كان لديك class تُسمى Article تحتوي على عامود يُسمى comments_count. سيقوم هذا المُفتاح بتخزين أعداد الـ comments الموجودة بكل Article. 3 صُنع نماذج Active Record إن صُنع نماذج Active Record لهو أمرٌ في غاية السهولة. كُل ما عليك فعله هو عمل صنف class فرعية من سجل التطبيق ApplicationRecord. class Product < ApplicationRecord end هذا سوف يصنع نموذج model يُسمى Product مُتصل بجدول يُسمى products بقاعدة البيانات فبواسطة ذلك سيُمكنك ربط الأعمدة الموجودة بكل صف في ذلك الجدول مع الخصائص الخاصة بنموذجك. فإعتبر أنك قُمت بإنشاء الجدول بإستخدام سطور SQL الآتية: CREATE TABLE products ( id int(11) NOT NULL auto_increment, name varchar(255), PRIMARY KEY (id) ); بإستعمال طريقة تخطيط البيانات السابق ذكرها، يمكنك كتابة كود مثل الآتي: p = Product.new p.name = "Some Book" puts p.name # "Some Book" وسنتابع في الدرس التالي التسمية،قراءة وكتابة البيانات، التوثيق، الاستدعاء والتهجير… من توثيقيات Ruby on Rails
-
- orm
- active record
-
(و 3 أكثر)
موسوم في:
-
مُقدّمة بعد إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات في الدّرس السّابق، حان الوقت للتّعامل مع البيانات وإدارتها باستعمال لغة بايثون عوضا عن لغة SQL؛ في هذا الدّرس سنتعرّف على كيفيّة الوصول إلى مُفسّر بايثون في مجلّد مشروعنا وكذلك كيفيّة إضافة البيانات وجلبها من قاعدة البيانات. الوصول إلى مُفسّر بايثون داخل مُجلّد المشروع سنقوم في هذا الدّرس بالتّعامل مع قاعدة البيانات باستعمال Flask-SQLAlchemy مُباشرة من مُفسّر بايثون، إن كنت على نظام Windows فهو في الغالب متواجد في قائمة ابدأ، أمّا إن كنت على لينكس أو OSX فادخل إلى الطّرفيّة Terminal واكتب python تأكّد فقط من أنّك في مُجلّد kalima قبل أن تقوم بالوصول إلى مُفسّر بايثون، وتأكّد كذلك بأنّك قد فعّلت البيئة الوهميّة. إن لم تستطع الوصول إلى مُفسّر بايثون في مُجلّد kalima فيُمكنك تنفيذ الأمر chdir من وحدة os لتغيير المُجلّد الحالي إلى مسار مُجلّد kalima: >>> import os >>> os.chdir('path/to/kalima') مع تغيير path/to/kalima إلى مسار مُجلّد kalima في حاسوبك. مُلاحظة: الشّيفرة التّي سأقوم بتنفيذها ستُسبق بعلامة >>> أمّا المُخرج/النّتيجة فلن يُسبق بشيء. مثال: >>> site = 'Hsoub Academy' >>> site 'Hsoub Academy' بما أنّنا في مُفسّر بايثون نستطيع الوصول إلى قيمة المُتغيّر دون طباعتها، فقط اكتب اسم المُتغيّر ثم اضغط مفتاح ENTER. سنستعمل كلّا من db والصّنفين اللذ]ن يُشكلان كلّا من جدول المقالات والمُستخدمين للتّعامل مع البيانات فيها، وللوصول إلى كلّ من الكائن db والصّنفين Post و User يجب عليك أن تقوم باستيرادها: >>> from project import db >>> from project.models import Post, User إن حصلت على خطأ كما يلي: Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named project فهذا يعني بأنّك لست في مجلّد kalima لذا تأكّد من أنّك اتّبعت الإرشادات السّابقة على نحو صحيح. إدخال البيانات إلى قاعدة البيانات الآن، بعد استيراد كلّ من الكائن db والصّنفين Post وUser نستطيع القيام بأول عمليّة، ألا وهي عمليّة الإضافة، وسنُضيف أولا مُستخدما باسم khalid وبعدها سنُضيف مقالا له بعنوان Post 1. إضافة المُستخدم لإضافة مُستخدم سنُنشئ أولا كائنا من الصّنف User مع المعاملات التّي حدّدناها سابقا في دالّة init الخاصّة بالصّنف، ما يعني بأنّنا سنُنشئ مُستخدما كما يلي: user = User('khalid', 'email@example.com', 'password') وهنا يكون التّرتيب مُهمّا ومُطابقا لترتيب المُعاملات في الدّالة __init__، ويُمكنك كذلك تسميّة كلّ معامل وتغيير التّرتيب إن لم تتذكّر سوى أسماء المعاملات كما يلي: user = User(password='password', email='email@example.com',name='khalid') كما تُلاحظ عندما تذكر اسم كلّ معامل، فالتّرتيب غير مهم خلافا للمثال الأول. بعد إنشاء الكائن من صنف المُستخدم بالبيانات التّي نُريدها، يُمكننا الوصول إلى كل قيمة أو تغييرها ببساطة: >>> user = User('khalid', 'email@example.com', 'password') >>> user.name 'khalid' >>> user.email 'email@example.com' >>> user.password 'password' >>> user.email = 'khalid@example.com' >>> user.email 'khalid@example.com' >>> user <username: khalid | email: khalid@example.com > كما تُلاحظ، يُمكننا الوصول إلى كل قيمة من القيم التّي حدّدناها سابقا وكذا تعديلها بإسناد قيمة جديدة بكل بساطة. لاحظ كذلك مُخرجات آخر أمر، يُمكنك أن ترى بأنّ طريقة التّنسيق هذه هي نفسها ما قد حدّدناه سابقا في الدّالة __repr__ بالصّنف User، وإليك تذكيرا سريعا: def __repr__(self): return '<username: {} | email: {} >'.format(self.name, self.email) وأنبّه إلى أنّنا لم نغيّر أي شيء بعد في قاعدة البيانات، وإنشاء الكائن ليس سوى تمهيد لإضافته إلى جلسة تتواجد في الكائن db ثمّ تأكيد التّغييرات لإضافة المُستخدم إلى قاعدة البيانات حقيقة، ولإضافة الكائن user الذي أنشأناها قبل قليل إلى الجلسة نقوم بما يلي: >>> db.session.add(user) والجلسة هنا عبارة عن مكان لإضافة البيانات لوضعها بعد ذلك في قاعدة البيانات، وعند إضافة كل كائن إلى الجلسة لا يُضاف إلى قاعدة البيانات حقيقة إلى أن تنفّذ الأمر db.session.commit. لذا لإضافة المُستخدم خالد إلى قاعدة البيانات PostgreSQL فسننفّذ الأمر التّالي: >>> db.session.commit() بعد تنفيذ الأمر والعودة إلى أداة psql لعرض جميع البيانات في جدول المُستخدمين فستلاحظ بأنّ المُستخدم الذي أضفناه موجود بالفعل: kalima=# select * from users; id | name | email | password | created_date ----+--------+--------------------+----------+---------------------------- 1 | khalid | khalid@example.com | password | 2017-04-08 18:48:05.316805 (1 row) لاحظ بأنّ العمود id أخذ القيمة 1 رغم أنّنا لم نُحدّدها، ولو أضفنا مُستخدما آخر الآن لكان رقم مُعرّفه 2 ولو حذفت مثلا المُستخدم الذي يحمل رقم المعرّف 1 وأضفت مُستخدما آخر، فرقم مُعرّف هذا المُستخدم لن يأخذ مكان المُستخدم الأول بل سيأخذ رقما جديدا مُخالفا للأرقام السّابقة؛ ولاحظ كذلك بأنّ تاريخ الإضافة قد أضيف دون أن نقوم بتحديده يدويا. إضافة المقال بعد أن قُمنا بإضافة المُستخدم، حان الوقت لإضافة مقال خاص به، بالطّبع في التّطبيق المُستخدِم هو من سيُضيف مقالاته، وبعد تسجيله الدّخول، سنستطيع إضافة المقال ووضع قيمة مفتاح مُعرّفه كقيمة للمُعامل author_id، وسنقوم في هذا الجزء بإعطاء مثال لكيفيّة إضافة مقال وإسناد كاتب له، وفي الجزء التّالي سوف نضيف المزيد من المقالات والمُستخدمين لشرح كيفيّة الوصول إلى بيانات كل مُستخدم بما فيها مقالاته، وكذا كاتب كلّ مقال. لإضافة المقال ذي العنوان Post 1 نقوم بنفس الشّيء، أولا نُنشئ كائنا من الصّنف Post ثمّ نُسند له القيم التّي حدّدناها سابقا في الدّالة __init__ الخّاصّة بالصّنف، لكن هذه المرّة نقوم بإضافة مُعامل آخر، وهو عبارة عن قيمة رقم مُعرّف المُستخدم الذي أضاف المقال، وبما أنّنا نمتلك مُستخدما رقم مُعرّفه 1 فهذا يعني بأنّنا نستطيع أن نُسند له هذا المقال بصفته كاتبا له. >>> post = Post('Post 1', 'post 1 content', author_id=1) >>> post <title Post 1 | post 1 content > >>> db.session.add(post) >>> db.session.commit() >>> post.author <username: khalid | email: khalid@example.com > >>> post.author.name u'khalid' >>> post.author.email u'khalid@example.com' >>> post.author.password u'password' كما تُلاحظ، يُمكنك تحديد أسماء معاملات إن أردت، وترك أسماء أخرى على شرط أن تكون القيم مُرتّبة، فقد ذكرت اسم المُعامل author_id فقط لكي تفهم القيمة الثّالثة، وسيتوجّب عليك ذكر الاسم إن كان لك العديد من المفاتيح الأجنبيّة (أرقام مُعرّف تُشير إلى جداول كثيرة) لأنّها ستكون كلّها عبارة عن أرقام لا معنى لها لمن يقرأ الشّيفرة، ويجب عليك أن تتذكّر ترتيبها باستمرار، لذا من المُفضّل تجنّب هذا بذكر اسم كلّ معامل. لاحظ كذلك عندما نستدعي الكائن، فإنّ الدّالة __repr__ تستبدل كلّا من المنطقتين بالعنوان والمحتوى كما هو مُتوقّع. بعد إضافة المقال إلى الجلسة ثمّ تأكيد التّغييرات وكتابتها إلى قاعدة البيانات، أصبح بإمكاننا الآن الوصول إلى كاتب المقال عن طريق post.author والمُخرج عبارة عن كائن يحمل بيانات المُستخدم الذي أدخل البيانات كما لو أنّك حصلت عليه من قاعدة البيانات، إذ تستطيع الوصول إلى قيمة أي عمود في جدول المُستخدمين والنّتيجة تكون عبارة عن سلسلة نصيّة مسبوقة بحرف u للإشارة إلى أنّها عبارة عن Unicode وبالطّبع يُمكنك التّعامل معها كما تتعامل مع سلسلة نصيّة عاديّة. بعد الوصول إلى المُستخدم كاتب المقال، يُمكنك الحصول على مقالاته الأخرى كذلك: >>> post.author.posts.all() [<title Post 1 | post 1 content >] المُخرج عبارة عن قائمة من المقالات يُمكنك الدّوران حولها باستخدام حلقة for ولأنّنا لا نمتلك سوى مقال واحد حاليّا، سنقوم بالوصول إليه مُباشرة برقم العنصر في القائمة: >>> post.author.posts[0] <title Post 1 | post 1 content > >>> post.author.posts[0].title u'Post 1' >>> post.author.posts[0].content u'post 1 content' >>> post.author.posts[0].author <username: khalid | email: khalid@example.com > لاحظ أنّنا استطعنا الوصول إلى كاتب المقال مُجدّدا في آخر سطر، يُمكنك الاستمرار إلى ما لانهاية، المقال –> كاتبُه –> مقال كَتَبه –> كاتبُه –> مقال كَتَبه –> كاتبُه وهكذا… ما يعني بأنّ السّطر التّالي مُمكن: >>> post.author.posts[0].author.posts[0].author.posts[0].author.posts[0].author.posts[0].author.name u'khalid' بالطّبع، لا فائدة من استعمال SQLAlchemy بهذه الطّريقة، إنّما يجب عليك أن تفهم كيف يعمل، وبأنّ مثل هذه الأمور مُمكنة فربّما تُفيدك في تفادي بعض الأخطاء البرمجيّة. خاتمة تعرّفنا في هذا الدّرس على كيفيّة استعمال مُفسّر لغة بايثون للتّعامل مع قاعدة البيانات الخاصّة بنا، وتمكّنّا من إضافة سجلّ إلى جدول المُستخدمين وسجلّ آخر إلى جدول المقالات. في الدّرس القادم، سنطّلع على كيفيّة إنشاء العديد من السّجلات لنتمكّن من العمل معها في بقيّة الدّروس الخاصّة بالتّعامل مع قاعدة البيانات باستعمال مكتبة SQLAlchemy لتتمكّن من تطوير تطبيقات ويب أفضل وأكثر تعقيدا باستعمال إطار العمل Flask.
-
تجهيز قاعدة البيانات بما أنّنا سنستخدم قاعدة البيانات PostgreSQL لهذا التّطبيق، عليك أولا أن تقوم بتنصيبها، إن كنت تستخدم Ubuntu فيُمكنك مُراجعة درس كيفيّة تنصيب PostgreSQL على Ubuntu، أمّا إن كنت على نظام Windows أو نظام Mac OS فتستطيع تحميلها من الموقع الرّسمي وتنصيبها، يُمكنك كذلك استخدام برنامج pgAdmin لإدارة قواعد بياناتك عن طريق برنامج رسومي. يُمكنك استعمال البرنامج الرّسومي لإنشاء قاعدة البيانات إن أردت ذلك، لكنّنا سنستعمل أداة psql لتنفيذ أوامر PostgreSQL واستعمال لغة SQL مباشرة من سطر الأوامر، لذا تأكّد من أنّك تستطيع الوصول إلى أداة psql. إنشاء قاعدة البيانات لإنشاء قاعدة البيانات، يكفي أن ننفّذ الأمر التّالي على سطر أوامر psql : CREATE DATABASE kalima; بعد تنفيذ الأمر، سيكون المُخرج كما يلي: CREATE DATABASE كلمة المرور للاتّصال بقاعدة البيانات، سنحتاج إلى كلمة مرور، إن سبق لك وأن خصّصت كلمة مرور أثناء التّنصيب، تستطيع تخطي هذه الخطوة، أمّا إن لم تمتلك كلمة مرور أو أنّك نسيتها، فيُمكنك ببساطة تغييرها في سطر أوامر psql بالأمر التّالي: \password بعد تنفيذ الأمر سيُطلب منك كتابة كلمة مرور جديدة وإعادة كتابتها للتّأكد من أنّك لم تُخطئ. كلمة المرور هذه مُهمّة جدا للاتّصال بقاعدة البيانات من تطبيق فلاسك باستخدام أداة SQLAlchemy لذا تأكّد من أنّها مُتاحة. ما معنى ORM؟ ORM اختصار Object-Relational Mapper أي رابط الكائنات بالعلاقات (الجداول)، الهدف منه ببساطة التّعامل مع قواعد بيانات SQL باستعمال الكائنات Objects والأصناف Classes عوضا عن تعليمات SQL، فعوضا عن إنشاء البيانات وجلبها وتعديلها وحذفها عن طريق تعليمات SQL التّي ستتكرّر كثيرا في الشّفرة يُمكن ببساطة استخدام لغة بايثون للوصول إلى نفس الهدف، كما أنّ استعمالها مع لغة برمجة يخلق شيئا من عدم التّناسق. لو تابعت سلسلة دروس Flask للمُبتدئين، للاحظت بأنّنا استعملنا ملفّا باسم manage_db للتّعامل مع قواعد البيانات عن طريق الدّوال عوضا عن كتابة تعليمات SQL عند الرّغبة في إجراء كل عمليّة، ولو استعملنا SQL الخام لكان تكرار الشّفرة كثيرا. بالإضافة إلى ميّزة تعريف الأصناف التّي تُمثّل الجداول والتّعامل معها عن طريق التّوابع (الدوال) لتجنّب تكرار الشّفرة، يقوم الـORM بالكثير من الأشياء المُملّة خلف الكواليس، فعوضا عن الاهتمام بالتّفاصيل الصّغيرة بأنفسنا، يقوم الـORM بالاهتمام بها من أجلنا لنهتمّ بالأمور الأكثر أهميّة، وفي النّهاية، مُعظمنا لا يتقن لغة SQL كثيرا لذا من المُفضّل استعمال مكتبة للتّعامل مع قواعد البيانات باللغة التّي نُجيدها. وبما أنّ استعمال الـORM يُتيح لنا عزل الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في معزل عن التّطبيق فهذا يُتيح لنا تعديل الخصائص وإضافة الميّزات للتّطبيقات دون التّأثير على تطبيق معيّن بحد ذاته، ومن الشّائع جمع الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في ملف باسم models.py في مجلّد المشروع. يُساعدنا الـORM كذلك على تحقيق مبدأ MVC أو Model-View-Controller أي “نموذج، عرض، مُتحكّم ” وهو مبدأ يقوم على عزل جزء العرض، المُتحكّمات، والنّماذج في تطوير التّطبيقات لمرونة أكثر في التّطوير، أي أنّ كلّا من العرض (الذي يُمثّل القوالب في تطبيقنا) والمُتحكّم (الذي يُمثّل دوال الموجّهات في ملفّات views.py) والنّموذج (أي الجزء الذي يتعامل مع البيانات) أجزاء منفصلة حسب الوظيفة متّصلة في التّطبيق ويُمكن أن تنتقل البيانات بينها ببساطة، ورغم أنّ إطار Flask يمنحك الحريّة الكاملة في طريقة تسميّة أجزاء تطبيقك، إلّا أن أطر عمل أخرى مثل Django و Rails تفرض عليك تسميّات محدّدة. ما هو SQLAlchemy؟ بعد أن عرّفنا معنى الـORM بقي تعريف مكتبة SQLAlchemy، وهي مكتبة تُسهّل علينا التّعامل مع قواعد البيانات المُختلفة، كما أنّها تحتوي على ORM قوي ومُعتمد عليه من طرف المشاريع الكبيرة. تحتوي SQLAlchemy على الكثير من الدّوال المُساعدة والكائنات التّي تُسهّل عليك كتابة SQL بلغة بايثون، والORM المبني فيه يُستعمل لربط الكائنات بالبيانات في قاعدة البيانات. سنستعمل في غالب هذا المشروع الـORM الخاص بـSQLAlchemy ولن نتطرّق إلى بقيّة ميّزات المكتبة، لذا إن أردت معرفة المزيد عن المكتبة فعليك بالتّوثيق الرّسمي. إضافات Flask Flask Extensions أو إضافات فلاسك عبارة عن مكتبات وأطر عمل Frameworks مبنيّة لتُسهّل على المُطوّر القيام بالأشياء المُفصّلة وتجنّب التّعامل مع كل شيء بأنفسنا، فمثلا، يُمكننا أن نستعمل مكتبة SQLAlchemy مع تطبيق Flask مُباشرة، إلّا أن في هذه الطّريقة الكثير من الأمور غير المُهمّة والكثير من الإعدادات، وبما أنّنا في مسيرة تعلّم إطار فلاسك لا كيفيّة استعمال SQLAlchemy، ولتسهيل استعمال SQLAlchemy مع المشاريع المبنيّة بإطار العمل فلاسك، قام كاتب الإطار Armin Ronacher بتطوير إضافة للإطار باسم Flask-SQLAlchemy التّي أصبحت أحد أشهر الإضافات على موقع Github. بالإضافة إلى Flask-SQLAlchemy هناك الكثير من الإضافات التّي يُمكننا استعمالها لتطوير تطبيقات فلاسك، وإليك بعضا من هذه الإضافات: Flask-Login إضافة لتسهيل التّعامل مع جلسات المُستخدمين Sessions، تُتيح إمكانيّة تسجيل دخول مُستخدم وتسجيل خروجه، لكنّها لا تقوم بالتّحقق من صحّة البيانات (اسم المُستخدم وكلمة المرور مثالا) وتترك المُطوّر للاهتمام بالأمر. Flask-Bcrypt إضافة لتشفير كلمات المرور باستعمال خوارزميّة Bcrypt قبل حفظها بقاعدة البيانات لحماية أكثر، هذا لمنع المُخترق من سرقة كلمات المرور حتى بعد وصوله إلى قاعدة البيانات، وكلّما كانت خوارزميّة التّشفير أعقد كلّما كان من الصّعب فك التّشفير عن كلمة المرور ما يُوفّر حماية أكثر. Flask-WTF بما أنّ مُعظم التّطبيقات تعتمد على نماذج HTML (حقول النّصوص، كلمات المرور و مساحة النّص TextArea) وبما أنّها تُسبّب الكثير من الثّغرات الأمنيّة في التّطبيقات والتّي يُمكن أن يُساء استغلالها، فلا بد من توفير طريقة آمنة وبسيطة للتأكّد من أنّ ما يُدخله المُستخدم في هذه الحقول آمن. يُمكنك بالطّبع التّأكد من مُدخلات المُستخدم بنفسك، لكنّ الأمر يأخذ وقتا، كما أنّه ممل في الحقيقة، إذ عليك تكرار نفس الشّيء كلّ مرّة. عوضا عن الاعتماد على مهاراتك البرمجيّة للتأكّد من سلامة المُدخلات، يُمكنك أن تترك إضافة Flask-WTF للاهتمام بالأمر في تطبيقاتك المبنيّة بإطار فلاسك، الإضافة مبنيّة على مكتبة WTForms التّي يُمكنك استعمالها مع أطر عمل أخرى، وأنصحك بالاطلاع على توثيق المكتبة الرّسمي للمزيد من المعلومات عن كيفيّة مُعالجة النّماذج. Flask-Migrate ببساطة، Flask-Migrate إضافة تُتيح لك تهجير البيانات Migrations عند تطوير تطبيقك. هذه الإضافة مهمّة جدّا إن كنت تطوّر تطبيقا سبق وأن نشرته على نحو مُتواصل، إذ تُتيح لك تهجير البيانات في كل مرّة تُضيف جدولا جديدا أو علاقة بين الجداول إلى قاعدة البيانات. تخيّل أنّك تمتلك تطبيقا يحتوي جدول المُستخدمين فيه على أكثر من ألف مُدخل، إن أردت إتاحة إمكانيّة إضافة تاريخ ازدياد للمُستخدمين فستضطر إلى حذف كلّ شيء في هذا الجدول وإضافة العمود الجديد ثمّ إعادة البيانات من جديد، الأمر مُعقّد بعض الشّيء وفقدان البيانات أمر غير مرغوب فيه بتاتا. مُجدّدا عوضا عن القيام بكل شيء بنفسك، دع إضافة Flask-Migrate لتهتمّ بكل هذا التّعقيد من أجلك، فبسطر أو سطرين تستطيع تطبيق الميّزة الجديدة لتطبيقك وتهجير البيانات القديمة بكل بساطة. Flask-Testing إضافة لتسهيل إجراء اختبارات وحدة Unit tests لتطبيقك، إذ أنّ اختبار التّطبيق مُهمّ جدّا للتأكّد من أنّ كلّ شيء بخير وأنّ المُستخدمين لا يواجهون أية مشاكل، خاصّة إذا كان مشروعك كبيرا، فاختبار كل وظيفة يدويّا قد يأخذ منك وقتا طويلا، وإن لم تختبره آليا فنسبة الخطأ كبيرة جدّا. إذا أضفت خاصيّة جديدة لتطبيقك فأنت بذلك تُعرّض أجزاء أخرى من التّطبيق إلى الخطأ، وستُسهّل عليك الاختبارات معرفة ما إذا كان التّطبيق لا يزال يعمل كما ينبغي له أو لا، وبما أنّ اختبارات الوحدة تختبر كلّ وظيفة على نحو مُستقل، فسيسهل عليك معرفة أي جزء يجب عليك الاهتمام به لإصلاح التّطبيق. Flask-Gravatar هذه الإضافة تُسهّل لنا استعمال خدمة Gravatar لتمكين المُستخدمين من إضافة صورة شخصيّة لهم، إذ تكون الصّورة الشّخصيّة مُرتبطة بالبريد الإلكتروني للمُستخدم وتُستعمل هذه الخدمة في الكثير من التّطبيقات في وقتنا الحالي. هناك مئات الإضافات الخاصّة بإطار Flask لذا لا يُمكنني ذكرها كلّها، إن أردت الاطّلاع على إضافات أخرى، تستطيع البحث عنها عن طريق أداة pip كما يلي: pip search flask سنتعرّف على معظم هذه الإضافات في قادم الدّروس مع التّقدم في المشروع، وهذا الهدف الأساسي من هذه الإضافات، كلّما تقدّمت أكثر وكبر المشروع كلّما احتجت إلى التّعامل مع الكثير من المهام المُملّة كالتّأكد من أنّ ما يرسله المُستخدم إلى قاعدة بياناتك آمن، وكالتّعامل مع الجلسات لتوفير نظام تسجيل دخول آمن دون الاضطرار للقيام بكل التّفاصيل؛ كما أنّ الإضافات تُقلّل من حجم الخطأ في التّطوير، فالاعتماد على إضافة لتسجيل دخول المُستخدمين بشكل آمن أفضل من مُحاولة إنشاء طريقة خاصّة بك قد تكون مليئة بالثّغرات الأمنيّة. وبما أنّ فلاسك إطار عمل مُصغّر، فبإضافاته يُمكنك أن تستخدمه كما تُستخدم أطر العمل الضّخمة كـDjango و Rails و Laravel وغيرها من الأطر المشهورة. خاتمة بعد أن أنشأنا قاعدة البيانات وتعرّفنا على بعض المفاهيم المُهمّة في تطوير تطبيقات الويب مع إطار فلاسك، حان الوقت لإنشاء الجداول الأساسيّة في قاعدة البيانات لنتمكّن من التّعامل معها عن طريق إضافة Flask-SQLAlchemy وهذا بالضّبط ما سنقوم به في الدّرس القادم.
-
يحدُث كثيراً أن ينقسم مجتمع المطوّرين حول تقنيّات يراها بعضهم غير ذات جدوى أو على الأقل ليست بالأهميّة التي يروّج لها مؤيّدوها. تنطبق هذه الملاحظة على أطر العمل التي تعمل على ربط العلاقات بالكائنات Object relational mapping (أو ORM اختصارا)، ومن بينها Eloquent الذي يُستخدَم مبدئيًّا في Laravel؛ دون أن يعني ذلك عدم إمكانيّة استخدامه خارج Laravel كما سنرى في هذه السّلسلة. ليست أطر عمل ORM بالتقنيّة الجديدة، فهي توجد منذ سنين وأصبحت جزءًا من عمليّة التطوير بالنسبة للكثير من المبرمجين؛ كما أنها حسّنت من أدائها وتغلّبت على الكثير من النواقص مع الزمن. يتناول هذا الدّرس، الأوّل من سلسلة دروس عن الإطار Eloquent ORM، الأسباب التي أدّت إلى ظهور أطر عمل ORM والهدف من ورائها. التصوّر البرمجي Programming paradigm وإدارة البيانات العلاقيّة تُكتَب أغلب تطبيقات PHP الحديثة بأسلوب ذي تصوّر Paradigm كائنيّ التوجّه Object oriented، بينما تستخدم قواعدَ بيانات علاقيّة لإدارة البيانات وتخزينها. دور أُطُر عمل ORM هو تسهيل الانتقال بين هذيْن العالميْن أثناء تشغيل التطبيق. البرمجة كائنية التوجّه تعتمد لغات البرمجة على أفكار ونُظُم تحدّد طريقة عملها وأساليب كتابة البرامج التي تعمل بها. تُسمّى هذه الأساليب والقواعد بالتصورات البرمجيّة. يمكن للغةِ برمجة أن تُصنَّف في أكثر من تصوّر؛ إلّا أن كل لغة تركّز غالبًا على بضعة تصوّرات، ممّا يجعل كتابة برامج وفقَ هذه التصوّر ات أسهل بالنسبة لمبرمجي اللغة. تدعم لغة PHP البرمجيّة ميزات من تصوّرات برمجيّة عدّة؛ إلا أنها تُركّز على تصوّريْن: التصوّر الإجرائي Procedural الذي يمكن عدّه التصوّر الأساسي للغة منذ بداياتها. التصوّر كائنيّ التوجه Object oriented الذي اعتمده مصمّمو لغة البرمجة - فعليًّا - في الإصدار الخامس (سنة 2004). يُؤسَّس التصوّر الإجرائي على التصريح بكيفيّة إجراء العمليّات، خطوة بخطوة، واستخدام الحلقات Loops، العبارات الشرطيّة Conditions وتجميع الأوامر في سياقات محليّة Local context أو ضمن وحدات Modules يمكن استدعاءها عند الحاجة. أما التصوّر كائنيّ التوجه فيقوم على جمع البيانات والإجراءات (الدوالّ) ضمن كائن Object واحد يمكنه تطبيق الإجراءات المضمَّنة فيه على البيانات التي تخصّه. أنظمة قواعد بيانات العلاقيّة يعتمد النموذج العلاقي على نظريّة المجموعات Set theory والمنطق الرياضي من أجل تجميع البيانات ضمن جداول Tables؛ هي في الواقع علاقات Relations وفق التعريف الرياضي، ومنه التسميّة. يهدف النموذج العلاقي إلى تقديم طريقة تمكّن المستخدمين من تحديد البيانات المُعدّة للتخزين في قاعدة البيانات وتلك التي يريدون الحصول عليها من القاعدة، دون الاهتمام بالكيفيّة التي يستخدمها نظام الإدارة للإجابة على هذه الطلبات. يسمّى التصوّر البرمجي الذي يهتمّ بماهيّة المهمّة دون التركيز كثيرًا على كيفيّة أدائها بالتصوّر التقريري Declarative paradigm. يمكن عدّ لغة الاستعلام SQL تطبيقًا عمليًّا للنموذج العلاقي، وإن كانت تنحرف أحيانًا عن هذا النموذج. ربط العلاقات بالكائنات Object relational mapping تنبني شفرة التطبيقات التي تعتمد على تصوّر كائنيّ التوجه على أسس نظريّة تختلف عن تلك التي تُبنى عليها قواعد البيانات (النموذج العلاقي)؛ وهو ما يعني أنه على المطورين إيجاد طريقة للتخاطب مع قاعدة البيانات انطلاقًا من الشفرة البرمجيّة. يستخدم المبرمجون عادةً كائنًا مخصّصًا - يُسمّى كائن الوصول إلى البيانات Data access object، أو DAO اختصارا - لتخزين البيانات في القاعدة أو جلبها منها ثم تقديمها لبقيّة التطبيق بصيغة تناسبه. تُكتَب في هذا الصّنف استعلامات SQL المطلوب تنفيذها للتخاطب مع قاعدة البيانات، إما مباشرة أو عبر مكتبة وسيطة. يُساعد استخدام كائن DAO على الفصل بين أجزاء التطبيق واحترام مبادئ نمط التطوير Model-Vue-Controller (أو MVC اختصارا)؛ إلا أنّ كائنات DAO تتطلّب الكثير من الوقت، إذ يتحتّم على المطوِّر كتابة الكثير من التعليمات لتخزين البيانات في القاعدة أو جلبها منها. تأتي أطُر عمل ORM - ومن بينها Eloquent - للتخفيف من عبء هذه المهمّة. إطار العمل Eloquent ORM يسعى Laravel إلى أن يكون إطار عمل سهلَ الاستخدام يوفّر على المطوّرين الوقت ويرفع من إنتاجيّتهم؛ لذا جعل من Eloquent إطار عمل ORM الذي يستخدمه مبدئيًّا، لما يتميّز به من سهولة الاستخدام ووضوح آليّة العمل. طُوِّر Eloquent وفقا لنمط التسجيلة النشطة Active record الذي يقوم على وجود صنف Class لكلّ جدول في قاعدة البيانات، بحيث يُنشَأ كائن من هذا الصّنف لكل تسجيلة (سطر في الجدول). يعني هذا أن بيانات الكائن تحمل نسخة طبق الأصل من تسجيل الجدوَل. يُسمِّى Eloquent الصّنفَ الذي يطابق الجدول بالنموذج Model. يحوي كلّ كائن من هذا الصنف خاصيّات Attributes بعدد وأسماء توافق حقول (أعمدة) الجدول؛ وتمكّن الدوالّ التي يوفّرها من القيام بعمليّات من قبيل إدراج التسجيلة، التعديل عليها أو حذفها. إذا كان لدينا - مثلا - جدول في قاعدة البيانات باسم Address نحتفظ فيه بعناوين أشخاص، فإن إدراج عنوان جديد في قاعدة البيانات سيكافئ إنشاء كائن من الصنف (النموذج) Address وملئه بالبيانات التي نريد ثم استدعاء دالة التخزين في هذا الكائن. يضيف Eloquent وظائف مساعدة مثل التحقّق من أن الكائنات تحترم قواعد معيّنة قبل تخزينها في الجدول؛ وهو ما يعني التقليل من الأخطاء على مستوى قاعدة البيانات. قد تجد نفسك أمام حالات معقّدة لا تؤدّي فيها هذه الطريقة (تطبيق الدوالّ على الصنف المماثل لجدول قاعدة البيانات) النتيجة المطلوبة؛ يمكنك في هذه الحالة استخدام منشئ الاستعلامات Query builder وكتابة استعلامات SQL مباشرة. يُنصَح بتجنّب Eloquent عند تنفيذ سلسلة طويلة من المهامّ تلقائيًّا، دون تدخّل يدوي. يُناسب Eloquent المعاملات Transactions، وهي مجموعة إجراءات تُنفَّذ في قاعدة البيانات على أنّها وِحدة لا تتجزّأ: إما أن تُطبَّق جميع الإجراءات الموجودة في المعاملة أو لا تُطبَّق أي منها.
-
أنشأنا في الدرس السابق بنية قاعدة البيانات الخاصة بمشروع Larashop. نكمل في هذا الدرس حديثنا عن قواعد البيانات في Laravel بشرح كيفية إدراج تسجيلات في قواعد البيانات وكيفية استخراجها منها باستخدام إطار العمل Eloquent. هذا الدرس جزء من سلسلة تعلم Laravel والتي تنتهج مبدأ "أفضل وسيلة للتعلم هي الممارسة"، حيث ستكون ممارستنا عبارة عن إنشاء تطبيق ويب للتسوق مع ميزة سلة المشتريات. يتكون فهرس السلسلة من التالي: مدخل إلى Laravel 5.تثبيت Laravel وإعداده على كلّ من Windows وUbuntu.أساسيات بناء تطبيق باستخدام Laravel.إنشاء روابط محسنة لمحركات البحث (SEO) في إطار عمل Laravel.نظام Blade للقوالب.تهجير قواعد البيانات في Laravel. استخدام Eloquent ORM لإدخال البيانات في قاعدة البيانات، تحديثها أو حذفها. (هذا الدرس)إنشاء سلة مشتريات في Laravel.الاستيثاق في Laravel.إنشاء واجهة لبرمجة التطبيقات API في Laravel.إنشاء مدوّنة باستخدام Laravel.استخدام AngularJS واجهةً أمامية Front end لتطبيق Laravel.الدوّال المساعدة المخصّصة في Laravel.استخدام مكتبة Faker في تطبيق Laravel لتوليد بيانات وهمية قصدَ الاختبار. سنغطي في هذا الدرس المواضيع التالية: نماذج Eloquentأعراف التسمية.أسماء الجداول والمفاتيح الخارجية.الأختام الزمنية.إطار العمل Eloquentقراءة البيانات READ.تحديث البيانات UPDATE.حذف البيانات DELETE.إدراج البيانات INSERT.تنفيذ استعلامات SQL في Laravel.نماذج Eloquent لمشروع Larashop.استخدام النماذج في المتحكمات.إظهار بيانات النماذج في العروض.إطار عمل Eloquentيأتي Laravel مضمنًّا بإطار عمل Eloquent الذي يُستخدَم للتخاطب مع قاعدة البيانات وتنفيذ عمليات مثل الإدراج Insert، التحديث Update أو الحذف Delete على الجداول. Eloquent هو إطار عمل لربط كائنات التطبيق بعلاقات (جداول) قاعدة البيانات Object Relational Mapper, ORM. يقوم مبدأ ربط العلاقات بالكائنات على تنفيذ نمط ActiveRecord (التسجيلة النشطة)؛ الذي هو وسيلة للوصول إلى البيانات في قاعدة البيانات، حيث يضمن جدول بيانات (أو علاقة في قاعدة البيانات بصفة عامة) في صنف Class وتُربط كل تسجيلة من جدول البيانات بكائن Object من الصنف. بهذه الطريقة يُصبح التعامل مع الصنف مماثلا للتعامل مع الجدول في قاعدة البيانات. مثلا، لإدراج تسجيلة جديدة في جدول قاعدة البيانات ننشئ - في التطبيق - كائنا جديدا من الصنف المربوط بالجدول. وإذا أردنا أن نحدّث بيانات تسجيلة من الجدول نحدّث خاصيّات الكائن المربوط بها. نماذج Eloquentتُستخدَم النماذج في بنية MVC للتفاعل مع مصادر البيانات (قواعد البيانات، ملفات نصية، … إلخ). تُعرَّف النماذج في Laravel بتمديد الصنف Illuminate\Database\Eloquent\Model الذي يوفّر دوال جاهزة للاستخدام من أجل التفاعل مع مصدر البيانات. أعراف التسمية في Eloquentتوجد بعض الأعراف التي يفترض إطار العمل Eloquent مبدئيا اتّباعها، مع وجود إمكانية لتغييرها حسب الرغبة. في العرف أن اسم النموذج يكون كلمة مفردة تبدأ بحرف كبير Upper case، بينما اسم الجدول في قاعدة البيانات كلمة للجمع بأحرف صغيرة Lower case. يعتمد Laravel هذا العرف فيربط تلقائيا بين النموذج ذي الاسم المفرد والجدول الذي يكون اسمه جمعا لاسم النموذج. نستخدم أداة Artisan لإنشاء نموذج لجدول التصنيفات categories باسم Category (مفرد categories): php artisan make:model Categoryينشئ الأمر ملفا للنموذج على المسار app/Category.php. نفتح الملف لرؤية محتواه: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model { // }نعرف فضاء الأسماء الذي يتبع له النموذج: ;namespace App.نستورد فضاء الأسماء الخاص بـ Eloquent بالتعليمة: use Illuminate\Database\Eloquent\Model;.يمدّد الصنفُ Category صنفَ نماذج Eloquent الذي تحدثنا عنه أعلاه: class Category extends Model.من المتعارف عليه أيضا أن حقل المفتاح الرئيس للجدول يُسمّى id، ومن الممكن مثل ما هو الحال مع اسم الجدول، تحديدُ اسم مغاير لحقل المفتح الرئيس. يمكن تحديد اسم الجدول في النموذج بغض النظر عن المتعارف عليه بإعطاء قيمة للمتغير table$، نفس الشيء بالنسبة للمفتاح الرئيس مع المتغير primaryKey$: protected $primaryKey = 'id'; protected $table = 'categories';تسجيلات الأختام الزمنيةيفترض Laravel إضافةَ الحقلين created_at وupdated_at إلى جداول قاعدة البيانات. تُدرج قيمتا الحقلين عند إنشاء تسجيلة جديدة في الجدول، وتحدّث قيمة updated_at عند تحديث قيمة التسجيلة. إن لم تضف هذين الحقلين في جداول قاعدة البيانات فيمكن تعطيل الإعداد المبدئي على النحو التالي: public $timestamps = false;استخدام Eloquentنكمل كتابة الشفرة المصدرية للنموذج Category ليصبح كما يلي: <?php namespace App; class Category extends Model { protected $primaryKey = 'id'; protected $table = 'categories'; }عرّفنا حقل المفتاح الرئيس للجدول: ;'$primaryKey = 'id. ليس هذا ضروريا هنا ما دام اسم الحقل يوافق العُرْف (id). نفس الملحوظة تنطبق على تعريف اسم الجدول في التعليمة الموالية.قراءة محتوى جدول في قاعدة البياناتسنرى، في هذه الفقرة، كيفية العثور على جميع التصنيفات التي نحتفظ بها في جدول التصنيفات. ملحوظة: نطبع النتائج في الأمثلة أدناه مباشرة من الشيفرة المصدرية للمسار دون الاستعانة بالمتحكم رغم أن ذلك مخالف لمبدأ MVC، إلا أن الغرض هنا هو رؤية عمل Eloquent. سنعود لترتيب الأمور في ما بعد. افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('/read', function() { $category = new App\Category(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } }); ننشئ كائنا جديدا من صنف النموذج: $category = new App\Category();التعليمة التالية تستدعي الدالة all في الكائن الذي أنشأناه للتو، وتمرر له مصفوفة تحدد الحقول التي نود الحصول عليها؛ في حالتنا حدّدنا الحقلين id (المعرِّف) وname (اسم التصنيف). إن لم تُحدَّد معطيات للمصفوفة فستُرجع الدالة جميع الحقول. نستخدم حلقة تكرارية foreach لإظهار النتائج التي تحصلنا عليها.احفظ التعديلات ثم افتح الرابط http://larashop.dev/read في المتصفح. ستحصُل على لائحة شبيهة بالتالي (قد تختلف النتيجة لديك قليلا): 5 CLOTHING 4 FASHION 3 KIDS 1 MEN 2 WOMENتحديث تسجيلاتسنحدّث في هذه الفقرة تسجيلة في جدول التصنيفات باستخدام المعرِّف id. نختار معرّف إحدى التصنيفات الظاهرة في نتيجة المثال السابق، مثلا التصنيفKIDS ذو المعرِّف 3. نعيد فتح ملف المسارات routes.php ونضيف مسارا جديدا كما يلي: Route::get('/update', function() { $category = App\Category::find(4); $category->name = 'KIDS 2'; $category->save(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } });نستدعي الدالة find الموجودة في النموذج مع تمرير معرّف التصنيف إليها. ترجع الدالة كائنا من صنف Category يحوي بيانات التصنيف المستقاة من تسجيلة في الجدول categories.نعيّن الاسم الجديد للتصنيف بالتعديل على الخاصية name في الكائن category$.لتُعتمَد التعديلات وتخزَّن في السجل نستدعي الدالة save من الكائن category$.نستخدم حلقة تكرارية foreach لإظهار النتائج التي تحصلنا عليها.احفظ الملف ثم افتح الرابط http://larashop.dev/update في المتصفح. لاحظ تغيّر اسم التصنيف من KIDS إلى KIDS 2. حذف تسجيلة من جدول في قاعدة البياناتنختار أحد التصنيفات لحذفه (مثلا، التصنيف CLOTHING ذو المعرف 5). افتح ملف المسارات routes.php وأضف المسار التالي: Route::get('/delete', function() { $category = App\Category::find(5); $category->delete(); $data = $category->all(array('name','id')); foreach ($data as $list) { echo $list->id . ' ' . $list->name . '</br>'; } }); يوجد شبه كبير بين تحديث تسجيلة وحذفها. الفرق هو أنه بعد إيجاد التصنيف (الدالة find) نستدعي الدالة delete في الكائن category$ لحذف التسجيلة المربوطة به. افتح الرابط http://larashop.dev/delete ولاحظ أن التصنيف لم يعد موجودا. إدراج تسجيلةلإدراج تسجيلة جديدة في جدول قاعدة البيانات ننشئ كائنا جديدا من صنف Category ونعيّن خواصّه ثم نخزنه في الجدول، كما يلي: Route::get('/insert', function() { $category= new App\Category; $category->name='Music'; $category->save(); return 'category added'; }); بالذهاب إلى الرابط http://larashop.dev/insert تظهر رسالة category added دلالةً على إضافة التصنيف. يمكن أيضا التحقق من إضافة التصنيف من سطر أوامر MySQL أو بالذهاب إلى الرابط http://larashop.dev/read. توجد طريقة أخرى لاستخدام سطر برمجي واحد لإدراج تصنيف في تسجيلة. نستخدم لهذا الغرض الدالة create من نموذج التصنيف Category؛ ولكن يجب قبل ذلك التعديل على النموذج Category لتمكين الإسناد الشامل Mass assignment (تحديد قيم معطيات عدّة مرة واحدة). نفتح ملف النموذج لتحريره ثم نضيف السطر التالي: protected $fillable = array('name', 'created_at_ip', 'updated_at_ip'); يعرف المتغير fillable$ مصفوفة بالحقول التي يمكن تعيين قيمها دفعة واحدة. احفظ ملف النموذج ثم افتح ملف المسارات routes.php وعدل المسار insert/ ليصبح التالي: Route::get('/insert', function() { App\Category::create(array('name' => 'New Music')); return 'category added'; }); نستدعي الدالة create من الصنف Category ونمرر لها مصفوفة بحقول التسجيلة الجديدة مع قيمها. ينبغي أن تكون الحقول الممررة قابلة للإسناد الشامل، أي مذكورة في المتغير fillable$. لاحظ أن إنشاء الكائن وتعيين قيم خاصياته ثم تخزين محتوياته في قاعدة البيانات كل هذا تم من خلال استدعاء الدالة create. ملحوظة 1: عند طلب الرابط http://larashop.dev/insert في المرة الأولى تظهر الرسالة category added ولكن عند طلب نفس الرابط مرة أخرى دون تعديل المسار تظهر صفحة بيضاء دلالة على عدم إدراج التسجيلة. يعود السبب في ذلك إلى أننا أثناء تعريف الجدول categories في الدرس السابق علّمنا الحقل name بالدالة unique أي أنه لا يمكن لتسجيلتين من هذا الجدول أن يكون لهما نفس الاسم. ملحوظة 2: الإسناد الشامل غير ممكّن مبدئيا لأسباب أمنية ويجب عند تمكينه اختيار حقول fillable$ بعناية حتى لا تمثل خطرا أمنيا. يجب دائما تطهير Sanitize البيانات التي يستقيها التطبيق من المستخدم. تنفيذ استعلامات SQL مباشرةقد ترغب، لسبب أو آخر، في التعامل المباشر مع قاعدة البيانات باستخدام استعلامات SQL؛ يوفر Laravel صنف DB لهذا الغرض. استعلامات SELECTتُستخدَم دالة select لتنفيذ استعلامات القراءة من قاعدة البيانات على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id = ?', [1]);تأخذ الدالة DB::select معطيين: الأول هو استعلام القراءة المراد تنفيذه، والثاني معطيات نود استخدامها في الاستعلام. بالنسبة للمعطيات المراد استخدامها في الاستعلام فتُحدّد أماكنها بعلامة ? وتكون قيمتها في مصفوفة تمرّر في المعطى الثاني للدالة DB::select. ينفذ السطر أعلاه استعلام SQL التالي: SELECT name FROM categories WHERE id = 1;نفرض أننا نريد تنفيذ استعلام SQL التالي: SELECT name FROM categories WHERE id BETWEEN 1 AND 4;يطلب الاستعلام قيمتين (1 و4). يُترجم الاستعلام في النموذج على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id BETWEEN ? AND ?', [1,4]);تُبدل أول علامة ? في الاستعلام بأول عنصر من المصفوفة في معطى الدالة الثاني، وعلامة ? الثانية بالمعطى الموالي وهكذا. يمكن أيضا استخدامُ متغيرات بدلا من ? على النحو التالي: $category = DB::select('SELECT name FROM categories WHERE id BETWEEN :id1 AND :id2', ['id1' => 1, 'id2' => 4]);لاحظ استخدام : قبل أسماء المتغيرات في استعلام SQL. استعلامات INSERTتُستخدم دالة DB::insert لإدراج تسجيلات في الجدول بنفس طريقة استخدام DB::select للقراءة منه: $inserted=DB::insert('INSERT INTO categories (name) VALUES (?)', ['TEST']);ترجع الدالة DB::insert عدد التسجيلات التي أدرجها الاستعلام. استعلامات UPDATEلتحديث تسجيلة في جدول بقاعدة البيانات نستخدم الدالة DB::update: $affected = DB::update('UPDATE categories SET name = 'TEST UPDATE' WHERE name = ?', ['TEST']);ترجع الدالة DB::update عدد التسجيلات التي حدثها الاستعلام. استعلامات DELETEتوفر الدالة DB::delete إمكانية تنفيذ استعلامات DELETE على النحو التالي: $deleted = DB::delete('DELETE FROM categories WHERE id = ?', [13]);ترجع الدالة DB::delete عدد التسجيلات التي حذفها الاستعلام. استعلامات عامةبالنسبة للاستعلامات التي لا ترجع أية قيمة فيمكن استخدام الدالة DB::statement: DB::statement('drop tables drinks');نماذج Eloquent لمشروع Larashopنشرع الآن بعد أن رأينا آلية عمل Eloquent ببناء بقية نماذج مشروع Larashop. نفذ الأوامر التالية لإنشاء نماذج للعلامات التجارية، المنتجات ومنشورات المدونة على التوالي: php artisan make:model Brand php artisan make:model Product php artisan make:model Postنعرّف في كل ملف نموذج حقل المفتاح الرئيس، اسم الجدول وأسماء الحقول المسموح بإسنادها fillable. ملف Brand.php: <?php namespace App; class Brand extends Model { protected $primaryKey = 'id'; protected $table = 'brands'; protected $fillable = array('name', 'created_at_ip', 'updated_at_ip'); } ملف Product.php: <?php namespace App; class Product extends Model { protected $primaryKey = 'id'; protected $table = 'products'; protected $fillable = array('name', 'title', 'description','price','category_id','brand_id','created_at_ip', 'updated_at_ip'); } ملف Post.php: <?php namespace App; class Post extends Model { protected $primaryKey = 'id'; protected $table = 'posts'; protected $fillable = array('url', 'title', 'description','content','blog','created_at_ip', 'updated_at_ip'); } استخدام النماذج في المتحكماتتقضي بنية MVC وعادات البرمجة الصحيحة أن تكون المتحكمات هي من يتعامل مع النماذج. سنعدّ متحكم المشروع Front.php للعثور على البيانات من النماذج وتمريرها إلى العروض لتظهر لدى المتصفح. عدّل ملف Front.php كالتالي: <?php namespace App\Http\Controllers; use App\Brand; use App\Category; use App\Product; use App\Http\Controllers\Controller; class Front extends Controller { var $brands; var $categories; var $products; var $title; var $description; public function __construct() { $this->brands = Brand::all(array('name')); $this->categories = Category::all(array('name')); $this->products = Product::all(array('id','name','price')); } public function index() { return view('home', array('title' => 'Welcome','description' => '','page' => 'home', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function products() { return view('products', array('title' => 'Products Listing','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_details($id) { $product = Product::find($id); return view('product_details', array('product' => $product, 'title' => $product->name,'description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_categories($name) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function product_brands($name, $category = null) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function blog() { return view('blog', array('title' => 'Welcome','description' => '','page' => 'blog', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function blog_post($id) { return view('blog_post', array('title' => 'Welcome','description' => '','page' => 'blog', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products)); } public function contact_us() { return view('contact_us', array('title' => 'Welcome','description' => '','page' => 'contact_us')); } public function login() { return view('login', array('title' => 'Welcome','description' => '','page' => 'home')); } public function logout() { return view('login', array('title' => 'Welcome','description' => '','page' => 'home')); } public function cart() { return view('cart', array('title' => 'Welcome','description' => '','page' => 'home')); } public function checkout() { return view('checkout', array('title' => 'Welcome','description' => '','page' => 'home')); } public function search($query) { return view('products', array('title' => 'Welcome','description' => '','page' => 'products')); } } في المتحكم: نستورد النماذج: use App\Brand; use App\Category; use App\Product; نعرف متغيرات لتحميل بيانات النماذج: var $brands; var $categories; var $products; يعرف المتغيران title$ وdescription$ على التوالي عنوانا ووصفا لأغراض التحسين لمحركات البحث. نُعرّف باني Constructor صنف المتحكم: public function __construct(){…}تحمّل هذه الدالة البيانات من النماذج إلى المتغيرات المعرّفة سابقا. نحمّل في الدالة index العرض home مع تمرير مصفوفة معطيات تمثل بيانات النماذج مع بيانات أخرى لغرض التحسين لمحركات البحث.عرض بيانات النماذج في العروضنستخدم الحلقات التكرارية في قوالب Blade من أجل عرض بيانات النماذج التي مررها المتحكم إلى العروض. على سبيل المثال: @foreach ($brands as $brand) <li><a href='{{url("products/brands/$brand->name")}}'> <span class="pull-right">(50)</span>{{$brand->name}}</a></li> @endforeachتوجد عروض المشروع في الملف المرفق. خاتمةمن السهل إنشاء نماذج Eloquent واستخدامها؛ كل ما عليك فعله هو تمديد صنف Model والبدء باستخدام النموذج. يوفر Laravel أيضا إمكانية تخصيص استعلامات SQL دون المرور بـEloquent لمن يرغب في ذلك. ملف مرفق: عروض المشروع. ترجمة -وبتصرف- لمقال Laravel 5 Eloquent ORM لصاحبه Rodrick Kazembe.