<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Flask</title><link>https://academy.hsoub.com/programming/python/flask/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Flask</description><language>ar</language><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x623;&#x637;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; &#x641;&#x64A; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628;: &#x641;&#x644;&#x627;&#x633;&#x643; &#x646;&#x645;&#x648;&#x630;&#x62C;&#x627;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%81%D9%84%D8%A7%D8%B3%D9%83-%D9%86%D9%85%D9%88%D8%B0%D8%AC%D8%A7-r1547/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_05/626e31db7bb9e_-------.png.6b18dd3bf242ec3080bbda4828e9ecf4.png" /></p>
<p>
	سنغطي في هذا المقال من سلسلة <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">تعلم البرمجة</a> ما يلي:
</p>

<ul>
	<li>
		أساسيات أطر عمل الويب.
	</li>
	<li>
		استخدام إطار Flask في مثال Hello World.
	</li>
	<li>
		بناء برنامج دليل جهات الاتصال في تطبيق ويب.
	</li>
</ul>

<h2 id="أطر-عمل-الويب-web-frameworks">
	أطر عمل الويب Web Frameworks
</h2>

<p>
	تُعد البرامج التي تعتمد على الواجهة CGI التي تحدثنا عنها في <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1524/" rel="">المقال السابق</a> وسيلةً فعالةً لبناء مواقع ويب تفاعلية، إلا أن لها عدة مشاكل لا يمكن تجاهلها، لعل أخطرها بدء الخادم عمليةً جديدةً في كل طلب، مما يسبب بطءً واستهلاكًا للموارد، لذا لا يمكن استخدامها في التطبيقات ذات العمليات الكثيرة المتزامنة، والمشكلة الثانية وجود الشيفرة وتعليمات HTML والبيانات في ملف واحد، مما يصعّب عملية الصيانة ويعرّضها للأخطاء، فقد يتسبب تعديل بسيط في HTML بأخطاء تركيبية في شيفرة بايثون، وقد جُربت عدة أساليب مختلفة للتعامل مع هذه المشاكل، إلا أن الأسلوب الذي استمر والذي سننظر فيه هو <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل الويب web framework</a>، وأشهر هذه الأطر:
</p>

<ul>
	<li>
		صفحات خوادم مايكروسوفت النشطة Active Server Pages: واختصارًا ASP، يعمل هذا الإطار جنبًا إلى جنب مع خادم ويب مايكروسوفت IIS وبيئة "‎.NET" الخاصة بها، وهذا يعني إمكانية استخدام أي لغة مبنية على "‎".NET -بما في ذلك نسخة بايثون الخاصة بها- في إطار ASP.
	</li>
	<li>
		صفحات خوادم جافا Java Server Pages: واختصارًا JSP، هي إطار عمل جافا الخاص بتطوير الويب، و هي تقنية لتوليد تطبيقات الخوادم المصغرة Servlets، التي هي عمليات خفيفة تشبه برامج CGI، لكنها أسهل في التعامل معها.
	</li>
	<li>
		إطار عمل Ruby on Rails: يشبه إطار العمل <a href="https://wiki.hsoub.com/Rails" rel="external">ريلز rails</a> الخاص بلغة روبي إطار عمل Flask الخاص ببايثون، والذي سندرسه قريبًا.
	</li>
	<li>
		إطار عمل جانغو Django: يُعد جانغو أكثر أطر عمل بايثون شهرةً، خاصةً في بناء المواقع الكبيرة، وله شروحات كثيرة في كتب وتوثيقات إلكترونية، وهو غني بوحدات الإضافات plug-in modules المتاحة لتوسيعه، إلا أنه صعب التعلم موازنةً بإطار Flask.
	</li>
	<li>
		إطار العمل Flask: وهو ما سندرسه في هذا المقال، إذ يوفر جميع العناصر الأساسية الموجودة في أطر العمل، وهو سهل التعلم نسبيًا، ويمكن استخدامه ببساطة دون كثير من التعقيد الذي يشتت الانتباه عن الأفكار الرئيسية.
	</li>
</ul>

<p>
	تتمثل الفكرة الأساسية في جميع أطر عمل الويب في أنها تقلل الحمل على الخادم، باستخدام تقنيات البرمجة المتزامنة، والتي سندرسها في المقال التالي، كما تمقال المنطق logic عن شيفرة العرض presentation code، لتسهيل صيانة الموقع، حيث تسعى أحدث المعايير الصادرة عن w3c في كل من <a href="https://academy.hsoub.com/files/13-%D9%86%D8%AD%D9%88-%D9%81%D9%87%D9%85-%D8%A7%D9%94%D8%B9%D9%85%D9%82-%D9%84%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-html5/" rel="">HTML5</a> و CSS3 إلى تحقيق هذا المقال، إذ يجب أن تُستخدم <a href="https://wiki.hsoub.com/HTML" rel="external">HTML </a>حصرًا في هيكلة بناء المستند، بينما تُستخدم التنسيقات المورَّثة CSS للمظهر، من خطوط وألوان ومواضع وتحكم في رؤية العناصر أو إخفائها وغير ذلك، وبهذا تصبح برمجة الويب عملًا منظمًا يمكن صيانته، من خلال الجمع بين تلك الممارسات في كل من CSS وHTML مع أطر عمل الويب، وذلك من خلال تقنيتين رئيسيتين:
</p>

<ol start="">
	<li>
		توجيه نقطة النهاية endpoint routing للروابط، والتي يشار إليها أحيانًا بالربط mapping، حيث يوجَّه الجزء الأخير من الرابط من ملف إلى دالة أو تابع في إطار العمل.
	</li>
	<li>
		توفر قوالب المستندات طريقةً لإنشاء ملفات HTML ساكنة، فيها محددات للمواضع place-markers لإدراج البيانات فيها، ويمكن لدوال إطار عمل الويب أن تجهز البيانات ثم تمررها إلى محرك القالب، الذي يجلب القالب المناسب، ويدرج البيانات في محددات مواضعها لتوليد خرج HTML النهائي الذي يُعاد إلى متصفح المستخدم.
	</li>
</ol>

<p>
	سنرى استخدام كلا التقنيتين في Flask، ولأطر عمل الويب غالبًا نفس المفاهيم، رغم اختلاف تفاصيل بنائها اللغوي syntax، واصطلاحات الاستدعاء المتبعة.
</p>

<h2 id="تثبيت-flask">
	تثبيت Flask
</h2>

<p>
	لا يوجد إطار عمل Flask في مكتبة بايثون القياسية، لذا يجب تثبيته إما باستخدام أداة <code>pip</code> التي تأتي مع بايثون، أو استخدام حزمة تنفيذية خاصة، وهو ما يُنصح به مستخدمو لينكس، خاصةً عندما يُثبت على النظام أكثر من إصدار بايثون.
</p>

<p>
	عند استخدام <code>pip</code> نفتح طرفية النظام (وقد نضطر إلى تشغيل أمر <code>pip</code> بصلاحيات مدير النظام، خاصةً عند تثبيت بايثون لجميع المستخدمين على الحاسوب) ونكتب فيها ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_9" style=""><span class="pln">$ pip install flask</span></pre>

<p>
	يمكن التحقق منها بتشغيل بايثون، واستيراد Flask بالأمر <code>import flask</code>، فإذا لم نحصل على أخطاء نكون قد نجحنا.
</p>

<h2 id="استخدام-flask-في-مثال-hello-world">
	استخدام Flask في مثال Hello World
</h2>

<p>
	يوفر إطار عمل Flask وحدة خادم ويب بسيطةً، يمكن استخدامها للاختبار والتطوير قبل نقل الشيفرة إلى منصة استضافة ويب في شبكة تابعة لشركة أو على الإنترنت، وسندرس الآن كيفية تشغيله وتوفير صفحة ويب بسيطة.
</p>

<h3 id="صفحة-ويب-بسيطة">
	صفحة ويب بسيطة
</h3>

<p>
	لن نحتاج هنا إلى إنشاء ملف HTML كما فعلنا في حالة CGI في المقال السابق، بل سنعيد شيفرة HTML من دالة Flask، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_11" style=""><span class="pln">import flask

helloapp = flask.Flask(__name__)

@helloapp.route("/")
def index():
   return """
</span><span class="tag">&lt;html&gt;&lt;head&gt;&lt;title&gt;</span><span class="pln">Hello</span><span class="tag">&lt;/title&gt;&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;h1&gt;</span><span class="pln">Hello from Flask!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;&lt;/html&gt;</span><span class="pln">"""

if __name__ == "__main__":
    helloapp.run()</span></pre>

<p>
	يجب أن نشير هنا إلى بضعة أمور، حيث يُسند أول سطر بعد <code>import flask</code> نسخةً من كائن تطبيق <code>Flask</code> إلى متغير <code>helloapp</code>، وهو اسم عشوائي رغم أنه نفس اسم تطبيقنا، ثم نمرر المتغير الخاص <code>__name__</code>، الذي رأيناه في فصول سابقة، إلى التطبيق الذي يستخدمه ليعرّف الموقع الرئيسي (الجذر) لموقع الويب.
</p>

<p>
	أما الأمر التالي فهو الدالة التي تعالج طلب http GET، والتي تسمى <code>index</code> اصطلاحًا لتوافق تسمية ملف <code>index.htm</code>، غير أن المثير للاهتمام هنا هو المزخرِف <code>‎@helloapp.route("/")‎</code> الذي يسبقها، والذي يخبر إطار Flask أن أي طلب إلى جذر الموقع <code>/</code> يجب توجيهه إلى التابع التالي المسمى <code>index</code> في حالتنا هذه، ويمكن توجيه عدة نقاط نهاية end points إلى نفس التابع بتكديس المزخرفات decorators فوق بعضها البعض، وقد ذكرنا من قبل أن توجيه نقاط النهاية هو إحدى التقنيات المستخدمة في أطر عمل الويب، وهذه هي طريقة إطار عمل Flask لتوجيهها.
</p>

<h3 id="تشغيل-خادم-ويب-flask">
	تشغيل خادم ويب Flask
</h3>

<p>
	نبدأ تشغيل شيفرة Flask التي صارت جاهزةً الآن بالطريقة المعتادة، باستدعاء ما يلي من المجلد الذي يحوي التطبيق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_13" style=""><span class="pln">$ python hello.py</span></pre>

<p>
	ينبغي أن نرى رسالةً تخبرنا أن الخادم يعمل وينتظر الطلبات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_15" style=""><span class="pln"> * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)</span></pre>

<p>
	نستطيع الآن العودة إلى المتصفح لندخل العنوان الموجود في الرسالة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_19" style=""><span class="pln">http://127.0.0.1:5000/</span></pre>

<p>
	ستظهر رسالة "Welcome from Flask"، وبهذا نكون قد بنينا أول تطبيق ويب بإطار عمل Flask.
</p>

<h3 id="مقدمة-في-القوالب">
	مقدمة في القوالب
</h3>

<p>
	تتعامل شيفرة إطار Flask التي رأيناها حتى الآن مع مشاكل توسع التطبيقات، وزيادة حجمها، وبعض الفوضى التي تسببها برمجة CGI، إلا أنها لا تستطيع مقال الشيفرة عن HTML، فلا زلنا نكتب سلاسل HTML داخل شيفرة البرنامج، ولمعالجة تلك المشكلة نستخدم قوالب Flask.
</p>

<p>
	والقوالب في إطار Flask ما هي إلا ملفات HTML ساكنة فيها محددات markers أو مواضع خاصة لاستقبال البيانات من التطبيق، وهي تشبه سلاسل التنسيق format strings التي في بايثون، فمثلًا نريد قالبًا يستطيع استقبال رسالة الترحيب في سلسلة، ثم يدرجها في قالب، سيكون هذا القالب كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_17" style=""><span class="dec">&lt;!doctype  html&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;&lt;title&gt;</span><span class="pln">Hello from Flask</span><span class="tag">&lt;/title&gt;&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
   </span><span class="tag">&lt;h1&gt;</span><span class="pln">{{message}}</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	إذا نظرنا إلى <code>{{message}}</code> فسنجد المواضع التي ذكرناها، فتلك الأقواس المزدوجة هي مواضع استقبال البيانات، والمتغير <code>message</code> هو اسم المتغير الذي سيدخله محرك القالب إلى HTML.
</p>

<p>
	نحفظ المثال السابق في ملف باسم hello.htm داخل مجلد باسم <code>templates</code> في مجلد المشروع، واسم القالب مهم هنا لأنه المكان الذي يتوقع إطار Flask أن يجد فيه ملفات القوالب، يتبقى الآن بعض التعديلات على شيفرة بايثون الخاصة بنا لربطها بمحرك القوالب، وسنغير الشيفرة السابقة لتكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_24" style=""><span class="pln">from flask import Flask, render_template

helloapp = Flask(__name__)

@helloapp.route("/")
def index():
   return render_template("hello.htm", message="Hello again from Flask")

if __name__ == "__main__":
    helloapp.run()</span></pre>

<p>
	الاختلاف الأول في تعليمة <code>import</code>، حيث غيرنا النمط لنستطيع استيراد الأسماء التي نحتاجها مباشرةً.
</p>

<p>
	نلاحظ الآن اختفاء شيفرة HTML من ملف بايثون الخاص بنا، ونمرر الرسالة مثل سلسلة عادية إلى الدالة <code>render_template</code> مع اسم القالب، ونترك الباقي لإطار Flask، لكننا نريد أن نضمن مطابقة الوسائط المسماة في استدعاء هذه الدالة للأسماء التي في مواضع القالب، ثم نعرف كيف نقرأ البيانات الواردة من طلبات http لنستطيع تكرار نسخة CGI التي نفذناها من تطبيق "hello user".
</p>

<h2 id="استخدام-flask-في-مثال-hello-user">
	استخدام Flask في مثال Hello User
</h2>

<p>
	نريد الآن تعديل التطبيق ليعمل مع استمارة HTML التي استخدمناها من قبل، فنبدأ بتحويل HTML إلى قالب نرسله عند تحديد المستخدم لنقطة نهاية "hello"، ولا نحتاج إلى إضافة أية محددات خاصة إلى HTML لأننا لا ندرج أي بيانات، لكن يجب تغيير الخاصية <code>method</code> للاستمارة إلى <code>"POST"</code>، وكذلك الخاصية <code>action</code> لتعكس منفذ إطار Flask -الذي هو 5000- ونقطة النهاية المطلوبة للرابط، والتي هي <code>sayhello</code>، ثم نحفظ ذلك في مجلد <code>templates</code> باسم <code>helloform.htm</code> ليستطيع إطار Flask العثور عليه، وسيبدو بعد تلك التعديلات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_26" style=""><span class="dec">&lt;!doctype html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">Hello user page</span><span class="tag">&lt;/title&gt;</span><span class="pln">
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Hello, welcome to our website!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">8000
    </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"hello"</span><span class="pln"> 
          </span><span class="atn">method</span><span class="pun">=</span><span class="atv">"POST"</span><span class="pln"> 
          </span><span class="atn">action</span><span class="pun">=</span><span class="atv">"http://localhost:5000/sayhello"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;p&gt;</span><span class="pln">Please tell us your name:</span><span class="tag">&lt;/p&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"username"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"username"</span><span class="pln"> 
             </span><span class="atn">size</span><span class="pun">=</span><span class="atv">"30"</span><span class="pln"> </span><span class="atn">required</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Submit"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/form&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span></pre>

<h3 id="كتابة-شيفرة-flask">
	كتابة شيفرة Flask
</h3>

<p>
	نحتاج الآن لإضافة تابعين جديدين إلى تطبيقنا، يعرض الأول منهما قالب <code>helloform.htm</code>، بينما يرد الثاني على طلب إرسال الاستمارة، ونلاحظ أن الدالة الثانية ستستخدم قالب hello.htm الأصلي، ولم نضف شيئًا سوى كتابة سلسلة رسالة جديدة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_28" style=""><span class="pln">from flask import Flask, render_template, request

helloapp = Flask(__name__)

@helloapp.route("/")
def index():
   return render_template("hello.htm", message="Hello again from Flask")

@helloapp.route("/hello")
def hello():
   return render_template("helloform.htm")

@helloapp.route("/sayhello", methods=['POST'])
def sayhello():
   name=request.form['username']
   return render_template("hello.htm", message="Hello %s" % name)

if __name__ == "__main__":
    helloapp.run()</span></pre>

<p>
	لاحظ أننا اضطررنا إلى إضافة <code>request</code> إلى قائمة العناصر المستورَدة لأننا نستخدمه للوصول إلى بيانات طلب http، كما عدلنا مزخرف معالج <code>sayhello</code> ليشير إلى أنه يستطيع معالجة طلبات النوع POST -وقد كان الافتراضي طلبات GET- حيث نستخرج بيانات <code>username</code> داخل الدالة من الاستمارة، وندخلها في السلسلة التي نعيدها إلى قالب hello.htm. أما معالج <code>hello</code> فهو أبسط من ذلك، إذ يرسل قالب <code>helloform.htm</code> إلى المستخدم.
</p>

<p>
	إذا شغّلنا الشيفرة الآن فسيعمل الخادم، وإذا كتبنا العنوان التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_30" style=""><span class="pln">http://localhost:5000/hello</span></pre>

<p>
	فسنرى نفس الاستمارة التي كانت لدينا في مثال CGI من قبل (لاحظ أن كلمة <code>localhost</code> هي اسم بديل لـ 127.0.0.1، ويمكن تذكرها بسهولة أكثر)، فإذا ملأنا الاستمارة وضغطنا زر <code>Submit</code>؛ فستظهر لنا رسالة ترحيبية.
</p>

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

<h2 id="دليل-جهات-الاتصال">
	دليل جهات الاتصال
</h2>

<p>
	كتبنا في مقال <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/" rel="">العمل مع قواعد البيانات</a> في البرمجة تطبيقًا لدليل جهات اتصال يعمل من سطر الأوامر، وسنعيد استخدام قاعدة البيانات تلك لبناء نسخة ويب مبنية على إطار Flask، وسنضيف بعض عناصر برمجة الويب الأخرى أثناء ذلك، وسيكون تطبيق ويب بسيط رغم تلك العمليات التي سننفذها، غير أنه سيوفر أساسًا كافيًا لبناء تطبيقات ويب وفهم التوثيقات والتدريبات الأخرى.
</p>

<h3 id="إعداد-المشروع">
	إعداد المشروع
</h3>

<p>
	لمشاريع إطار Flask عادةً بنية محددة، فهي تأخذ صورة هرمية مجلد، حيث يكون اسم المشروع في الأعلى ، متبوعًا بمجلد <code>static</code> للملفات الساكنة مثل الصور وملفات CSS، ومجلد <code>templates</code> للقوالب، وحزمة بايثون اسمها في الغالب هو اسم المشروع، والتي هي مجلد يحوي ملفًا اسمه <code>‎__init__.py</code> يتحكم في ما تصدره الحزمة، كما تحتوي عادةً على ملف <code>setup.py</code> يُستخدم لتثبيت الحزمة إذا كانت موزَّعةً من فهرس حزم بايثون Python Package Index أو PyPI اختصارًا، وتسهل هذه الهرمية توزيع التطبيق باستخدام أدوات بايثون القياسية مثل <code>pip</code>.
</p>

<p>
	لكننا لن نوزع التطبيق في حالة دليل جهات الاتصال، لذا سنكتفي بترتيب بسيط مبني على المجلدات القياسية الثلاثة، إضافةً إلى مجلد رابع لملف قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_32" style=""><span class="pln">addressbook
    static
    templates
    db</span></pre>

<p>
	سننسخ ملف قاعدة البيانات من المقال السابق إلى مجلد db هنا.
</p>

<h3 id="إنشاء-قالب-html">
	إنشاء قالب HTML
</h3>

<p>
	سيكون لدينا صفحة ويب واحدة تتكون من استمارة بسيطة لإدخال البيانات، فيها ثلاثة أزرار هي <code>Create</code> و<code>Find</code> و<code>List all</code>، حيث سيستخدم زر <code>Create</code> البيانات التي في الاستمارة لإضافة مدخل جديد إلى قاعدة البيانات، ويعرض زر <code>Find</code> قائمةً بجميع العناوين المطابقة للبيانات التي في الاستمارة، بينما يعرض زر <code>List all</code> القائمة الكاملة للعناوين.
</p>

<p>
	سنستخدم مزيةً جديدةً لمحرك القوالب، وهي القدرة على تكرار صفوف HTML وفقًا لمجموعة بيانات الدخل، وسيُدمج هذا مع عنصر HTML جديد هو وسم الجدول <code>&lt;table&gt;</code> وعائلته التي سنستخدمها لعرض قائمة العناوين.
</p>

<p>
	وسيبدو القالب كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_34" style=""><span class="dec">&lt;!doctype html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">Flask Address Book</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width, initial-scale=1"</span><span class="tag">&gt;</span><span class="pln">
 
    </span><span class="tag">&lt;style&gt;</span><span class="pln">
      h1 </span><span class="pun">{</span><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;}</span><span class="pln">
      label </span><span class="pun">{</span><span class="pln">
         width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20em</span><span class="pun">;</span><span class="pln"> 
         text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln"> 
         margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln"> 
         margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2em</span><span class="pun">;</span><span class="pln"> 
         </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;}</span><span class="pln">
      input </span><span class="pun">{</span><span class="pln">
         margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln"> 
         </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln"> 
         width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12em</span><span class="pun">;}</span><span class="pln">
      input</span><span class="pun">.</span><span class="pln">button </span><span class="pun">{</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6em</span><span class="pun">;</span><span class="pln"> text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;}</span><span class="pln">
      br </span><span class="pun">{</span><span class="pln">clear</span><span class="pun">:</span><span class="pln"> all</span><span class="pun">;}</span><span class="pln">
      div</span><span class="pun">.</span><span class="pln">buttons </span><span class="pun">{</span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln"> width</span><span class="pun">:</span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;}</span><span class="pln">
    </span><span class="tag">&lt;/style&gt;</span><span class="pln">
    
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
 
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;header&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Address Book Website</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;/header&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"hello"</span><span class="pln"> 
            </span><span class="atn">method</span><span class="pun">=</span><span class="atv">"POST"</span><span class="pln"> 
            </span><span class="atn">action</span><span class="pun">=</span><span class="atv">"http://localhost:5000/display"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;fieldset&gt;&lt;legend&gt;</span><span class="pln">Address</span><span class="tag">&lt;/legend&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">First name:
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"First"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"First"</span><span class="pln">
                </span><span class="atn">required</span><span class="pln"> </span><span class="atn">autofocus</span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">Second Name:
               </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"Last"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Last"</span><span class="pln">
                      </span><span class="atn">required</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">House Number:
                   </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"House"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"House"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">Street:
                   </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"Street"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Street"</span><span class="pln">
                          </span><span class="atn">required</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">District:
                   </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"District"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"District"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">Town:
               </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"Town"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Town"</span><span class="pln">
                      </span><span class="atn">required</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">Postcode:
               </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"Postcode"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Postcode"</span><span class="pln">
                      </span><span class="atn">required</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">Phone:
               </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"Phone"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Phone"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/label&gt;</span><span class="pln">
      </span><span class="tag">&lt;/fieldset&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"buttons"</span><span class="tag">&gt;</span><span class="pln">
           </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"List All"</span><span class="pln">  </span><span class="tag">/&gt;</span><span class="pln">
           </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Filter"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Filter"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
           </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Add"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Add"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
           </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"reset"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Clear"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/form&gt;</span><span class="pln">
      </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"data"</span><span class="tag">&gt;</span><span class="pln">
         </span><span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"addresses"</span><span class="tag">&gt;</span><span class="pln">
         </span><span class="tag">&lt;tr&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">First</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">Second</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">House#</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">Street</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">District</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">Town</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">Postcode</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;th&gt;</span><span class="pln">Phone</span><span class="tag">&lt;/th&gt;</span><span class="pln">
         </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
         {% for row in book %}
         </span><span class="tag">&lt;tr&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.First}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.Last}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.House}}</span><span class="tag">&lt;/td&gt;</span><span class="pln"> 
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.Street}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.District}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.Town}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.PostCode}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
            </span><span class="tag">&lt;td&gt;</span><span class="pln">{{row.Phone}}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
         </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
         {% endfor %}
         </span><span class="tag">&lt;/table&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">

  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	يوجد عدد كبير من العناصر الجديدة هنا، بما في ذلك قسم <code>&lt;style&gt;</code> الذي يتحكم في تخطيط الاستمارة، ويمكن الرجوع إلى أي شرح للغة CSS -مثل <a href="https://wiki.hsoub.com/CSS" rel="external">توثيق CSS في موسوعة حسوب</a>- لمعرفة ما تفعله الشيفرة هنا إذ لا يتسع المقام لشرحها بسبب بعدها عن الغرض من المقال.
</p>

<p>
	كما توجد بعض مزايا HTML الجديدة:
</p>

<ul>
	<li>
		يوضع ترميز المحارف في وسم <code>meta</code> داخل وسم <code>head</code>، وتجب إضافة هذا الوسم في صفحات الويب الحديثة خاصةً إذا كنا نستخدم محارف غير قياسية، وإلا فسيكون لدينا في الصفحة أجزاء غير قابلة للقراءة.
	</li>
	<li>
		الوسم <code>meta</code> هو منفذ للعرض viewport، وهو مصمم لتحسين عرض الصفحة على الأجهزة المحمولة، ويُفضل إضافة هذا الوسم إلى الصفحة.
	</li>
	<li>
		استخدمنا عددًا من وسوم <code>div</code>، وهي مجرد أدوات تنظيمية لا تظهر على الشاشة إلا إذا تعمدنا إظهارها باستخدام CSS، وهي تشبه ودجات <code>Frame</code> التي استخدمناها في <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1378/" rel="">برامج Tkinter الرسومية</a>، وتفيدنا في التحكم في نطاق الأوامر لكل من CSS وجافاسكربت.
	</li>
	<li>
		تحتوي الاستمارة <code>form</code> على ثلاثة عناصر جديدة، يساهم كل منها في تحسين مظهرها، هي العنصر <code>fieldset</code> الذي يجمع عدة حقول داخل إطار مرئي يُدرج فيه العنصر <code>legend</code>، والعنصر <code>label</code> الذي يغلف حقول <code>input</code> ليجعلها معًا على الشاشة.
	</li>
	<li>
		نختم الاستمارة بثلاثة أزرار من النوع <code>submit</code> لها الخاصية <code>name</code> التي تُرسَل إلى الخادم، ونستطيع استخدام تلك البيانات لتحديد الدالة التي يجب تنفيذها، أما الزر الأخير فيكون من النوع <code>reset</code>، وهو يمسح حقول الاستمارة ولا يرسل شيئًا إلى الخادم.
	</li>
	<li>
		قسم <code>&lt;table&gt;</code> الذي يبدأ بصف من الترويسات <code>&lt;th&gt;</code> و<code>&lt;tr&gt;</code>.
	</li>
	<li>
		يوفر الجزء التالي ميزةً جديدةً لمحرك القوالب، وهي القدرة على تنفيذ حلقات تكرارية واستبدال عدة أجزاء من البيانات، وهي الحقول التي في كل صف في حالتنا، وتُحدَّد بنى التحكم هذه بمحارف <code>{%...%}</code>، ويدعم المحرك عدة بنىً مختلفة إضافةً إلى الحلقة الموضحة هنا.
	</li>
</ul>

<h3 id="كتابة-شيفرة-إطار-flask">
	كتابة شيفرة إطار Flask
</h3>

<p>
	لا نحتاج إلى إضافة الكثير من الشيفرات الجديدة في هذا المشروع، فعناصر إطار Flask مجرد توسيع طفيف من المثال السابق لتحديد أي زر من أزرار <code>submit</code> الثلاثة قد ضُغط، وبمجرد أن ننفذ ذلك نستدعي دوال بايثون العادية التي تعدل قاعدة البيانات باستخدام وحدة <code>sqlite3</code> كما شرحنا في <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/" rel="">مقال قواعد البيانات</a>، وتعيد تلك الدوال قائمةً من عناصر القواميس، بمقدار عنصر واحد لكل صف في قاعدة البيانات، وتمرَّر تلك القائمة إلى محرك عرض القوالب template rendering engine الذي ينفذ مهمة إدخال HTML إلى الصفحة التي أنشئت، وستبدو الشيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5929_36" style=""><span class="pln">from flask import Flask, render_template, request, g
import sqlite3, os

addBook = Flask(__name__)
addBook.config.update(dict(
   DATABASE=os.path.join(addBook.root_path,'static','address.db'),
   ))

@addBook.route("/")
def index():
   data = findAddresses()
   return render_template("address.htm", book=data)

@addBook.route("/display", methods=['POST'])
def handleForm():
   if 'Filter' in request.form:
      query= buildQueryString(request.form)
      return render_template('address.htm', book=findAddresses(query))
   elif 'Add' in request.form:
      addAddress(request.form)  # add a new entry
   return render_template("address.htm", book=findAddresses())

# Note: flask.g is the "global context" object
# that lives for the life of the application.
def get_db():
    if not hasattr(g, 'sqlite_db'):
       try:
          file = addBook.config['DATABASE']
          db = sqlite3.connect(file)
          db.row_factory = sqlite3.Row  # return dicts instead of tuples
       except: print("failed to initialise sqlite")
       g.sqlite_db = db
    return g.sqlite_db

@addBook.teardown_appcontext
def close_db(error):
    if hasattr(g, 'sqlite_db'):
         db = g.sqlite_db
         db.commit()
         db.close
                    
def buildQueryString(aForm):
    base = "WHERE"
    test = " %s LIKE '%s' "
    fltr = ''

    for name in ('First','Last',
                 'House','Street',
                 'District','Town',
                 'PostCode','Phone'):
       field = aForm.get(name, '')
       if field:
           if not fltr:  fltr = base + test % (name, field)
           else: fltr = fltr + ' AND ' + test % (name, field)
    return fltr 

def findAddresses(filter=None):
    base = """
SELECT First,Last,House,Street,District,Town,PostCode,Phone
FROM address %s
ORDER BY First;"""

    db = get_db()
    if not filter: filter = ""  # empty -&gt; get all
    query = base % filter
    cursor = db.execute(query)
    data = cursor.fetchall()
    return data

def addAddress(aForm):
    db = get_db()
    cursor = db.cursor()
    
    first   = aForm.get('First','')
    last    = aForm.get('Last','')
    house   = aForm.get('House','')
    street  = aForm.get('Street','')
    district= aForm.get('District','')
    town    = aForm.get('Town','')
    code    = aForm.get('PostCode','')
    phone   = aForm.get('Phone','')

    query = '''INSERT INTO Address 
               (First,Last,House,Street,District,Town,PostCode,Phone)
               Values ("%s","%s","%s","%s","%s","%s","%s","%s;");''' %\
               (first, last, house, street, district, town, code, phone)
    cursor.execute(query)
   
if __name__ == "__main__":
   addBook.run()</span></pre>

<p>
	نلاحظ بعض النقاط المهمة هنا:
</p>

<ul>
	<li>
		نستورد الاسم <code>g</code> من إطار Flask، وهو كائن خاص يوفره Flask ليحمل قيم مستويات التطبيق، ونستفيد من المبدأ الذي يقوم عليه، رغم غرابة اسمه، وهو يشبه المعامِل <code>self</code> في البرمجة الكائنية لكنه ينطبق هنا على تعاملات الويب بدلًا من الكائن.
	</li>
	<li>
		نعِدّ موقع قاعدة البيانات في البنية الخاصة <code>addbook.config</code>، وهناك عدة عناصر أخرى يجب إعدادها هنا في الموقع الكامل، بما في ذلك اسم المستخدم وكلمة المرور للمدير admin، وتخزَّن هذه الأمور عادةً في ملف config، ويُستخدم أمر خاص لتحميلها. كما يجب الانتباه إلى خيار <code>DEBUG</code> الذي يؤدي لطبع معلومات كثيرة إلى الطرفية عند ضبطه على القيمة <code>True</code>، لأن هذه المعلومات مفيدة للغاية في حال حدوث المشاكل أثناء التطوير.
	</li>
	<li>
		تتحقق الدالة <code>get_db</code> من كون الخاصية <code>sqlite_db</code> مضبوطةً أو لا قبل أن تضبطها، وهذا يضمن وجود اتصال واحد فقط لقاعدة البيانات.
	</li>
	<li>
		كما تضبط هذه الدالة <code>row_factory</code> من <code>sqlite3.Row</code>، وفائدته أنه يجعل Sqlite تعيد قائمةً من كائنات <code>Row</code> بدلًا من صفوف tuple تحتوي على قيم، وتُعامَل كائنات <code>Row</code> تلك على أنها قواميس، وهو ما يبحث عنه Flask تحديدًا في محرك القوالب الخاص به، لذا يوفر سطر الشيفرة ذاك علينا كثيرًا من تنسيق البيانات.
	</li>
	<li>
		ينبغي أن توجد معالجات أخطاء <code>try/except</code> حول الكثير من التعليمات البرمجية، خاصةً أقسام قواعد البيانات، لكننا لم نشأ الإطالة أكثر من اللازم، وسنرى مثالًا في دالة <code>get_db</code> يوضح أننا نستطيع استخدام تعليمات <code>print</code> لعرض خرج التنقيح debug output في الطرفية.
	</li>
	<li>
		يُستخدم هنا مزخرِف جديد هو <code>‎@addBook.teardown_appcontext</code> لرفع راية إلى إطار Flask بأنه يجب تشغيل الدالة <code>close_db</code> عند إغلاق التطبيق.
	</li>
	<li>
		تساعد الدالة <code>buildQueryString</code> في بناء شرط <code>WHERE</code> الخاص باستعلامنا ديناميكيًا، وقد تبدو معقدةً إلا أنها مجرد تعديل بسيط على سلسلة نصية، ويسمح لنا هذا الأسلوب باستخدام دالة واحدة لإيجاد جميع العناوين عند عدم استخدام مرشحات filters، أو العناوين المطلوبة فقط.
	</li>
	<li>
		تكون عمليات البحث أكثر مرونةً باستخدام عامل <code>LIKE</code> الخاص بـ SQL، بدلًا من اختبار التكافؤ equality test، بما في ذلك القدرة على استخدام علامة <code>%</code> محرف بدل في SQL.
	</li>
	<li>
		نستخدم تابع القاموس <code>get</code> لجلب القيم من الاستمارة، وهذا يضمن حصولنا على قيمة افتراضية عند عدم وجود المفتاح لسبب ما، وهي سلسلة فارغة في حالتنا.
	</li>
</ul>

<h3 id="تشغيل-دليل-جهات-الاتصال">
	تشغيل دليل جهات الاتصال
</h3>

<p>
	سنغير مجلد التطبيق ونشغل الملف address.py، ثم نستخدم المتصفح لزيارة <code>localhost:5000</code>، وبهذا تطابق عملية التشغيل هذه عملية التشغيل السابقة، ويجب أن نرى نفس الأسماء والعناوين التي أنشأناها في مقال قواعد البيانات في المتصفح.
</p>

<p>
	كما ينبغي أن نستطيع الآن إدخال القيم في الاستمارة، وترشيح النتائج لمطابقة كلمات البحث -نستخدم <code>%</code> محرف بدل wildcard- وكذلك نستطيع إضافة إدخالات جديدة، وبما أنه لا يوجد تحقق من الحقول أو الاستمارة فيجب أن نراعي إدخال قيم منطقية مناسبة، أو نتلافى أي أخطاء يدويًا باستخدام محث <code>sqlite3</code>.
</p>

<p>
	ينبغي أن يقدم هذا المقال فكرةً عن متطلبات إنشاء تطبيق ويب، وهناك المزيد لتعلمه بما في ذلك تقنيات برمجة المتصفحات، وأمور الأمان في جانب الخادم، وملفات تعريف الارتباط cookies، وإطلاق الموقع الحي في صورته النهائية على الإنترنت، وكل هذا خارج عن سياق شرحنا، لذا يُرجع فيه إلى <a href="https://academy.hsoub.com/learn/python-application-development/" rel="">تطوير التطبيقات باستخدام لغة Python من أكاديمية حسوب</a>، أو <a href="https://academy.hsoub.com/learn/php-web-application-development/" rel="">دورة تطبيقات الويب باستخدام PHP</a>، وغيرها من مقالات البرمجة والكتب البرمجية في الأكاديمية كما توفر شركات استضافة الويب توثيقات ممقالةً عن تحقيق الاستفادة القصوى من المواقع التي ننشئها.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	نأمل في نهاية هذا المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		تحسّن أطر عمل الويب إمكانية توسيع المواقع وصيانتها.
	</li>
	<li>
		توجه أطر عمل الويب نقاط النهاية إلى الدوال.
	</li>
	<li>
		توجد عدة إطارات عمل للويب في السوق الآن.
	</li>
	<li>
		إطار Flask يمثل حلًا وسطًا بين البساطة والإمكانيات.
	</li>
	<li>
		يستخدم Flask مزخرفات decorators لتوجيه نقاط النهاية.
	</li>
	<li>
		كما يستخدم نظام قوالب لتمرير البيانات إلى صفحات الويب.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutflask.htm" rel="external nofollow">للمقال الحادي والثلاثين: Using Web Apllication Frameworks</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-%D9%88%D9%81%D8%A7%D8%A6%D8%AF%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-r1548/" rel="">البرمجة المتزامنة وفائدتها في برمجة التطبيقات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1524/" rel="">كيفية كتابة تطبيقات الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1523/" rel="">برمجة عملاء ويب باستخدام بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1524/" rel="">كيفية كتابة تطبيقات الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1522/" rel="">كيفية التعامل مع الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/networking/%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-r603/" rel="">تواصل البرامج والعمليات البرمجية عبر الشبكة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1547</guid><pubDate>Tue, 03 May 2022 08:09:00 +0000</pubDate></item><item><title>&#x62A;&#x642;&#x633;&#x64A;&#x645; &#x627;&#x644;&#x633;&#x62C;&#x644;&#x627;&#x62A; &#x625;&#x644;&#x649; &#x635;&#x641;&#x62D;&#x627;&#x62A;  Pagination &#x641;&#x64A; Flask-SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D9%82%D8%B3%D9%8A%D9%85-%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D8%A5%D9%84%D9%89-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-pagination-%D9%81%D9%8A-flask-sqlalchemy-r831/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/29.jpg.f9af82ffd1f0901c5212b8f95e120c52.jpg" /></p>

<p>
	إن كانت لدينا آلاف المقالات فلا يُمكننا أن نعرضها جميعها في الصّفحة الرّئيسية، ولو كانت تحتوي على آلاف الصّور ومقاطع الفيديو فمن المؤكّد بأنّ الصّفحة ستأخذ عدّة دقائق لتنهي التّحميل، والحل الشّائع حاليّا في تطبيقات الويب هو تجميع عدد محدّد من السّجلات في كل صفحة، مثلا خمسة سجلّات في الصّفحة الأولى وخمسة أخرى في الصّفحة الثّانيّة، وهكذا… بهذه الطّريقة يُمكنك عرض شريط أسفل الصّفحة لتوفير طريقة للمُستخدم للتنقل بين الصّفحات، كذلك يُمكنك استعمال لغة جافا سكربت لوضع زر لتحميل المزيد من المقالات كما هو شائع في الكثير من المواقع على الانترنت.
</p>

<h2>
	كيف تعمل خاصية الصفحات في Flask-SQLAlchemy
</h2>

<p>
	قبل أن ننتقل إلى كيفيّة تقسيم الصّفحات إلى سجلّات لا بد أن تعرف المبدأ الرّئيسي للعمل، بدءًا من معنى كلمة Pagination (تحويل مجموعة من السّجلات إلى صفحات مُرقّمة، كل صفحة تحمل عددا مُعيّنا من السّجلات، والعدد الذي تُحدّده لكل صفحة يكون ثابتا إلى آخر مجموعة من السّجلات). فمثلا لنفترض بأنّ الأسماء التّاليّة مُسجلة لدينا في قاعدة البيانات:
</p>

<ul>
<li>
		1 عمر
	</li>
	<li>
		2 عبد الرّحمن
	</li>
	<li>
		3 خالد
	</li>
	<li>
		4 يوسف
	</li>
	<li>
		5 أحمد
	</li>
	<li>
		6 إبراهيم
	</li>
	<li>
		7 كمال
	</li>
	<li>
		8 كريم
	</li>
	<li>
		9 مُعاذ
	</li>
	<li>
		10 جواد
	</li>
</ul>
<p>
	لنُقسّمها إلى صفحات مُرقّمة، كل صفحة ستحتوي على 3 أسماء أو أقل:
</p>

<p>
	الصّفحة 1:
</p>

<ul>
<li>
		1 عمر
	</li>
	<li>
		2 عبد الرّحمن
	</li>
	<li>
		3 خالد
	</li>
</ul>
<p>
	الصّفحة 2:
</p>

<ul>
<li>
		4 يوسف
	</li>
	<li>
		5 أحمد
	</li>
	<li>
		6 إبراهيم
	</li>
</ul>
<p>
	الصّفحة 3:
</p>

<ul>
<li>
		7 كمال
	</li>
	<li>
		8 كريم
	</li>
	<li>
		9 مُعاذ
	</li>
</ul>
<p>
	الصّفحة 4:
</p>

<ul>
<li>
		10 جواد
	</li>
</ul>
<p>
	بهذه الطّريقة، عندما تطلب من قاعدة البيانات السّجلات المُتواجدة في الصّفحة رقم 1، ستحصل على الأسماء: عمر، عبد الرّحمن، خالد. وإن طلبت السّجلات في الصّفحة رقم 4 فستحصل على الاسم "جواد"، وهكذا ستتمكّن من تقسيم السّجلات المُتواجدة في قاعدة البيانات لتفادي الاستعلام عنها كلّها في مرّة واحدة ومن ثم تقسيمها بنفسك باستعمال لغة Python، وهذا يكون بطيئا جدّا إذا ما كانت لديك الكثير من السّجلات في قاعدة البيانات، وعوضا عن الحصول عليها جميعا في مرّة واحدة، تطلب سجلّات صفحة واحدة فقط.
</p>

<p>
	إذا كنت تستخدم كلّا من مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy للتّعامل مع قاعدة البيانات فيُمكنك استعمال خاصيّة تجميع عدد من السّجلات في عدد من الصّفحات عبر استعمال التّابع <code>paginate</code> الذي يأخذ مُعاملين أساسيّين، المُعامل <code>page</code> والذي سيُعبّر عن رقم الصّفحة، والمُعامل <code>per_page</code> الذي سيُعبّر عن عدد السّجلات التّي تتواجد بكل صفحة، وكمثال على هذين المعاملين، فقيمة <code>per_page</code> في مثال الأسماء سابقا هي 3 وكلّما غيّرت قيمة المُعامل <code>page</code> من 1 إلى 4 ستحصل على الأسماء المتواجدة بكل صفحة حسب رقم الصّفحة.
</p>

<p>
	السّطر التّالي مثال بسيط على كيفيّة استخدام التّابع <code>paginate</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_7" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pagination </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln">per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pagination
</span><span class="pun">&lt;</span><span class="pln">flask_sqlalchemy</span><span class="pun">.</span><span class="typ">Pagination</span><span class="pln"> object at </span><span class="lit">0x7f0b4a3cc910</span><span class="pun">&gt;</span></pre>

<p>
	ستُلاحظ بعد تنفيذك للأسطر السّابقة، أنّ المُتغيّر <code>pagination</code> عبارة عن كائن من الصّنف <code>Pagination</code> وليس عبارة عن قائمة سجلّات تُمثّل المقالات، ذلك أن SQLAlchemy توفّر لنا العديد من الخصائص والتّوابع التّي يُمكننا استخدامها مع أي كائن من الصّنف <code>Pagination</code>، فيُمكنك مثلا أن تتحقّق من أنّ الصّفحة الحاليّة هي آخر صفحة أو العكس أو أن تحصل على عدد الصّفحات الإجمالي والعديد من التّوابع والخصائص الأخرى التّي سنتطرّق إليها والتّي ستُساعدك حتما عندما ترغب في العمل مع صفحات مُتعدّدة أو استخدام تنسيقات مُحدّدة حسب شروط مُعيّنة.
</p>

<p>
	سنُغطّي في الفقرات التّاليّة بعضا من أهم الأمور التّي يُمكنك القيام بها مع خاصيّة ترقيم الصّفحات لتُقدّم لمُستخدمي تطبيقك أفضل تجربة استخدام مُمكنة.
</p>

<h1>
	الوصول إلى السجلات الموجودة بالصفحة
</h1>

<p>
	نفّذنا الأسطر التّالية قبل قليل لنحصل على كائن باسم <code>pagination</code> من الصّنف <code>Pagination</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_9" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> pagination </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span></pre>

<p>
	ولكن الأهم أن نحصل على المقالات المُتواجدة في الصّفحة كي نتمكّن من عرض عنوان كل مقال ومحتواه أو مُعالجة بيانات كل مقال على حدة. وللوصول إلى السّجلات المُتواجدة بالصّفحة، أضف خاصيّة <code>items</code> للكائن <code>pagination</code>، وبالتّالي ستتمكّن من الدّوران حول المقالات الثّلاثة بحلقة <code>for</code> بسيطة ومنه ستتمكّن من الوصول إلى عنوان كل مقال ومُحواه وكاتبه وما إلى ذلك (تماما كما تتعامل مع المقالات التّي تحصل عليها عن طريق <code>()query.all</code> أو أي استعلام مُشابه).
</p>

<p>
	والمثال التّالي يوضح هذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_11" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts </span><span class="pun">=</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">items

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span></pre>

<p>
	كما ترى فقد تمكّنّا من الوصول إلى قائمة المقالات المُتواجدة في الصّفحة الأولى، ويُمكنك الآن التّعامل مع المُتغيّر <code>posts</code> كما تتعامل مع أي مُتغيّر آخر يُمثّل قائمة سجلّات في قاعدة البيانات.
</p>

<h2>
	الانتقال إلى الصفحة التاليّة
</h2>

<p>
	بعد أن تعرّفنا على كيفيّة الوصول إلى الصّفحة الأولى وعناصر الصّفحة، حان الوقت للانتقال إلى الصّفحة التّاليّة والوصول إلى عناصرها.
</p>

<p>
	للوصول إلى الصّفحة التّاليّة، كل ما عليك القيام به هو إضافة التّابع <code>next</code> إلى مُتغيّر الصّفحة الحاليّة والذي يجب أن يكون كائنا من الصّنف <code>Pagination</code>، انظر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_13" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2 </span><span class="pun">=</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">next</span><span class="pun">()</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> other content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user4 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">&gt;]</span></pre>

<p>
	في المثال السابق: نصل أولًا إلى الصّفحة الأولى ثم نسند القيمة إلى المُتغيّر <code>page_1</code> وبعدها نطلع على عناصر الصّفحة للتأكّد، بعدها تأتي الفكرة الأساسيّة إذ نُنشئ مُتغيّرا جديدا <code>page_2</code> بحيث نستخدم المُتغيّر <code>page_1</code> مع التّابع <code>next</code> للحصول على الصّفحة الثّانيّة، وبعدها ننظر إلى عناصر الصّفحة.
</p>

<h2>
	الصفحة السابقة
</h2>

<p>
	تتشابه طريقة الوصول إلى الصّفحة السّابقة مع طريقة الوصول إلى الصّفحة التالية، فقط استعمل التّابع <code>prev</code> عوضا عن التّابع <code>next</code>، انظر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_15" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> other content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user4 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">&gt;]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">prev</span><span class="pun">()</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span></pre>

<p>
	نستعمل التّابع <code>paginate</code> أولا مع تمرير القيمة <code>2</code> إلى المُعامل <code>page</code> للحصول على الصّفحة الثّانيّة، ومن ثمّ نقوم بإنشاء مُتغيّر باسم <code>page_1</code> بالقيمة <code>()page_2.prev</code> (أي الصّفحة التّي تسبق الصّفحة الثّانيّة)، وهكذا نصل إلى الصّفحة الأولى مرة أخرى.
</p>

<h2>
	التحقق من وجود صفحة تالية للصفحة الحالية
</h2>

<p>
	قد ترغب أحيانا بمعرفة ما إذا كانت هذه الصّفحة التّي تتعامل معها هي الأخيرة أم لا، وتستطيع ذلك عن طريق الخاصيّة <code>has_next</code> التّي تُرجع إمّا القيمة المنطقيّة <code>True</code> أو القيمة <code>False</code>، بحيث يكون الشرط صحيحًا إذا كانت للصّفحة صفحة مُواليّة والعكس إذا كانت آخر صفحة. مثال على الحالة الأولى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_17" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">has_next
</span><span class="kwd">True</span></pre>

<p>
	كما تُلاحظ، فالصّفحة الأولى ليست آخر صفحة لأنّ عدد المقالات يتجاوز 3 مقالات، وعليه فالخاصيّة <code>has_next</code> تُرجع القيمة المنطقيّة <code>True</code>، وهذا يعني بأنّ القيمة كانت لتكون <code>False</code> لو كانت عدد المقالات المُتواجدة بقاعدة البيانات ثلاثة أو أقل من ذلك. مثال على الحالة الثّانيّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_19" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_5 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_5</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">New</span><span class="pln"> title </span><span class="kwd">for</span><span class="pln"> post </span><span class="kwd">from</span><span class="pln"> user8 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">&gt;]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_5</span><span class="pun">.</span><span class="pln">has_next
</span><span class="kwd">False</span></pre>

<p>
	في هذه الحالة تكون الصّفحة الخامسة هي آخر صفحة وليس بعدها أية صفحة أخرى، حتى أنّ بها مقالا واحدا فقط، وبالتّالي فالنّتيجة هي القيمة <code>False</code> عند استعمالنا للخاصيّة <code>has_next</code>.
</p>

<h2>
	التحقق من أن للصفحة الحالية صفحة تسبقها
</h2>

<p>
	بما أنّ هناك طريقة لمعرفة ما إذا كانت للصّفحة الحاليّة صفحة أخرى بعدها، فلا بد أن تكون هناك طريقة للتّعرف على عكس ذلك، أي معرفة ما إذا كانت هذه الصّفحة أول صفحة بحيث لا صفحة تسبقها أم لا. ولمعرفة ما إذا كانت لهذه الصّفحة الحاليّة صفحة أخرى تسبقها يُمكنك استعمال الخاصيّة <code>has_prev</code>، انظر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_21" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">items
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">has_prev
</span><span class="kwd">False</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">has_next
</span><span class="kwd">True</span></pre>

<p>
	نحصل هنا على الصّفحة الأولى ونتحقّق من أنّ لها صفحة تسبقها، والنّتيجة هي القيمة <code>False</code> كما هو مُتوقّع، بعدها نقوم بالتّحقق ممّا إذا كانت للصّفحة صفحة تالية بعدها، والنّتيجة مُتوقّعة كذلك. لنجمع الآن كلّا من التّابع <code>next</code> والخاصيّة <code>has_prev</code> ونرى النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_23" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">next</span><span class="pun">().</span><span class="pln">has_prev
</span><span class="kwd">True</span></pre>

<p>
	النّتيجة هي القيمة <code>True</code> لأنّ قيمة ()<code>page_1.next</code> هي الصّفحة الثّانيّة، ومن المُؤكّد بأنّ للصّفحة الثّانيّة صفحة تسبقها.
</p>

<h2>
	عدد الصفحات وكيفية الدوران حول قائمة الصفحات
</h2>

<p>
	للوصول إلى عدد الصّفحات الكليّ عند استخدام التّابع <code>paginate</code>، أضف الخاصيّة <code>pages</code> إلى الكائن، وسيعمل مهما كانت الصّفحة الحاليّة. مثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_25" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">pages
</span><span class="lit">5</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_3</span><span class="pun">.</span><span class="pln">pages
</span><span class="lit">5</span></pre>

<p>
	في المثال أعلاه، نستورد الصّنف <code>Post</code> أولًا كالعادة ونحصل على الصّفحة الأولى ونُسند قيمتها إلى المُتغيّر <code>page_1</code>، وبعدها نستعمل الخاصيّة <code>pages</code> للتّعرف على العدد الإجماليّ للصّفحات الذي هو خمسة، وبعدها نقوم بنفس الشّيء مع الصّفحة الثّالثة، وذلك فقط لتوضيح أنّك تستطيع الحصول على العدد الإجمالي للصّفحات بغض النّظر عن الصّفحة التّي أنت فيها.
</p>

<h2>
	الدوران حول قائمة أرقام الصفحات
</h2>

<p>
	قد ترغب أحيانًا في الوصول إلى رقم كل صفحة على حدة، وأغلب الظّن أنّك تعمل على شريط لتمكين المُستخدم من الانتقال بين الصّفحات دون ترتيب مُحدّد (الانتقال من الصّفحة الثّالثة إلى الخامسة على سبيل المثال). يُمكنك استخدام التّابع <code>iter_pages</code> للحصول على كائن مُولّد (generator) والذي يسمح لك بالوصول إلى كل رقم على حدة، ويُمكنك التّعامل معه باستخدام حلقة <code>for</code> كما تتعامل مع قوائم python عاديّة، ويُمكنك كذلك الحصول على قائمة عبر استخدام الدّالة <code>list</code> لكنّ الأمر ليس ضروريا. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_27" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">iter_pages</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">generator object iter_pages at </span><span class="lit">0x7f4d96115230</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> page </span><span class="kwd">in</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">iter_pages</span><span class="pun">():</span><span class="pln">
</span><span class="pun">...</span><span class="pln">     </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">page</span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln"> 
</span><span class="lit">1</span><span class="pln">
</span><span class="lit">2</span><span class="pln">
</span><span class="lit">3</span><span class="pln">
</span><span class="lit">4</span><span class="pln">
</span><span class="lit">5</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">page_1</span><span class="pun">.</span><span class="pln">iter_pages</span><span class="pun">())</span><span class="pln">
</span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span></pre>

<p>
	عندما طبّقنا التّابع <code>()iter_pages</code> على المُتغيّر <code>page_1</code> حصلنا على معلومة بسيطة تُشير إلى أنّ هذا الكائن من النّوع <code>generator</code>، أي أنّه يُولّد كل عنصر عندما تحتاج إليه فقط، وكما تُلاحظ، فعندما استخدمنا حلقة <code>for</code> وطبعنا كل عنصر على حدة، استطعنا الوصول إلى أرقام الصّفحات من واحد إلى خمسة، وفي السّطر الأخير، ينتج استدعاء الدّالة <code>list</code> وتمرير المُولّد إليها قائمةً عاديّة، وهذا السّطر الأخير غير مفيد إلا في التّوضيح فقط، واستخدام المُولّد مُباشرة أمر طبيعي.
</p>

<p>
	فهذا المُولّد يُستخدم بشكل شائع لتوفير شريط تصفّح لتمكين الزّائر من الانتقال من صفحة إلى أخرى، ولا بدّ أنّك صادفت مثل هذا الشّريط من قبل. ولتوفير الشّريط لمُستخدمي تطبيقك، استخدم ماكرو خاص مع مُحرّك القوالب Jinja، وهو كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_40" style="">
<span class="pun">{%</span><span class="pln"> macro render_pagination</span><span class="pun">(</span><span class="pln">pagination</span><span class="pun">,</span><span class="pln"> endpoint</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="pln">pagination</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{%-</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> page </span><span class="kwd">in</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">iter_pages</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> page </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> page </span><span class="pun">!=</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">page </span><span class="pun">%}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"{{ url_for(endpoint, page=page) }}"</span><span class="pun">&gt;{{</span><span class="pln"> page </span><span class="pun">}}&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;{{</span><span class="pln"> page </span><span class="pun">}}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="pln">ellipsis</span><span class="pun">&gt;…&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">{%-</span><span class="pln"> endfor </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endmacro </span><span class="pun">%}</span></pre>

<p>
	يأخذ الماكرو <code>render_pagination</code> مُعاملين اثنين، الأول هو الكائن الذي يُمثّل صفحة مُعيّنة، ويجب أن يكون من الصّنف <code>Pagination</code>، مثل <code>page_1</code> أو <code>page_2</code> في الأمثلة السّابقة، أمّا المُعامل الثّاني فهو رابط المُوجّه الذي سيكون مسؤولا عن عرض الصّفحات في المُتصفّح، ويجب أن يكون الرّابط على شكل اسم الطّبعة الزّرقاء (إن وُجدت) ثمّ نقطة ثمّ اسم الدّالة المُرتبطة بالمُوجّه.
</p>

<p>
	فمثلا إن كان الموجّه الخاصّ بك يقع تحت طبعة زرقاء باسم <code>posts</code> وكانت اسم الدّالة المُرتبطة بهذا الموجّه هي <code>(pages(page</code> بحيث <code>page</code> رقم الصّفحة، فقيمة المُعامل <code>endpoint</code> في الماكرو أعلاه يجب أن تكون كما يلي: <code>'posts.pages'</code>، والسّبب الرّئيسي لتوفير هذا المُعامل هو أنّ الماكرو يستخدم الدّالة <code>url_for</code> لتوليد رابط للصّفحة حسب رقمها، والتّالي بعض الرّوابط التّي يُمكن أن تُولّد:
</p>

<pre class="ipsCode">
/posts/page/1
/posts/page/2
/posts/page/3
...
</pre>

<p>
	وعليه يكون الشريط في نفس المكان في كل مرّة تصل فيها إلى صفحة مُعيّنة. لاحظ بأنّنا نستعمل في الماكرو حلقة <code>for</code> مع التّابع <code>()iter_pages</code> الذي تحدّثنا عنه سابقا، وذلك لعرض أرقام الصّفحات وإضافة رابط لكل صفحة، وهكذا سيكون الشّريط كما يلي: 1 2 3 4 5
</p>

<p>
	مع رابط تحت كل رقم ليُوجّه إلى الصّفحة المُناسبة في التّطبيق.
</p>

<p>
	تتحقق الجملة الشّرطيّة <code>if</code> إن كانت الصّفحة الحاليّة تحمل نفس رقم الصّفحة المُتواجد في <code>pagination.page</code> وذلك لعرض الصّفحة الحاليّة بشكل مُميّز (في هذه الحالة سيكون خطّا عريضا مع إزالة الرابط) ليعرف الزّائر أية صفحة يتواجد فيها. تستطيع كذلك أن تنسقه كما تشاء، فقط أضف خاصيّة css وسيكون التّنسيق هو نفسه في جميع أنحاء التّطبيق ما دمت تستدعي هذا الماكرو في المكان الذي تُريد به الشّريط.
</p>

<p>
	إذا كنت تستخدم إطار العمل Bootstrap فإن الماكرو التّالي يُوفّر تنسيقا جميلا لشريط التّصفّح مع زرّين إضافيّين، واحد للانتقال إلى الصّفحة السّابقة والآخر للانتقال إلى الصّفحة التّاليّة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_30" style="">
<span class="pun">{%</span><span class="pln"> macro render_pagination</span><span class="pun">(</span><span class="pln">pagination</span><span class="pun">,</span><span class="pln"> endpoint</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="pln">pagination</span><span class="pun">&gt;</span><span class="pln">

  </span><span class="pun">&lt;</span><span class="pln">nav aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Page navigation"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">ul </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"pagination"</span><span class="pun">&gt;</span><span class="pln">

  </span><span class="pun">{#</span><span class="pln"> </span><span class="pun">انتقل</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">الصّفحة</span><span class="pln"> </span><span class="pun">السّابقة</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">كانت</span><span class="pln"> </span><span class="pun">مُتواجدة</span><span class="pln"> </span><span class="com">#}</span><span class="pln">

  </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">has_prev </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"{{ url_for(endpoint, page=pagination.prev_num) }}"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Previous"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span aria</span><span class="pun">-</span><span class="pln">hidden</span><span class="pun">=</span><span class="str">"true"</span><span class="pun">&gt;«&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'disabled'</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"#"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Previous"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span aria</span><span class="pun">-</span><span class="pln">hidden</span><span class="pun">=</span><span class="str">"true"</span><span class="pun">&gt;«&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{#</span><span class="pln"> </span><span class="pun">عرض</span><span class="pln"> </span><span class="pun">أزرار</span><span class="pln"> </span><span class="pun">الصّفحات</span><span class="pln"> </span><span class="pun">(&lt;&lt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">&gt;&gt;)#}</span><span class="pln">

  </span><span class="pun">{%-</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> page </span><span class="kwd">in</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">iter_pages</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> page </span><span class="pun">%}</span><span class="pln">

    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> page </span><span class="pun">!=</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">page </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"{{ url_for(endpoint, page=page) }}"</span><span class="pun">&gt;{{</span><span class="pln"> page </span><span class="pun">}}&lt;/</span><span class="pln">a</span><span class="pun">&gt;&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"active"</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"{{ url_for(endpoint, page=page) }}"</span><span class="pun">&gt;{{</span><span class="pln"> page </span><span class="pun">}}&lt;/</span><span class="pln">a</span><span class="pun">&gt;&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">

    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="pln">ellipsis</span><span class="pun">&gt;…&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">{%-</span><span class="pln"> endfor </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{#</span><span class="pln"> </span><span class="pun">انتقل</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">الصّفحة</span><span class="pln"> </span><span class="pun">المُواليّة</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">كانت</span><span class="pln"> </span><span class="pun">مُتواجدة</span><span class="pln"> </span><span class="com">#}</span><span class="pln">
  </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> pagination</span><span class="pun">.</span><span class="pln">has_next </span><span class="pun">%}</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"{{ url_for(endpoint, page=pagination.next_num) }}"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Next"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span aria</span><span class="pun">-</span><span class="pln">hidden</span><span class="pun">=</span><span class="str">"true"</span><span class="pun">&gt;»&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'disabled'</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"#"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Next"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span aria</span><span class="pun">-</span><span class="pln">hidden</span><span class="pun">=</span><span class="str">"true"</span><span class="pun">&gt;»&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">nav</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endmacro </span><span class="pun">%}</span></pre>

<p>
	لاحظ جيّدا بأنّ هذا الماكرو يستخدم كذلك كلّا من الخاصيّتين <code>has_next</code> و <code>has_prev</code>، وذلك لتعطيل زرّ الانتقال إلى الصّفحة السّابقة إذا لم تكن تتواجد وتعطيل زر الانتقال إلى الصّفحة التّالية في نفس الحالة كذلك.
</p>

<p>
	كل ما عليك فعله لاستخدام الماكرو هو وضعه في أعلى ملفّ HTML واستدعائه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_32" style="">
<span class="pun">{{</span><span class="pln"> render_pagination</span><span class="pun">(</span><span class="pln">pagination</span><span class="pun">,</span><span class="pln"> </span><span class="str">'posts.pages'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></pre>

<p>
	يفترض المثال أعلاه أنّ المُتغيّر الذي يحمل كائنا من الصّنف <code>Pagination</code> يُسمّى <code>pagination</code> والذي سيتوجّب عليك تمريره إلى ملفّ HTML عن طريق الدّالة <code>render_template</code> ورابط الموجّه المسؤول عن عرض الصّفحات هو <code>posts.pages</code> والذي سيُمرّر إلى الدّالة <code>url_for</code> لتوليد رابط كل صفحة على حدة.
</p>

<h2>
	الحصول على رقم الصفحة التالية
</h2>

<p>
	تطرّقنا من قبل إلى أنّك تستطيع الوصول إلى الكائن الذي يُمثّل الصّفحة التّاليّة عن طريق استخدام التّابع <code>next</code>، ولكن ماذا لو أردت أن تصل إلى رقم الصّفحة التّالية فقط؟ يُمكنك الحصول على رقم الصّفحة التّاليّة عن طريق استخدام الخاصيّة <code>next_num</code>، انظر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_34" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">next_num
</span><span class="lit">2</span></pre>

<p>
	في المثال، نحصل على الصّفحة الأولى ثمّ نستخدم الخاصيّة <code>next_num</code> للحصول على رقم الصّفحة التالية للصّفحة الأولى والذي هو الرّقم 2 وهذا طبيعي لأنّ رقم الصّفحة الأولى هو 1.
</p>

<h2>
	الحصول على رقم الصفحة الحالية
</h2>

<p>
	للوصول إلى رقم الصّفحة الحاليّة كل ما عليك القيام به هو استخدام الخاصيّة <code>page</code> وستحصل على رقم الصّفحة المرتبطة بالكائن من الصّنف <code>Pagination</code>. انظر المثال التالي لكيفية الحصول على رقم الصّفحة الحاليّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_36" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_1</span><span class="pun">.</span><span class="pln">page
</span><span class="lit">1</span></pre>

<h2>
	الحصول على رقم الصّفحة السّابقة
</h2>

<p>
	تشبه طريقة الوصول إلى رقم الصّفحة السّابقة ما سبق، فقط استخدم الخاصيّة <code>prev_num</code> عوضا عن <code>next_num</code> و <code>page</code>. يغطي المثال التّالي كيفيّة الحصول على أرقام الصّفحات التّي ذكرناها إلى الآن.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7050_38" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">paginate</span><span class="pun">(</span><span class="pln">page</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> per_page</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">page
</span><span class="lit">2</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">prev_num
</span><span class="lit">1</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> page_2</span><span class="pun">.</span><span class="pln">next_num
</span><span class="lit">3</span></pre>

<h2>
	خاتمة
</h2>

<p>
	هكذا نكون قد وصلنا إلى جزء مُهم من مشوارنا لتعلّم كيفيّة التّعامل مع قاعدة بياناتنا باستخدام كل من مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy، وتبقى لنا بضعة أمور مُهمّة لتعلّم كيفيّة إجراء عمليّات CRUD كلّها، إذ أنّنا لم نتعرّف بعد على كلّ من كيفيّة تعديل وحذف السّجلات إلّا أنّها أمور بسيطة لذا لن تأخذ الكثير من المساحة في هذه السّلسلة من الدّروس.
</p>

<p>
	لذا سنُنهي جزء التّعامل مع قاعدة البيانات لنتمكّن بعدها من العودة إلى تطبيق "كلمة" لنستمرّ في تطويره بإنشاء نظام لتسجيل مُستخدمين جدد وتسجيل دخولهم وتسجيل خروجهم، إضافة إلى عرض المقالات المتواجدة بقاعدة البيانات وكذا تمكين كل مُستخدم من إضافة مقالات خاصّة به، وسنستغلّ ما تعلّمناه من طرق لتقسيم السّجلات إلى صفحات مُتعدّدة ومُختلف المعلومات التّي اكتسبناها لتُعرض كل المقالات بشكل مُناسب للمُستخدمين مع شريط تصفّح للانتقال بين الصّفحات وما إلى ذلك.
</p>
]]></description><guid isPermaLink="false">831</guid><pubDate>Fri, 21 Feb 2020 16:44:15 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x627;&#x644;&#x62A;&#x627;&#x628;&#x639; filter &#x641;&#x64A; &#x645;&#x643;&#x62A;&#x628;&#x629; SQLAlchemy &#x628;&#x62C;&#x627;&#x646;&#x628; &#x628;&#x642;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x648;&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x62A;&#x648;&#x627;&#x631;&#x64A;&#x62E;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D8%A7%D8%A8%D8%B9-filter-%D9%81%D9%8A-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-sqlalchemy-%D8%A8%D8%AC%D8%A7%D9%86%D8%A8-%D8%A8%D9%82%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B1%D9%8A%D8%AE-r830/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/28.jpg.7bd67254f1970f847533f33e1c89f70d.jpg" /></p>

<p>
	بعد أن تعرفنا على كيفيّة استعمال التّابع <code>filter</code> في مكتبة SQLAlchemy لترشيح السجلات عند الحصول عليها من قاعدة البيانات باستعمال شروط منطقيّة متقدمة في <a href="https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B1%D8%B4%D9%8A%D8%AD-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%B4%D8%B1%D9%88%D8%B7-%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-%D9%81%D9%8A-sqlalchemy-r829/" rel="">الدّرس السّابق</a>، سنستمر في استكشاف ميّزات SQLAlchemy لبناء تطبيقات ويب أفضل، إذ سنتعرف في هذا الدّرس على كيفيّة استعمال التابع <code>filter</code> مع بقيّة التّوابع والدّوال المتوفّرة في المكتبة، إضافة إلى مقدمة بسيطة إلى كيفيّة التّعامل مع التّاريخ والوقت في بايثون للحصول على سجلّات من قاعدة البيانات حسب وقت وتاريخ محددين.
</p>

<h2>
	مزج التابع <code>filter</code> ببقية التوابع، والدوال التي توفرها مكتبة SQLAlchemy
</h2>

<p>
	يمكن مزج التّابع <code>filter</code> ببقيّة التّوابع، كما في حالة مزجه مع التّابع <code>limit</code> لتحديد عدد معيّن من النّتائج بعد ترشيحها وفق شرط أو شروط معيّنة، أو حتى مزج <code>filter</code> مع <code>filter_by</code> إن أردت ذلك (لكن مزجهما لا فائدة منه).
</p>

<p>
	لنحصل مثلًا على جميع المُستخدمين الذين تبدأ أسماءهم بالمقطع <code>user</code> ونحدّد عدد النّتائج في نتيجتين فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_7" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'user'</span><span class="pun">)).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">

</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user4 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user4@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user5@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<p>
	كذلك يمكنك استعمال <code>order_by</code> بعد التابع <code>filter</code> لترتيب النّتائج التي تُحقّق الشروط المطروحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_9" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">in_</span><span class="pun">([</span><span class="str">'user4'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'abdelhadi'</span><span class="pun">])).</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">


</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln"> 

</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user4 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user4@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<p>
	وهذا مثال آخر على كيفيّة مزج كل من <code>filter</code> و <code>order_by</code> ثمّ <code>limit</code> في استعلام واحد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_11" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">in_</span><span class="pun">([</span><span class="str">'user4'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'abdelhadi'</span><span class="pun">])).</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">

</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<h2>
	استعمال filter للحصول على نتائج حسب تاريخ إضافتها
</h2>

<p>
	قد يحتاج التّعامل مع التّاريخ والوقت في بايثون إلى درس مُستقل لما فيه من التّعقيد والحالات المُختلفة، ورغم أنّني سأحاول ذكر معظم الأشياء المهمّة في هذه الفقرة، إلّا أنّني لن أذكر كل شيء، بل أهيب بك أن تجد درسا يشرح هذا الجزء بتفصيل أكبر.
</p>

<h3>
	الهدف
</h3>

<p>
	هدفنا من هذه الفقرة هو تقديم فكرة عن كيفيّة التّعامل مع السّجلات حسب تاريخ إضافتها (أي قيمة العمود <code>created_date</code>)، فبما أنّنا نمتلك معلومة مهمّة عن السّجل وهو وقت إضافته فسنتمكّن من الحصول على سجلّات حسب يوم إضافتها والسّجلات التّي أضيفت أثناء مقطع زمني معيّن (مثلا بين 5 أيام و10 أيام الماضيّة)، وعندما تفهم أساسيّات التّعامل مع التّاريخ والوقت فستتمكّن من إضافة ميّزات أخرى إلى تطبيقاتك كتحديد تاريخ آخر تعديل وكذلك أرشفة السّجلات حسب تاريخ إضافتها والعديد من الأفكار الأخرى.
</p>

<h3>
	وحدة <code>datetime</code>
</h3>

<p>
	الوحدة <code>datetime</code> هي وحدة مبنيّة مُسبقا بلغة بايثون، ويكفي للوصول إليها أن تقوم باستيرادها مُباشرة. تحتوي هذه الوحدة على العديد من الدّوال المُساعدة والوحدات الأخرى داخلها، وسنهتم حاليا بكل من الوحدة البنت <code>datetime</code> والدّالة <code>timedelta</code> فقط، لذا سنقوم باستيرادهما كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_13" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> datetime</span><span class="pun">,</span><span class="pln"> timedelta</span></pre>

<p>
	هنا نستدعي كلا من <code>datetime</code> و<code>timedelta</code> من الوحدة <code>datetime</code> وبالتّالي فبغض النّظر عن التّشابه في الاسم فإن الوحدة التّي نستدعي منها هي الأصل والوحدة <code>datetime</code> الأخرى مجرّد فرع من الوحدة الأصليّة.هذا يعني بأنّنا إن أردنا الوصول إلى الوحدة الفرعيّة <code>datetime</code> عند استدعاء الوحدة الأصليّة <code>datetime</code> مُباشرة فعلينا إخبار بايثون بالأمر صراحة.
</p>

<p>
	بالمثال يتضح المقال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_15" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> datetime
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> datetime
</span><span class="pun">&lt;</span><span class="pln">module </span><span class="str">'datetime'</span><span class="pln"> </span><span class="pun">(</span><span class="pln">built</span><span class="pun">-</span><span class="kwd">in</span><span class="pun">)&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">datetime
</span><span class="pun">&lt;</span><span class="pln">type </span><span class="str">'datetime.datetime'</span><span class="pun">&gt;</span></pre>

<p>
	قارن الخرج بما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_17" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> datetime</span><span class="pun">,</span><span class="pln"> timedelta
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> datetime
</span><span class="pun">&lt;</span><span class="pln">type </span><span class="str">'datetime.datetime'</span><span class="pun">&gt;</span></pre>

<p>
	الاستنتاج هنا هو أنّ <code>datetime</code> هي الوحدة الأصلية و<code>datetime.datetime</code> هي وحدة فرعيّة، وبينهما اختلاف واضح. والآن بعد أن حدّدنا الفرق بين كل من الوحدة <code>datetime</code> والوحدة البنت <code>datetime</code>، وبما أنّنا نستدعي هذه الأخيرة فسأشير إليها بـ<code>datetime</code> مُباشرة.
</p>

<p>
	إليك تذكيرا بسطر الاستيراد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_19" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> datetime</span><span class="pun">,</span><span class="pln"> timedelta</span></pre>

<p>
	لنحدّد الآن الفرق بين كل من <code>datetime</code> و<code>timedelta</code>، وأبسط طريقة لشرح كل واحدة هي كالآتي:
</p>

<p>
	datetime تُمكّننا من التّعامل مع التاريخ (date) والوقت (time).timedelta تُحدّد الفرق بين مُدّتين زمنيّتين.`
</p>

<p>
	هذا يعني أنّك إن أردت الحصول على مدّة زمنّية معيّنة (الوقت الحالي حسب توقيتك المحلي أو توقيت UTC مثلا) فسيتوجّب عليك استخدام <code>datetime</code> مع مُختلف التّوابع التّي تُوفّرها الوحدة. وإن أردت الحصول على مقدار الوقت بين مدّتين زمنيّتين فسيتوجّب عليك استخدام <code>timedelta</code>، أمّا لو أردت الحصول مثلا على الفرق بين الوقت الحالي والوقت قبل 3 أيام فستستعمل كلا من <code>datetime</code> و<code>timedelta</code> .
</p>

<p>
	سأشرح لك بعض الأمثلة على كيفيّة استخدام كل من <code>datetime</code> و <code>timedelta</code> للحصول على سجلات من قاعدة البيانات حسب تاريخ إضافتها وشروط أخرى بفضل التّابع <code>filter</code> الذي تُوفّره لنا مكتبة SQLAlchemy، وسنتعرّف في الفقرات التّاليّة على بضعة أساليب لترشيح السّجلات حسب النقطة الزمنيّة التي أضيفت فيها، وذلك عبر استخدام التّابع <code>filter</code> وخصائص الصّنف <code>datetime</code>.
</p>

<h3>
	الحصول على سجلات حسب سنة إضافتها
</h3>

<p>
	سنبدأ أولا بالتّعرف على كيفيّة الحصول على السجلات التي أضيفت في سنة مُعيّنة، كالمستخدمين الذين سجّلوا في الموقع في سنة 2018 أو المقالات التي أضيفت في سنة 2017 وغير ذلك من الإمكانيّات الأخرى التي يُمكنك التفكير فيها عند إنشاء تطبيقات تعتمد على ترتيب المحتوى حسب السنوات أو عرض بيانات خاصّة بسنة مُعيّنة.
</p>

<p>
	للحصول مثلا على جميع المُستخدمين الذين سجّلوا في التّطبيق في سنة 2017، سنستعمل دالّة في SQLAlchemy باسم <code>extract</code> لاستخراج السنة من قيمة التاريخ لمُقارنتها مع السنة التي نرغب في الحصول على السجلات المرتبطة بها، أي أنّنا سنستعمل التّابع <code>filter</code> للحصول على السّجلات التي يحتوي تاريخ إضافتها على السّنة 2017، والمثال التّالي توضيح على ما سبق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_21" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

users2017 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'year'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2017</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	في الشّيفرة أعلاه، نستورد الدّالة <code>extract</code> أولًا من حزمة <code>sqlalchemy</code> (لاحظ أنّ هذه الحزمة مُتعلّقة بمكتبة SQLAlchemy وليس بإضافة Flask-SQLAlchemy)، ثمّ نقوم باستيراد الصّنف <code>User</code>، بعدها نُنشئ المُتغيّر <code>users2017</code> الذي سيحمل قائمة تحتوي على جميع المُستخدمين الذين تمّت إضافتهم إلى قاعدة البيانات في أي وقت من سنة 2017.
</p>

<p>
	الشّرط الذي نُمرّره للتّابع <code>filter</code> أعلاه هو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7350_23" style="">
<span class="pln">extract</span><span class="pun">(</span><span class="str">'year'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2017</span></pre>

<p>
	لاحظ بأنّ السّطر عبارة عن مُقارنة بسيطة إذ نُقارن القيمة النّاتجة عن استدعاء الدّالة <code>extract</code> مع تمرير سلسة نصيّة <code>’year’</code> كمعامل أول و<code>User.created_date</code> كمُعامل ثانِِ مع العدد الصّحيح <code>2017</code>، ما يعني بأنّك لو أردت الحصول على المُستخدمين الذين أُضيفوا في سنة 2018 فكل ما عليك فعله هو تغيير 2017 بـ 2018 كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_25" style="">
<span class="pln">extract</span><span class="pun">(</span><span class="str">'year'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2018</span></pre>

<h3>
	الحصول على سجلات أضيفت في شهر معين
</h3>

<p>
	نتّبع نفس المنهج عند الرّغبة في الحصول على سجلّات أُضيفت في شهر مُعيّن من السّنة، علينا فقط استخراج الشّهر (<code>month</code>) من التاريخ عوضا عن السّنة، فللحصول على السّجلات التّي أضيفت في الشّهر الأول من كلّ سنة سنستعمل الشّرط التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_27" style="">
<span class="pln">extract</span><span class="pun">(</span><span class="str">'month'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	ما يعني بأنّ الشيفرة الكليّة ستُصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_29" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

jan_users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'month'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	في هذه الحالة، سيحمل المُتغيّر jan_users قائمة بجميع المُستخدمين الذين سجّلوا في الشّهر الأول. لاحظ أنّنا لم نُحدّد السّنة هنا، ما يعني بأنّ النتيجة ستكون عبارة عن المُستخدمين الذين سجّلوا في الشّهر الأول من أي سنة كيفما كانت.
</p>

<h3>
	الحصول على سجلات أضيفت في يوم معين من الشهر
</h3>

<p>
	للحصول على سجلّ حسب اليوم من الشّهر الذي تمّت إضافته فيه إلى قاعدة البيانات، فكلّ ما عليك فعله هو استخدام الخيار <code>day</code> عوضا عن <code>year</code> للسّنة أو <code>month</code> للشّهر.
</p>

<p>
	مثال على كيفيّة الحصول على جميع المُستخدمين الذين سجّلوا في اليوم الأول من الشّهر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_31" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'day'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	الشّهر والسّنة لا يُهمّان هنا، المُهمّ أن يُضاف السّجل في اليوم الأول من أي شهر كان بغضّ النظر عن السّنة.
</p>

<h3>
	الحصول على سجلات أضيفت في تاريخ معين (سنة، شهر، يوم)
</h3>

<p>
	يُمكن جمع المعلومات السّابقة والدّالَّة <code>db.and_</code> التي تعرّفنا عليها في درس سابق للحصول على سجلّات من قاعدة البيانات حسب تاريخ مُحدّد، أي في يوم وشهر مُحدّدين وسنة مُعيّنة. للحصول مثلا على جميع المُستخدمين الذين سجّلوا في اليوم الأول من الشّهر الأول من سنة 2018:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_33" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db

users2018 </span><span class="pun">=</span><span class="pln"> extract</span><span class="pun">(</span><span class="str">'year'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2018</span><span class="pln">
first_jan_users </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'month'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
                          extract</span><span class="pun">(</span><span class="str">'day'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
                         </span><span class="pun">)</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">users2018</span><span class="pun">,</span><span class="pln"> first_jan_users</span><span class="pun">)).</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	هنا يحمل المُتغيّر <code>users2018</code> شرطا يحدّد المُستخدمين الذين تمّت إضافتهم إلى قاعدة البيانات في سنة 2018، والمُتغيّر <code>first_jan_users</code> يحمل شرطا يُحدّد بأن على المستخدم أن يُسجَّل في الشهر الأول وكذا في أول يوم، ما يعني بأنّنا جمعنا شرطين في شرط واحد.
</p>

<p>
	بعدها نستعمل الشّرطين <code>users2018</code> و<code>first_jan_users</code> للحصول على المستخدمين الذين يُحقّقون كلا الشّرطين في آن واحد، أي أن يُسجّلوا في سنة 2018 واليوم الأول من الشّهر الأول.
</p>

<p>
	يُمكنك تغيير القيم كيفما تشاء، وكذلك استعمال خصائص الوقت (السّاعة والدّقيقة على سبيل المثال) للحصول على سجلات حسب مُددِِ زمنيّة أكثر دقّة، وهذا ما سنتعرّف عليه في الفقرات التّاليّة من هذا الدّرس.
</p>

<h3>
	الحصول على سجلات أضيفت في ساعة معينة من اليوم
</h3>

<p>
	سنتّبع نفس المنهج الذي كنّا نستعمله عند التّعامل مع السنوات والأشهر والأيام للحصول على سجلّات حسب السّاعة من اليوم، أي الدّالة <code>extract</code>، وسنستخرج القيمة <code>hour</code> للعمل مع ساعات اليوم كما يلي (مع استبدال <code>HOUR</code> بالساعة في النظام الأربع والعشرينيّ 24h):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_35" style="">
<span class="pln">extract</span><span class="pun">(</span><span class="str">'hour'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> HOUR</span></pre>

<p>
	إن أردنا الحصول على جميع المُستخدمين الذين سجّلوا في الخامسة مساءً:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_37" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

five_pm_users </span><span class="pun">=</span><span class="pln"> extract</span><span class="pun">(</span><span class="str">'hour'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">17</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">five_pm_users</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<h3>
	الحصول على سجلات أضيفت في دقيقة معينة
</h3>

<p>
	للحصول على سجلّات حسب الدقيقة التي أُضيفت فيها، استعمل minute مع الدّالة extract. وللحصول على المُستخدمين الذين سجّلوا في الدّقيقة الأولى من كلّ ساعة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_39" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

first_minute_users </span><span class="pun">=</span><span class="pln"> extract</span><span class="pun">(</span><span class="str">'minute'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">first_minute_users</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<h3>
	الحصول على سجلات حسب وقت وتاريخ إضافتها
</h3>

<p>
	لنجمع جميع المعلومات أعلاه للحصول على سجلّات حسب كلّ من تاريخ إضافتها (سنة، شهر، يوم) ووقت إضافتها (السّاعة والدّقيقة)، نحصل في المثال التّالي على أي مُستخدم سجّل في اليوم الأول من الشّهر الأول من سنة 2018 في الدّقيقة الأولى من السّاعة الخامسة مساءً:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_41" style="">
<span class="kwd">from</span><span class="pln"> sqlalchemy </span><span class="kwd">import</span><span class="pln"> extract
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db

users2018 </span><span class="pun">=</span><span class="pln"> extract</span><span class="pun">(</span><span class="str">'year'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2018</span><span class="pln">
first_jan_users </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'month'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
                          extract</span><span class="pun">(</span><span class="str">'day'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
                         </span><span class="pun">)</span><span class="pln">
five_pm_first_minute_users </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">extract</span><span class="pun">(</span><span class="str">'hour'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln">
                                     extract</span><span class="pun">(</span><span class="str">'minute'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
                                    </span><span class="pun">)</span><span class="pln">
first_jan_five_pm_first_minute </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">first_jan_users</span><span class="pun">,</span><span class="pln">
                                         five_pm_first_minute_users
                                        </span><span class="pun">)</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">users2018</span><span class="pun">,</span><span class="pln">
                                  first_jan_five_pm_first_minute
                                 </span><span class="pun">)</span><span class="pln">
                         </span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	لاحظ الشّروط التّي استخدمناها:
</p>

<ul>
<li>
		<code>users2018</code>: المستخدمون الذين سجّلوا في سنة 2018
	</li>
	<li>
		<code>first_jan_users</code>: المستخدمون الذين سجّلوا في اليوم الأول من الشّهر الأول
	</li>
	<li>
		<code>five_pm_first_minute_users</code>: المستخدمون الذين سجّلوا في الدّقيقة الأولى من السّاعة الخامسة
	</li>
	<li>
		<code>first_jan_five_pm_first_minute</code>: المستخدمون الذين سجّلوا في الدّقيقة الأولى من السّاعة الخامسة في 1 يناير.
	</li>
</ul>
<p>
	يُمكن كذلك مزج الشّروط الواحد داخل الآخر دون حفظها في مُتغيّرات خاصّة، لكنّ يفضل تسجيل الشّروط في مُتغيّرات لتسهيل قراءة الشّيفرة.
</p>

<h2>
	التعامل مع الفروقات الزمنية
</h2>

<p>
	يُمكن استعمال الدّالة <code>timedelta</code> من وحدة <code>datetime</code> للتّعامل مع الفروقات الزّمنية، إذ تُرجع <code>timedelta</code> فرقا زمنيّا بين نقطتين زمنيّتين مُحدّدتين بمقدار زمنيّ مُعيّن. وللحصول على فرق زمني مقدار يوم واحد، سنُمرّر عدد الأيام (1 في هذه الحالة) إلى المُعامل <code>days</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_43" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> timedelta
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> one_day </span><span class="pun">=</span><span class="pln"> timedelta</span><span class="pun">(</span><span class="pln">days</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> one_day
datetime</span><span class="pun">.</span><span class="pln">timedelta</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	للحصول على فرق زمني مقداره 30 ثانيّة سنُمرّر القيمة إلى المُعامل <code>seconds</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_45" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> thirty_seconds </span><span class="pun">=</span><span class="pln"> timedelta</span><span class="pun">(</span><span class="pln">seconds</span><span class="pun">=</span><span class="lit">30</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> thirty_seconds
datetime</span><span class="pun">.</span><span class="pln">timedelta</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">)</span></pre>

<p>
	للحصول على فرق زمني مقداره يوم وثلاثون ثانيّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_47" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> timedelta</span><span class="pun">(</span><span class="pln">days</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> seconds</span><span class="pun">=</span><span class="lit">30</span><span class="pun">)</span><span class="pln">
datetime</span><span class="pun">.</span><span class="pln">timedelta</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">)</span></pre>

<p>
	يُمكن كذلك الحصول على الفرق الزمني بين قيمتي <code>datetime</code> مُختلفتين، فللحصول على الفرق الزّمني بين سنتي 2017 و2018 مثلًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_49" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> datetime</span><span class="pun">,</span><span class="pln"> timedelta
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> date1 </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">(</span><span class="pln">year</span><span class="pun">=</span><span class="lit">2017</span><span class="pun">,</span><span class="pln"> month</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> day</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> date2 </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">(</span><span class="pln">year</span><span class="pun">=</span><span class="lit">2018</span><span class="pun">,</span><span class="pln"> month</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> day</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">date1</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2017</span><span class="pun">-</span><span class="lit">01</span><span class="pun">-</span><span class="lit">01</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">date2</span><span class="pun">)</span><span class="pln">
</span><span class="lit">2018</span><span class="pun">-</span><span class="lit">01</span><span class="pun">-</span><span class="lit">01</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> delta </span><span class="pun">=</span><span class="pln"> date2 </span><span class="pun">-</span><span class="pln"> date1
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> delta
datetime</span><span class="pun">.</span><span class="pln">timedelta</span><span class="pun">(</span><span class="lit">365</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">delta</span><span class="pun">)</span><span class="pln">
</span><span class="lit">365</span><span class="pln"> days</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="lit">00</span><span class="pun">:</span><span class="lit">00</span></pre>

<p>
	لاحظ بأنّ كل ما قمنا به هو عمليّة فرق بسيطة <code>date2 – date1</code> وأسندنا القيمة إلى المتغيّر <code>delta</code>، والذي يُعطينا القيمة <code>365 days, 0:00:00</code> عند طباعته، أي أن الفرق الزمني بين السّنتين هو 365 يوما، صفر ساعة، صفر دقيقة وصفر ثانيّة.
</p>

<p>
	نستطيع استعمال قيمة الفرق الزمني في SQLAlchemy للحصول على سجلّات بشروط مثل أن تكون قد سُجّلت قبل شهر واحد، قبل سنة، ما بين الشّهر والشّهرين، إلى غير ذلك.
</p>

<p>
	يمكنّنا المثال التّالي من الحصول على جميع المُستخدمين الذين سجّلوا بعد أسبوعين مُنصرمين وقبل أسبوع واحد من الآن:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7350_51" style="">
<span class="kwd">from</span><span class="pln"> datetime </span><span class="kwd">import</span><span class="pln"> datetime</span><span class="pun">,</span><span class="pln"> timedelta

</span><span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">

</span><span class="com"># Get Users who signed up between</span><span class="pln">
</span><span class="com"># two weeks and one week ago</span><span class="pln">


datetime_now </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">utcnow</span><span class="pun">()</span><span class="pln">

seven_days </span><span class="pun">=</span><span class="pln"> timedelta</span><span class="pun">(</span><span class="pln">days</span><span class="pun">=</span><span class="lit">7</span><span class="pun">)</span><span class="pln">
one_week_ago </span><span class="pun">=</span><span class="pln"> datetime_now </span><span class="pun">-</span><span class="pln"> seven_days

fifteen_days </span><span class="pun">=</span><span class="pln"> timedelta</span><span class="pun">(</span><span class="pln">days</span><span class="pun">=</span><span class="lit">15</span><span class="pun">)</span><span class="pln">
two_weeks_ago </span><span class="pun">=</span><span class="pln"> datetime_now </span><span class="pun">-</span><span class="pln"> fifteen_days

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
        db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date </span><span class="pun">&gt;=</span><span class="pln"> two_weeks_ago</span><span class="pun">,</span><span class="pln">
                </span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date </span><span class="pun">&lt;=</span><span class="pln"> one_week_ago</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span></pre>

<h2>
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة استعمال التّابع <code>filter</code> لإجراء عمليّات متقدّمة، ومزجه ببقيّة التوابع المتوفرة في SQLAlchemy، كما ألقينا نظرة على خصائص التّاريخ والوقت وكيفيّة الاعتماد عليها للحصول على سجلّات من قاعدة البيانات حسب شروط زمنيّة مُعيّنة.
</p>
]]></description><guid isPermaLink="false">830</guid><pubDate>Fri, 21 Feb 2020 16:31:45 +0000</pubDate></item><item><title>&#x62A;&#x631;&#x634;&#x64A;&#x62D; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x634;&#x631;&#x648;&#x637; &#x645;&#x646;&#x637;&#x642;&#x64A;&#x629; &#x641;&#x64A; SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B1%D8%B4%D9%8A%D8%AD-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%B4%D8%B1%D9%88%D8%B7-%D9%85%D9%86%D8%B7%D9%82%D9%8A%D8%A9-%D9%81%D9%8A-sqlalchemy-r829/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/27.jpg.45073089490a0c33b12548c373e5fa53.jpg" /></p>

<p>
	سنُتم في هذا الدرس ما بدأناه في <a href="https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AD%D8%AF-%D9%85%D9%86-%D8%B9%D8%AF%D8%AF%D9%87%D8%A7-%D9%88%D8%A7%D9%84%D8%AD%D8%B5%D9%88%D9%84-%D8%B9%D9%84%D9%89-%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D8%A8%D8%B4%D9%83%D9%84-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A-%D9%81%D9%8A-sqlalchemy-r828/" rel="">الدرس السابق</a> من تعلم لكيفيّة استعمال الشروط والمعاملات المنطقيّة المتقدمة في لغة بايثون، من أجل الحصول على نتائج دقيقة من قاعدة البيانات عند استعمال مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy.
</p>

<h2>
	التعامل مع السلاسل النصية
</h2>

<p>
	قد تحتاج أحيانا إلى التّحقق من أنّ سلسلة نصيّة ما تبدأ أو تنتهي بكلمة أو حرف، أو أنّ كلمة أو حرفا معيّنا يتواجد في قائمة أو سلسلة نصيّة، لذا سنتعرّف في الفقرات التّاليّة على كيفيّة فعل ذلك في لغة بايثون.
</p>

<h3>
	التابع <code>startswith</code>
</h3>

<p>
	يُطبّق التّابع <code>startswith</code> على السّلسلة النّصيّة للتأكّد من أنّها <em>تبدأ</em> بمقطع معيّن، فمثلًا، سنتأكّد أنّ السّلسلة النّصيّة <code>abdelhadi</code> تبدأ بالمقطع <code>abd</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_8" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'abdelhadi'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> name</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'abd'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	يُمكنك تطبيق هذه الميّزة من أجل الحصول على جميع المقالات التّي يبدأ عنوانها بمقطع معيّن، فمثلا لنقل بأنّك تمتلك في مدوّنتك مقالات مُختلفة إضافة إلى مقالات تُشير إلى كل تحديث في تطبيقك لتعرض الميّزات الجديدة، ثم لنفترض زيادة حجم التطبيق بعد مدة إلى أن صارت له مُدونته المستقلة عن مُدوّنتك، سيتوجّب عليك الآن نقل المقالات المُخصّصة للتّحديثات إلى هذه المُدوّنة الجديدة، وعلى فرض أنّ تلك المقالات تبدأ بكلمة "تحديث"، فكيف يُمكنك الحصول على هذه المقالات لنقلها دون المقالات الأخرى؟
</p>

<p>
	فكما ترى، تلك طريقة واحدة لاستعمال هذا التّابع، إذ يُمكنك استعمال <code>startswith</code> للحصول على جميع المقالات التّي تبدأ بالمقطع، ومن ثم تنقلها إلى مكان آخر بشكل آلي.
</p>

<h3>
	العامل <code>in</code>
</h3>

<p>
	يُستعمل العامل <code>in</code> للتّأكّد من أن سلسلة نصيّة أو قائمة في بايثون تحتوي على مقطع نصي معيّن. فمثلا، سنتأكّد من أن الحرف <code>a</code> يتواجد بكلمة <code>abcd</code>، وسنتأكّد في المثال الآخر من أنّ اسم المُستخدم <code>khalid</code> يتواجد ضمن قائمة <code>usernames</code>، بالإضافة إلى حالتين لعدم استيفاء الشّرط والحصول على القيمة المنطقيّة <code>False</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_10" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'a'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'abcd'</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'e'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">'abcd'</span><span class="pln"> 
</span><span class="kwd">False</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> usernames </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ahmed'</span><span class="pun">,</span><span class="pln">  </span><span class="str">'ibrahim'</span><span class="pun">,</span><span class="pln">
 </span><span class="str">'ali'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'mohammed'</span><span class="pun">]</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> usernames
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'youssuf'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> usernames
</span><span class="kwd">False</span></pre>

<p>
	إليك استخدامًا للعامل <code>in</code>:
</p>

<p>
	قلنا في الفقرة السّابقة أنك تستطيع نقل جميع المقالات التّي تبدأ بالمقطع "تحديث" إلى مدونة أخرى، لكن ماذا لو كانت مقالاتنا التّي تبدأ بهذا المقطع تُشير إلى أكثر من تطبيق واحد؟ لنقل بأنّ المدونة حاليا بها تحديثات لتطبيقين، تطبيق "كلمة" وتطبيق آخر، وكلاهما يحصلان على تحديثات ومقال لكل تحديث، هذا يعني بأنّ الحصول على المقالات التّي تبدأ بالمقطع "تحديث" ستكون مزيجا بين تحديثات التّطبيقين، ولكنّنا نرغب بنقل مقالات التطبيق "كلمة" إلى مدونة "كلمة" دون المقالات الخاصّة بالتّطبيق الآخر.
</p>

<p>
	نستطيع هنا مزج كل من <code>startswith</code> و<code>in</code> و<code>and</code> للوصول إلى مُرادنا، بحيث نتأكّد من أنّ عناوين المقالات التّي سنحصل عليها تبدأ بكلمة "تحديث" وفي نفس الوقت تحتوي على اسم التّطبيق "كلمة" وإليك مثالا بسيطا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_12" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> kalima_update </span><span class="pun">=</span><span class="pln"> </span><span class="str">'تحديث في تطبيق كلمة'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> app_update </span><span class="pun">=</span><span class="pln"> </span><span class="str">'تحديث في تطبيق آخر'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> kalima_update</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'تحديث'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'كلمة'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln">  kalima_update
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> app_update</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'تحديث'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">'كلمة'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln">  app_update
</span><span class="kwd">False</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> app_update</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'تحديث'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'كلمة'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln">  kalima_update
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'كلمة'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln">  app_update
</span><span class="kwd">False</span></pre>

<p>
	كما تُلاحظ، استخدمنا كلًا من <code>startswith</code> مع <code>and</code> و<code>in</code> لنستطيع ترشيح عنوان المقال الذي يحمل تحديثا للتطبيق "كلمة" من العنوان الآخر.
</p>

<p>
	هذا مجرّد مثال على كيفيّة الاستفادة من مختلف الأدوات التّي توفّرها لنا لغة بايثون وكيفيّة مزجها لحل مشاكل تحدث على الواقع، وسنرى فيما بعد كيفيّة استخدام هذه الجمل التّي تُرجع حاليا القيمتين <code>True</code> و<code>False</code> فقط لترشيح بياناتنا في قاعدة البيانات باستعمال SQLAlchemy.
</p>

<h3>
	التابع <code>endswith</code>
</h3>

<p>
	يُطبّق التّابع <code>endswith</code> على السّلسلة النّصيّة للتأكّد من أنّ سلسلة نصيّة <em>تنتهي</em> بمقطع معيّن، على سبيل المثال، يُمكن أن نتأكّد من أنّ بريدا إلكترونيّا ينتهي بـ<code>example.com</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_14" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'abdelhadi@example.com'</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'example.com'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="str">'abdelhadi@gmail.com'</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'example.com'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	لاحظ أن البريد الإلكتروني الأول ينتهي بـ<code>example.com</code> لذا تحقّق الشّرط وأرجع مُفسّر بايثون القيمة <code>True</code>، أمّا الثّاني فينتهي بـ<code>gmail.com</code> وليس <code>example.com</code> لذا أُرجِعّت القيمة المنطقيّة <code>False</code>.
</p>

<p>
	إن تساءلت عن الفائدة من هذا الأمر على الواقع، فإليك السيناريو التّالي: لنقل مثلا بأنّ خدمة example.com ستلغي خدمات بريدها الإلكتروني وسيتوجّب عليك تنبيه جميع مُستخدميك لتنصحهم بالانتقال إلى خدمة بريد إلكتروني أخرى، يُمكنك مثلا أن تستعمل هذه الطّريقة للحصول على جميع المُستخدمين الذين سجّلوا ببريد إلكتروني من هذه الخدمة، ومن ثم تستطيع تنبيههم وحدهم دون المُستخدمين الآخرين. لا شك أن هناك أمثلة كثيرة أخرى على الواقع، وستجد تحديّات ومشاكل يُمكنك حلّها بمثل هذه الأدوات التّي توفّرها لغة بايثون.
</p>

<h2>
	ترشيح البيانات التي نحصل عليها من قاعدة البيانات باستعمال شروط منطقية عبر مكتبة SQLAlchemy
</h2>

<p>
	في السّابق، كنّا نستعمل التّابع <code>filter_by</code> للحصول على سجل أو عدّة سجلّات عند تَطابُقِ قيمة عمود معيّن مع القيمة المُمرّرة، فمثلا لو أردنا الحصول على مُستخدم يُطابق اسمه السّلسلة النّصيّة <code>khalid</code> يُمكن أن نستعمل التّابع <code>filter_by</code> مع تمرير السّلسلة النّصيّة إلى المعامل <code>name</code> والذي يمثّل اسم العمود في هذه الحالة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_16" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></pre>

<p>
	في الشّيفرة أعلاه، كل ما نفعله هو طلب سجل من قاعدة البيانات في كل مكان تُساوي فيه قيمة العمود <code>name</code> السّلسلة النّصيّة "khalid”. أي كأنّنا نقول: أعطني السّجل الذي يُرجع طَلبُه القيمة المنطقيّة <code>True</code> عند تنفيذ الجملة التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_18" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'khalid'</span></pre>

<p>
	وبالمثل يُمكن أن تستخدم filter_by مع بقيّة الأعمدة.
</p>

<p>
	يُعد التّابع <code>fliter_by</code> جيدًا في حالات كثيرة كالوصول إلى مستخدم عن طريق اسمه أو بريده الإلكتروني، أو حتى مقال عبر عنوانه، لكن ماذا لو أردنا إجراء عمليّات أكثر تقدّما، مثل الحصول على السّجلات التّي تبدأ أو تنتهي بمقطع نصي معيّن أو تلك التّي تحتوي بداخلها على مقطع ما، أو الوصول إلى جميع السّجلات التّي تحقّق مجموعة من الشّروط أو بعضها؟
</p>

<h2>
	التابع <code>filter</code>
</h2>

<p>
	في SQLAlchemy يُمكنك استعمال التّابع <code>filter</code> للحصول على نتائج تستوفي شروطا معيّنة تُمرّر إلى هذا التّابع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_20" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column </span><span class="pun">==</span><span class="pln"> value</span><span class="pun">)</span></pre>

<p>
	لدينا ثلاثة متغيّرات يُمكنك استبدالها هنا لتتحصّل على نتيجتك المرغوبة: <code>Table</code> هو اسم الصّنف المرتبط بالجدول الذي ترغب بالحصول على البيانات منه، و<code>column</code> يُمثّل اسم العمود، أمّا <code>value</code> فتمثّل القيمة.
</p>

<p>
	وكما تلاحظ، فهذا التّعبير شبيه جدّا بالتّابع <code>filter_by</code> لأنّ الشّرط هو ما إذا كانت قيمة العمود تُساوي كذا. أمّا للوصول إلى نتائج متنوّعة فتستطيع استبدال العامل <code>==</code> لكتابة شروط منطقيّة أخرى، وإليك بعض الأمثلة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_22" style="">
<span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column </span><span class="pun">==</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column </span><span class="pun">&lt;</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column </span><span class="pun">&gt;</span><span class="pln"> value</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">
</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span></pre>

<p>
	يُمكنك أن تعوض المتغيّر <code>value</code> بقيمة عمود آخر من الجدول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_24" style="">
<span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column2</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">.</span><span class="pln">column2</span><span class="pun">))</span></pre>

<p>
	بعد ترشيح السّجلات، يُمكنك بعد ذلك تطبيق كل من <code>all</code> أو <code>first</code> على النّتيجة. لاحظ في هذا المثال كيف أنّ كلّا من <code>filter</code> و <code>filter_by</code> يرجعان نفس النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_26" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></pre>

<p>
	وكذلك يتّبع <code>get</code> نفس المنهج لكنّه لا يحتاج إلى التّابع <code>first</code> لأنّ المعروف أنّ المفتاح الأولي لا يُمكن أن يحمل من طرف أكثر من سجل واحد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_28" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> dyouri@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> dyouri@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> dyouri@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></pre>

<h3>
	ترشيح السجلات عن طريق <code>in</code>
</h3>

<p>
	قد تُفكّر في تطبيق العامل <code>in</code> للحصول على سجلات تتواجد إحدى قيم أعمدتها في قائمة ما، لكنّ SQLAlchemy لن يقبل العامل <code>in</code> الذي توفّره لنا لغة بايثون، وعليه لن تحصل على أيّة نتيجة.
</p>

<p>
	يُمكنك تنفيذ التّابع <code>in_</code> في SQLAlchemy مع تمرير قائمة من القيم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_30" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">in_</span><span class="pun">([</span><span class="str">'abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user4'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user5'</span><span class="pun">])).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">



</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user4 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user4@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user5@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<p>
	لاحظ كيف طبّقنا التّابع <code>in_</code> كقيمة ممرّرة للتّابع <code>filter</code>:
</p>

<pre class="ipsCode">
Table.column.in_(list)
</pre>

<p>
	أمّا كل من <code>startswith</code> و <code>endswith</code> فلا تتغيّر ويُمكنك استخدامها كما وضّحت سابقا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_32" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'abd'</span><span class="pun">)).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'lid'</span><span class="pun">)).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></pre>

<p>
	تعلّمنا الآن كيفيّة الحصول على سجلّات تبدأ أو تنتهي أحد قيم أعمدتها بمقطع معيّن، لكن ماذا لو أردنا الحصول على السّجلات التي تحتوي على مقطع معيّن في أي مكان من النّص؟
</p>

<p>
	توفّر لنا مكتبة SQLAlchemy طريقة للحصول على السّجلات التّي تحتوي على مقطع معيّن بغض النّظر عن مكان تواجد هذا المقطع (سواء كان في بداية السّلسلة النّصيّة أو وسطها أو نهايتها)، وذلك باستعمال <code>contains</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_34" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'d'</span><span class="pun">)).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">

</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> dyouri@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<p>
	كما تلاحظ فقد حصلنا على جميع المُستخدمين الذين تحتوي أسماءهم على الحرف <code>d</code> سواء أكان في بداية الاسم أو في آخره أو وسطه.
</p>

<h3>
	ترشيح السجلات بأكثر من شرط واحد
</h3>

<p>
	قد تود عند استعمال <code>filter</code> أن تحصل على نتائج تُحقّق أكثر من شرط واحد، وعلى سجل أو سجلّات تستوفي العديد من الشّروط (مثل الحصول على كل مُستخدم انضمّ قبل شهر واحد وأضاف أكثر من 10 مقالات).
</p>

<p>
	وغالبًا ستستعمل <code>and</code> التّي توفّرها لغة بايثون، لكن كما الحال مع <code>in</code> فمكتبة SQLAlchemy توفّر بديلا لها، والبديل هو الدّالة <code>and_</code> في SQLAlchemy والتّي نصل إليها عن طريق الكائن <code>db</code>. إليك مثالا لطريقة القيام بالأمر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_36" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">condition1</span><span class="pun">,</span><span class="pln"> condition2</span><span class="pun">))</span></pre>

<p>
	مع استبدال <code>condition1</code> بالشّرط الأول و <code>condition2</code> بالشّرط الثّاني.
</p>

<p>
	وبما أنّ <code>and_</code> شبيهة بجملة <code>and</code> في لغة بايثون فالمتوقّع أنّ حالة تحقّق الشّرطين معا هي الحالة الوحيدة التي يُمكن أن تُرجع نتيجة من الجدول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_40" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	لنفترض أنّنا نُريد الحصول على أول مُستخدم يبدأ اسمه بكلمة <code>abd</code> وفي نفس الوقت يكون رقم مُعرّفه أكبر من الرّقم <code>1</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_38" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
</span><span class="pun">...</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'abd'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">...</span><span class="pln">  </span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></pre>

<p>
	كما تُلاحظ، حصلنا على المُستخدم عبدالهادي لأنّه يستوفي الشّرطين، فرقم المعرفّ الخاص بالمُستخدم هو 2 أي أنّه أكبر من 1، ثمّ إنّ اسم المُستخدم يبدأ بالمقطع <code>abd</code> بكل تأكيد. يُمكنك كذلك استخدام <code>filter</code> أكثر من مرّة لتطبيق العديد من الشّروط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_42" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
</span><span class="pun">...</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">startswith</span><span class="pun">(</span><span class="str">'abd'</span><span class="pun">)).</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
</span><span class="pun">...</span><span class="pln">  </span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id
</span><span class="lit">2</span></pre>

<p>
	لاحظ هنا بأنّ النّتيجة هي نفسها، أي أنّ كلّا من <code>db.and_</code> و استعمال <code>filter</code> أكثر من مرّة له نفس المفعول وشخصيّا أرى أنّ استعمال <code>db.and_</code> أفضل وأسهل.
</p>

<p>
	يُمكنك كذلك استخدام الدّالّة <code>or_</code> للحصول على شرط يستوفي إمّا هذا الشّرط أو ذاك، وهو شبيه بجملة <code>or</code> في بايثون، وإليك تذكيرا بسيطا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_44" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	يعني لو أردنا الحصول على مُستخدم ينتهي اسمه بالحرف <code>d</code> أو رقم مُعرّفه يُساوي 10 لكتبنا استعلامنا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_46" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
  db</span><span class="pun">.</span><span class="pln">or_</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'d'</span><span class="pun">),</span><span class="pln">
  </span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">==</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">


</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">id
</span><span class="lit">1</span></pre>

<p>
	لاحظ بأنّ الشّرط الثّاني خاطئ، ومع ذلك حصلنا على المُستخدم خالد لأنّ الشّرط الأول صحيح، لو استخدمت <code>and_</code> هنا لكانت النّتيجة عبارة عن القيمة <code>None</code> أو بمعنى آخر لا نتيجة لهذا الاستعلام وهذا لأنّ الشّرط الثّاني خاطئ.
</p>

<h3>
	مزج and و or معًا
</h3>

<p>
	كما رأينا سابقا، يُمكنك وضع شروط معقّدة بمزج <code>and</code> و <code>or</code> أكثر من مرّة داخل بعضها البعض كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_48" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span></pre>

<p>
	الشّرط الأول في الشيفرة أعلاه ينتِج القيمة <code>True</code>، والثّاني يُنتج القيمة <code>False</code>، يعني كأنّنا نقول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_50" style="">
<span class="kwd">True</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span></pre>

<p>
	ومن ثم فالخرج هو القيمة المنطقيّة <code>True</code>. يُمكنك أن تأخذ هذا المبدأ إلى أبعد الحدود لتكتب شروطًا أكثر تعقيدًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_52" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">((</span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">))</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">((</span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">))</span><span class="pln">
</span><span class="kwd">False</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	أعتقد بأنّني بالغت في مزج كل هذه الشّروط، لكنّني أشعر بأنّ فهم طريقة العمل هذه مُهمّة، خاصّة إن كنت تخطّط لقراءة شيفرة مشروع مفتوح المصدر.
</p>

<p>
	قد لا تحتاج أبدا إلى مزج كل من <code>or</code> و <code>and</code> لإنشاء شروط معقّدة في SQLAlchemy، لكنّي رأيت أن أمنحك مثالا لكيفيّة القيام بالأمر، ولا بأس إن لم تفهم المثال الآن إذ أنّه يختلف بعض الشّيء عمّا تطرّقنا إليه سابقا، وستستطيع أن تفهمه ببعض من المُمارسة.
</p>

<p>
	إليك مثالا على كيفيّة مزج <code>and</code> و <code>or</code> في SQLAlchemy:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_54" style="">
<span class="pln">db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">or_</span><span class="pun">(</span><span class="pln">
        condition1</span><span class="pun">,</span><span class="pln"> condition2
       </span><span class="pun">),</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">
        condition3</span><span class="pun">,</span><span class="pln"> condition4
       </span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لاحظ بأنّك تستطيع وضع الشّروط في مُتغيّرات لتعمل الشّيفرة السّابقة، مثلا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_56" style="">
<span class="pln">condition1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pln">
condition2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'username'</span><span class="pln">
condition3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
condition4 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'example.com'</span><span class="pun">)</span></pre>

<p>
	هذا كأنّنا نقول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_58" style="">
<span class="pun">(</span><span class="pln">condition1 </span><span class="kwd">or</span><span class="pln"> condition2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">condition3 </span><span class="kwd">and</span><span class="pln"> condition4</span><span class="pun">)</span></pre>

<p>
	إن لاحظت بيانات المُستخدم khalid فستدرك بأنّ هذه الشّروط تتحقّق فيه. وفي الشّيفرة التّاليّة، أضع الشّروط في مُتغيّر باسم condition لأمرّرها فيما بعد إلى التّابع filter.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_60" style="">
<span class="pln">condition </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">or_</span><span class="pun">(</span><span class="pln">
        </span><span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'khalid'</span><span class="pun">,</span><span class="pln">  </span><span class="com"># True</span><span class="pln">
        </span><span class="typ">User</span><span class="pun">.</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="str">'username'</span><span class="pln">  </span><span class="com"># False</span><span class="pln">
       </span><span class="pun">),</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">and_</span><span class="pun">(</span><span class="pln">
        </span><span class="typ">User</span><span class="pun">.</span><span class="pln">id </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">  </span><span class="com"># True</span><span class="pln">
        </span><span class="typ">User</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="str">'example.com'</span><span class="pun">)</span><span class="pln">  </span><span class="com"># True</span><span class="pln">
      </span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لنجرّب الآن تمرير هذا الشّرط إلى مكتبة SQLAlchemy وللنَنظر هل هناك من مُستخدم يحقّق الشّروط المذكورة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4155_62" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">condition</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span></pre>

<p>
	جيد! كل شيء سار كما هو متوقّع، فالمُستخدم خالد هو الوحيد الذي يُحقّق جميع الشّروط.
</p>

<h2>
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة استعمال التابع <code>filter</code> في مكتبة SQLAlchemy لترشيح السّجلات عند الحصول عليها من قاعدة البيانات باستعمال شروط منطقيّة متقدّمة. وسنتعرّف في الدرس القادم على كيفيّة استغلال ما تعلّمناه من حيل للتّعامل مع قواعد البيانات بطريقة أفضل.
</p>
]]></description><guid isPermaLink="false">829</guid><pubDate>Fri, 21 Feb 2020 16:45:46 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x628;&#x646;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642; Flask &#x648;&#x62A;&#x646;&#x634;&#x631;&#x647; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Docker &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 18.04</title><link>https://academy.hsoub.com/programming/python/flask/%D9%83%D9%8A%D9%81-%D8%AA%D8%A8%D9%86%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-flask-%D9%88%D8%AA%D9%86%D8%B4%D8%B1%D9%87-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-docker-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1804-r842/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/Flask-Docker.jpg.a84d8ab6fc6c9d987f8b7987a1a173f2.jpg" /></p>

<p>
	يعتبر <a href="https://academy.hsoub.com/devops/cloud-computing/docker/" rel="">دوكر Docker</a> من أشهر التطبيقات مفتوحة المصدر لإنشاء وإدارة ونشر استنساخ التطبيقات باستخدام الحاويات، فالحاوية هي حزمة تحتوي على متطلبات التطبيق للعمل على مستوى نظام التشغيل أي أن التطبيق المنشور باستخدام Docker يعمل في بيئته الخاصة ويُتعامل مع متطلباته بشكل منفصل.
</p>

<p>
	أما Flask فهو إطار ويب مصغّر (micro-framework) مبني باستخدام لغة بايثون، وتعود تسميته بالإطار المصغّر لأنه لا يحتاج إلى أدوات محدّدة أو مكونات إضافيّة لكي يعمل، بالإضافة إلى أنه يتميّز بالخفّة والمرونة وبدرجة عالية من التنظيم مما يجعل المبرمجين يفضلونه على بقية الإطارات.
</p>

<p>
	سيسمح لك نشر تطبيق Flask باستخدام Docker باستنساخ التطبيق على مختلف الخوادم بأقل إعدادات ممكنة، لذا سنرى كيفية إنشاء تطبيق Flask و نشره باستخدام Docker بالإضافة إلى كيفية تحديث التطبيق بعد نشره.
</p>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	لمتابعة هذا الدرس، ستحتاج إلى ما يلي:
</p>

<ul>
<li>
		مستخدم عادي - ليس جذر - مع صلاحيات sudo معّد باستخدام <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">هذا الدليل</a>
	</li>
	<li>
		خادم أوبنتو 18.04 مع Docker، يمكنك إعداده عن طريق اتباع الخطوات في <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04" rel="external nofollow">هذا الدرس</a> أو عن طريق استخدام ميّزة التثبيت الخاصة بـ DigitalOcean في <a href="https://www.digitalocean.com/docs/one-clicks/docker" rel="external nofollow">هذا الدرس</a>
	</li>
	<li>
		تثبيت Nginx بإتباع الخطوة الأولى من <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/" rel="">هذا الدرس</a>
	</li>
</ul>
<h2>
	الخطوة الأولى - إعداد تطبيق Flask
</h2>

<p>
	ستحتاج إلى إنشاء هيكل مجلدات تطبيقك، لذلك أنشئ مجلدًا في <code>‎/var/www</code> وسمّهِ على سبيل المثال TestApp:
</p>

<pre class="ipsCode">
sudo mkdir /var/www/TestApp
</pre>

<p>
	ثم انتقل إلى هذا المجلد باستخدام الأمر:
</p>

<pre class="ipsCode">
cd /var/www/TestApp
</pre>

<p>
	وبعد ذلك، أنشئ المجلد الرئيسي لتطبيق Flask:
</p>

<pre class="ipsCode">
sudo mkdir -p app/static app/templates
</pre>

<p>
	تشير راية <code>‎-p</code> إلى أن mkdir سينشئ المجلد مع جميع المجلدات الرئيسية غير الموجودة، وفي هذه الحالة، سينشئ mkdir مجلد الأب <code>app</code> حتى يتمكن من إنشاء مجلدات <code>static</code> و <code>templates</code> داخله.
</p>

<p>
	سيحتوي المجلد app على جميع الملفات المتعلّقة بتطبيق Flask مثل الواجهات (views) والمخططات الأوليّة (blueprints). فالواجهة هي الشيفرة البرمجيّة التي تكتبها للاستجابة إلى طلبات تطبيقك، أما المخططات الأوليّة فتنشئ مكونات التطبيق وتدعم الأنماط الشائعة داخل التطبيق أو عبر تطبيقات مختلفة.
</p>

<p>
	ستضع جميع الأصول مثل الصور وملفات CSS وملفات جافاسكربت في مجلد <code>static</code> ، وأما بالنسبة لقوالب HTML فستضعهم في مجلد <code>templates</code>.
</p>

<p>
	والآن، بعد أن أنشأنا هيكل المجلدات الأساسية، فسننشئ الملفات التي نحتاجها لتشغيل تطبيق Flask. أنشئ أولًا ملف <code>‎__init__.py</code> داخل مجلد <code>app</code>، سيجعل هذا الملف مفسر بايثون يتعامل مع مجلد <code>app</code> كحزمة.
</p>

<p>
	أنشئ ملف <code>‎__init__.py</code> باستخدام الأمر التالي:
</p>

<pre class="ipsCode">
sudo nano app/__init__.py
</pre>

<p>
	تسمح لك الحزم في بايثون بجمع الوحدات إلى مساحات أسماء منطقيّة أو تسلّسلات هرميّة لكي تتمكن من تقسيم الشيفرة البرمجيّة إلى كتل منفصلة قابلة للإدارة ذات وظائف معيّنة.
</p>

<p>
	بعد ذلك، ستضيف شيفرة برمجيّة إلى <code>‎__init__.py</code> لإنشاء نسخة من Flask واستدعاء المنطق الموجود في ملف <code>views.py</code>، والذي ستنشئه بعد إنهائك لهذا الملف. أضف الشيفرة البرمجيّة التاليّة إلى الملف الجديد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_14" style="">
<span class="kwd">from</span><span class="pln"> flask </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln">
app </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Flask</span><span class="pun">(</span><span class="pln">__name__</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> app </span><span class="kwd">import</span><span class="pln"> views</span></pre>

<p>
	ستنشئ الآن ملف <code>views.py</code> في مجلد <code>app</code>، سيحتوي هذا الملف على أغلب منطق التطبيق.
</p>

<pre class="ipsCode">
sudo nano app/views.py
</pre>

<p>
	بعد ذلك أضف هذه الشيفرة البرمجيّة إلى ملف <code>views.py</code>، ستُعيد هذه الشيفرة البرمجيّة السلسلة النصيّة ‎hello world!‎ إلى زوار صفحة الويب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_16" style="">
<span class="kwd">from</span><span class="pln"> app </span><span class="kwd">import</span><span class="pln"> app

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> home</span><span class="pun">():</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"hello world!"</span></pre>

<p>
	يسمى السطر <code>‎@app.route‎</code>‏ فوق الدالة بالمزخرِف ويعمل على تعديل الدالة التي بعده، وفي هذه الحالة، سيخبر المزخرِف Flask أي رابط URL ستنفّذ دالة <code>home‎‎()‎</code>، وأما بالنسبة إلى النص hello world المُعاد من الدالة home فسيظهر للمستخدم في المتصفّح.
</p>

<p>
	الآن، بعد الانتهاء من ملف <code>views.py</code>، فنحن مستعدين لإنشاء ملف <code>uwsgi.ini</code> الذي سيحتوي على إعدادات uWSGI لتطبيقنا وهذا الأخير عبارة عن خيار نشر لـ Nginx والذي هو خادم لكل من البروتوكول والتطبيق، أي يخدم بروتوكولات uWSGI و FastCGI و HTTP.
</p>

<p>
	استخدم الأمر التالي لإنشاء هذا الملف:
</p>

<pre class="ipsCode">
sudo nano uwsgi.ini
</pre>

<p>
	بعد ذلك، أضف هذه الإعدادات إلى الملف لإعداد خادم uWSGI:
</p>

<pre class="ipsCode">
[uwsgi]
module = main
callable = app
master = true
</pre>

<p>
	تعرّف هذه الشيفرة البرمجية الوحدة التي سيعمل منها تطبيق Flask، والتي هي في هذه الحالة ملف <code>main.py</code>، ولقد أشرنا إليه بـ main. وبالنسبة إلى خيار callable فهو يخبر uWSGI باستخدام نسخة من app المصدّر من التطبيق الرئيسي. ويسمح الخيار master للتطبيق أن يعمل دائمًا ولن يتوقف إلا لبعض الوقت عند إعادة تحميل التطبيق كاملًا.
</p>

<p>
	بعد ذلك، أنشئ ملف <code>main.py</code> ليكون مدخل تطبيقك، فالمدّخل يخبر uWSGI عن كيفية التعامل مع تطبيقك.
</p>

<pre class="ipsCode">
sudo nano main.py
</pre>

<p>
	والآن، أضف السطر التالي إلى الملف حيث أن هذا الأخير سيستدعي نسخة من Flask يسمى app من حزمة التطبيق التي أنشأناها سابقًا.
</p>

<pre class="ipsCode">
from app import app
</pre>

<p>
	وفي النهاية، أنشئ الملف <code>requirements.txt</code> لتحديد الاعتماديات التي سيثبتها مدير الحزم pip إلى نشر Docker الخاص بك:
</p>

<pre class="ipsCode">
sudo nano requirements.txt
</pre>

<p>
	أضف السطر التالي في الملف <code>‎/var/www/TestApp/app/requirements.txt</code> لإضافة Flask كتبعيّة:
</p>

<pre class="ipsCode">
Flask==1.0.2
</pre>

<p>
	يحدد هذا السطر نسخة Flask التي يجب تثبيتها، والتي هي في وقت كتابة هذا المقال، النسخة 1.0.2، ويمكنك التأكد من التحديثات على الموقع الرسمي لـ <a href="flask.pocoo.org" rel="">Flask</a>.
</p>

<p>
	والآن لقد أنتهيت من إعداد تطبيق Flask ومستعد لإعداد Docker.
</p>

<h2>
	الخطوة الثانية - إعداد Docker
</h2>

<p>
	سننشئ في هذه الخطوة ملفين، Dockerfile و <code>start.sh</code> لإنشاء نشر Docker الخاص بك، فملف Dockerfile هو مستند نصي يحتوي على الأوامر التي تُستخدم لتجميع الصورة (image) وأما بالنسبة لملف start.sh فهو سكربت shell الذي سيبني الصورة وسينشئ الحاوية من ملف Dockerfile.
</p>

<p>
	أنشئ أولًا ملف Dockerfile:
</p>

<pre class="ipsCode">
sudo nano Dockerfile
</pre>

<p>
	بعد ذلك، أضف إعداداتك التي ترغب بها إلى Dockerfile، ستحدّد هذه الأوامر كيف ترغب ببناء الصورة وكيف ستضاف المتطلبات الإضافيّة.
</p>

<ul>
<li>
		الملف <code>‎/var/www/TestApp/Dockerfile</code>:
	</li>
</ul>
<pre class="ipsCode">
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt
</pre>

<p>
	في هذا المثال، سنبني صورة Docker (أي image) من صورة موجودة بالفعل وهي tiangolo/uwsgi-nginx-flask ويمكنك إيجادها على <a href="https://hub.docker.com/r/tiangolo/uwsgi-nginx-flaskK" rel="external nofollow">DockerHub</a> وتعتبر هذه الصورة من أفضل الصور الموجودة لأنها تدعم العديد من نسخ بايثون بالإضافة إلى أنظمة التشغيل المختلفة.
</p>

<p>
	أول سطرين سيحددان الصورة الرئيسيّة التي ستستخدمها لتشغيل التطبيق وتثبيت معالج أوامر Bash والمحرّر النصي nano، وستثبت أيضًا عميل git للسحب والدفع إلى خدمات استضافة التحكّم بالإصدارات مثل GitHub و GitLab و Bitbucket. أما بالنسبة إلى ENV STATIC_URL /static فهو متغيّر البيئة الخاص بصورة Docker الحالية ويحدد الملف الثابت (static) الذي سيحتوي على جميع الأصول مثل الصور وملفات CSS و ملفات جافا سكربت.
</p>

<p>
	بالنسبة لآخر سطرين فستنسخ الملف requirements.txt إلى الحاوية ومن ثم ستثبّت التبعيات.
</p>

<p>
	والآن، بعد أن أنهينا ملف Dockerfile، أصبحنا مستعدين لإنشاء ملف start.sh الذي سيبني حاوية Docker، وقبل كتابة سكربت start.sh، تأكد من وجود منفذ (port) مفتوح لاستخدامه في الإعدادات، ويمكنك التأكد من ذلك عن طريق تشغيل الأمر التالي:
</p>

<pre class="ipsCode">
sudo nc localhost 56733 &lt; /dev/null; echo $?
</pre>

<p>
	إذا كانت مخرجات الأمر السابق هي 1 فهذا المنفذ مفتوح ويمكن استخدامه، وخلافا ذلك، ستحتاج إلى اختيار منفذ آخر لاستخدامه في ملف إعدادات start.sh.
</p>

<p>
	بمجرّد أن تجد منفذ مفتوح للاستخدام، أنشئ سكربت start.sh:
</p>

<pre class="ipsCode">
sudo nano start.sh
</pre>

<p>
	سيبني سكربت start.sh ملف <code>Dockerfile</code> وينشئ الحاوية من صورة Docker، ولهذا سنضيف إلى الملف ‎<code>‎/var/www/TestApp/start.sh</code>‎ الإعدادات التالية:
</p>

<pre class="ipsCode">
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
  --name=${app} \
  -v $PWD:/app ${app}
</pre>

<p>
	يسمى السطر الأول بـ shebang، وهو يحدد أن هذا الملف هو ملف bash وستُنفّذ أوامره، وأما السطر الثاني فيحدّد اسم الصورة والحاوية وستُحفظ على شكل متغيّر يسمى app. أما السطر التالي فيخبر Docker ببناء الصور من ملف Dockerfile الموجود في المجلّد الحالي، وفي هذا المثال، سينشئ صورة تسمى <code>docker.test</code>.
</p>

<p>
	الأسطر الثلاثة الأخيرة تنشئ حاوية تسمى docker.test والتي تعمل على المنفذ 56733، وفي النهاية، تربط المجلد الحالي بمجلد <code>‎‎‎/var/www</code> في الحاوية.
</p>

<p>
	يمكنك استخدام الراية <code>‎-d</code> لتشغيل الحاوية في وضع العفريت (daemon mode) أو كعملية خلفيّة (background process)، ويمكنك تضمين الراية <code>‎-p</code> لربط منفذ الخادم إلى منفذ معيّن في حاوية Docker، وفي هذه الحالة ستربط منفذ 59733 بمنّفذ 80 في حاوية Docker. بالنسبة إلى الراية <code>‎-v</code> ‏(volume) ‏فيحدد مكان Docker لوصله في الحاوية.
</p>

<p>
	شغّل سكربت <code>start.sh</code> لإنشاء صورة Docker وبناء حاوية من الصورة:
</p>

<pre class="ipsCode">
sudo bash start.sh
</pre>

<p>
	بمجرّد الانتهاء من الأمر السابق، استخدم الأمر التالي لعرض جميع الحاويات التي تعمل:
</p>

<pre class="ipsCode">
sudo docker ps
</pre>

<p>
	سيظهر لك شيء مشابه لهذا:
</p>

<pre class="ipsCode">
CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS              PORTS                           NAMES
58b05508f4dd        docker.test         "/entrypoint.sh /sta…"   12 seconds ago     Up 3 seconds    443/tcp, 0.0.0.0:56733-&gt;80/tcp   docker.test
</pre>

<p>
	سترى أن حاوية docker.test تعمل، والآن لنزور عنوان IP في المنفذ الذي اخترناه في متصفحك: <code>http://ip-address:56733</code>
</p>

<p>
	ستشاهد صفحة مشابهة لهذه الصفحة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_02/001HelloWorld.png.7ff3e49e85a0b299d3328ce4453253ef.png" data-fileid="34920" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="34920" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/001HelloWorld.png.7ff3e49e85a0b299d3328ce4453253ef.png" alt="001HelloWorld.png"></a>
</p>

<p>
	في هذه الخطوة نجحنا في نشر تطبيق Flask على Docker، سنستخدم في الخطوة التالية القوالب لعرض المحتوى إلى المستخدمين.
</p>

<h2>
	الخطوة الثالثة - خدمة ملفات القوالب
</h2>

<p>
	القوالب هي ملفات لعرض محتوى ثابت وحيوي لزوار تطبيقك، في هذه الخطوة، سننشئ قالب HTML لإنشاء الصفحة الرئيسية لتطبيقك.
</p>

<p>
	إبدأ بإنشاء ملف <code>home.html</code> في مجلد <code>app/templates</code>:
</p>

<pre class="ipsCode">
sudo nano app/templates/home.html
</pre>

<p>
	أضف الشيفرة البرمجية إلى قالبك لإنشاء صفحة HTML5 تحتوي على عنوان وبعض النصوص.
</p>

<ul>
<li>
		الملف <code>‎/var/www/TestApp/app/templates/home.html</code>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2978_21" style="">
<span class="dec">&lt;!doctype html&gt;</span><span class="pln">

</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en-us"</span><span class="tag">&gt;</span><span class="pln">   
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"x-ua-compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"ie=edge"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">Welcome home</span><span class="tag">&lt;/title&gt;</span><span class="pln">
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">

  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Home Page</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">This is the home page of our application.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	بعد ذلك، عدّل على ملف <code>app/views.py</code> لخدمة الملف المنشئ حديثًا:
</p>

<pre class="ipsCode">
sudo nano app/views.py
</pre>

<p>
	أضف أولا السطر التالي إلى بداية ملفك لإستدعاء أسلوب render_template من Flask والذي يرمّز صفحة HTML لتصيير (render) صفحة ويب للمستخدم.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_25" style="">
<span class="kwd">from</span><span class="pln"> flask </span><span class="kwd">import</span><span class="pln"> render_template
</span><span class="pun">...</span></pre>

<p>
	أضف مسار (route) آخر في نهاية الملف لتصيير ملف القالب حيث ستحدّد هذه الشيفرة البرمجية أن المستخدمين سيخدمون بمحتوى ملف <code>home.html</code> عند زيارة مسار <code>‎/template</code> في تطبيقك.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_23" style="">
<span class="pun">...</span><span class="pln">

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/template'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> template</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render_template</span><span class="pun">(</span><span class="str">'home.html'</span><span class="pun">)</span></pre>

<p>
	سيبدو ملف <code>app/views.py</code> بعد تحديثه كالتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_27" style="">
<span class="kwd">from</span><span class="pln"> flask </span><span class="kwd">import</span><span class="pln"> render_template
</span><span class="kwd">from</span><span class="pln"> app </span><span class="kwd">import</span><span class="pln"> app

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> home</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Hello world!"</span><span class="pln">

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/template'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> template</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render_template</span><span class="pun">(</span><span class="str">'home.html'</span><span class="pun">)</span></pre>

<p>
	من أجل تفعيل هذه التغييرات، ستحتاج إلى إيقاف وإعادة تشغيل حاويات Docker. شغّل الأمر التالي لإعادة بناء الحاوية:
</p>

<pre class="ipsCode">
sudo docker stop docker.test &amp;&amp; sudo docker start docker.test
</pre>

<p>
	زر تطبيقك الآن على <code>http://your-ip-address:56733/template</code> لمشاهدة خدمة القالب الجديد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_02/002HomePage.png.356569126f1ddbd589ac8daca61d7194.png" data-fileid="34921" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="34921" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/002HomePage.png.356569126f1ddbd589ac8daca61d7194.png" alt="002HomePage.png"></a>
</p>

<p>
	في هذه الخطوة أنشأت ملف قالب Docker لخدمة زوار تطبيقك وفي الخطوة القادمة سنرى كيف يمكنك تفعيل التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker.
</p>

<h2>
	الخطوة الرابعة - تحديث التطبيق
</h2>

<p>
	ستحتاج في بعض الأحيان إلى القيام ببعض التغييرات في تطبيقك مثل تثبيت متطلبات جديدة، تحديث حاوية Docker أو تغيير شيفرة HTML أو المنطق، لذلك، سنتحدّث الآن عن إعداد touch-reload للقيام بهذه التغييرات دون الحاجة إلى إعادة تشغيل حاوية Docker.
</p>

<p>
	يراقب بايثون autoreloading نظام الملفات للتغييرات وتحديث التطبيق عند إيجاد تغيير، وهذه العملية غير منصوح بها عند مرحلة الإنتاج (production) لأنها ستستهلك الكثير من الموارد. سنستخدم touch-reload لمراقبة التغييرات لملف معيّن وإعادة التحميل عند تحديث أو استبدال هذا الملف.
</p>

<p>
	لفعل ذلك، نبدأ بفتح ملف uwsgi.ini:
</p>

<pre class="ipsCode">
sudo nano uwsgi.ini
</pre>

<p>
	ونضيف هذا السطر الأخير إلى نهاية ملف <code>uwsgi.ini</code> كما هو موضح في الشيفرة التالية:
</p>

<pre class="ipsCode" id="ips_uid_2978_31">
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini</pre>

<p>
	يحدد هذا السطر الملف الذي يجب التعديل عليه لإعادة تحميل كامل التطبيق.
</p>

<p>
	لمشاهدة هذا، غيّر قليلا في تطبيقك، فعلى سبيل المثال، افتح ملف <code>app/views.py</code>:
</p>

<pre class="ipsCode">
sudo nano app/views.py
</pre>

<p>
	استبدل السلسلة النصيّة التي تعود من الدالة home:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2978_33" style="">
<span class="kwd">from</span><span class="pln"> flask </span><span class="kwd">import</span><span class="pln"> render_template
</span><span class="kwd">from</span><span class="pln"> app </span><span class="kwd">import</span><span class="pln"> app

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> home</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"&lt;b&gt;There has been a change&lt;/b&gt;"</span><span class="pln">

</span><span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/template'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> template</span><span class="pun">():</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render_template</span><span class="pun">(</span><span class="str">'home.html'</span><span class="pun">)</span></pre>

<p>
	والآن، إذا فتحت الصفحة الرئيسية لتطبيقك على <code>http://ip-address:56733</code> ستلاحظة عدم ظهور التغييرات، وهذا بسبب أن شرط إعادة التحميل هو تغيير ملف <code>uwsgi.ini</code>، لذا استخدم touch لتفعيل هذا الشرط:
</p>

<pre class="ipsCode">
sudo touch uwsgi.ini
</pre>

<p>
	أعد تحميل صفحة الرئيسية في تطبيقك على متصفحك مرّة أخرى، ستظهر لك التغييرات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2020_02/003ThereHasBeenAChange.png.2db6dbef2fa094a4bbc2571bf028484f.png" data-fileid="34922" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="34922" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_02/003ThereHasBeenAChange.png.2db6dbef2fa094a4bbc2571bf028484f.png" alt="003ThereHasBeenAChange.png"></a>
</p>

<p>
	في هذه الخطوة، أعددت شرط touch-reload لتحديث تطبيقك بعد القيام بتغييرات.
</p>

<h2>
	الخلاصة
</h2>

<p>
	في هذا الدرس، أنشأت ونشرت تطبيق Flask على حاوية Docker، ولقد أعددّت touch-reload لإعادة تحميل التطبيق دون الحاجة إلى إعادة تشغيل الحاوية.
</p>

<p>
	يمكنك الآن التوسع أكثر واكتشاف Docker بطريقة معمّقة، ويمكنك البدء <a href="https://docs.docker.com/" rel="external nofollow">بالتوثيق الرسمي</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-build-and-deploy-a-flask-application-using-docker-on-ubuntu-18-04" rel="external nofollow">How To Build and Deploy a Flask Application Using Docker on Ubuntu 18.04</a> لصاحبه Michael Okoh
</p>
]]></description><guid isPermaLink="false">842</guid><pubDate>Fri, 28 Feb 2020 16:00:13 +0000</pubDate></item><item><title>&#x62A;&#x631;&#x62A;&#x64A;&#x628; &#x627;&#x644;&#x633;&#x62C;&#x644;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x62D;&#x62F; &#x645;&#x646; &#x639;&#x62F;&#x62F;&#x647;&#x627; &#x648;&#x627;&#x644;&#x62D;&#x635;&#x648;&#x644; &#x639;&#x644;&#x649; &#x633;&#x62C;&#x644;&#x627;&#x62A; &#x628;&#x634;&#x643;&#x644; &#x639;&#x634;&#x648;&#x627;&#x626;&#x64A; &#x641;&#x64A; SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%AD%D8%AF-%D9%85%D9%86-%D8%B9%D8%AF%D8%AF%D9%87%D8%A7-%D9%88%D8%A7%D9%84%D8%AD%D8%B5%D9%88%D9%84-%D8%B9%D9%84%D9%89-%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D8%A8%D8%B4%D9%83%D9%84-%D8%B9%D8%B4%D9%88%D8%A7%D8%A6%D9%8A-%D9%81%D9%8A-sqlalchemy-r828/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/26.jpg.be2ff00efbf15f2fa35320f540ea3ad9.jpg" /></p>

<p>
	بعد أن تعلمنا كيفية الحصول على السجلات على حدة باستعمال أرقام مُعرّفاتها إضافة إلى كيفية الحصول على جميع السجلات من جدول معيّن والحصول عليها حسب اسم عمود مُعيّن باستعمال التّابع <code>filter_by</code>، سنتعرّف في هذا الدّرس على كيفيّة ترتيب السّجلات، والحد من عدد السجلّات التي نحصل عليها من كل استعلام، وكذلك كيفيّة الحصول على سجلّات بشكل عشوائيّ، إضافة إلى مقدمة قصيرة في استعمال طرق مختلفة لترشيح النّتائج بشروط منطقيّة.
</p>

<h2>
	ترتيب السجلات حسب قيم عمود معين
</h2>

<p>
	تُرتَّب السجلات عادة في تطبيقات الويب حسب قيمة معيّنة، فقد تجد مقالات في مدونة ما مرتّبة حسب تاريخ إضافتها ومن ثم تحصل على آخر المقالات المُضافة أولا بأول، كذلك يمكن ترتيب المُستخدمين حسب أسمائهم أبجديا، وهناك العديد من الخيارات الأخرى لترتيب البيانات كما سترى بعد قليل.<br>
	ولترتيب البيانات حسب عمود معيّن، يمكنك استعمال التّابع <code>order_by</code> بعد <code>query</code> مع تمرير اسم العمود في الجدول بإحدى طريقتين، إمّا كسلسلة نصيّة أو باستخدام الصّنف ثمّ اسم العمود مع فصلهما بنقطة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_7" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> users1 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="str">"created_date"</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> users2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> users1 </span><span class="pun">==</span><span class="pln"> users2
</span><span class="kwd">True</span><span class="pln">  </span></pre>

<p>
	كما تُلاحظ، نفّذنا استعلامًا عن المُستخدمين ثمّ رتبناهم حسب تاريخ الإضافة بكلتا الطّريقتين، ثمّ حصلنا على جميع النّتائج بالتّابع <code>all</code>، بعدها نتأكد أنّ الطّريقتين تؤديان إلى نفس النّتيجة، والنّتيجة أنّ هذا الأمر صحيح. لنحصل الآن على أول نتيجة ولننظر هل التّرتيب صحيح أم لا:
</p>

<pre class="ipsCode">
&gt;&gt;&gt; user = User.query.order_by(User.created_date).first()
&gt;&gt;&gt; user
&lt;username: khalid | email: khalid@example.com &gt;  
</pre>

<p>
	التّرتيب صحيح كما ترى، فخالد هو أوّل مُستخدم أضفناه إلى قاعدة البيانات. طريقة التّرتيب حسب بقيّة الأعمدة بسيطة كذلك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_10" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">id</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">name</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">email</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">  </span></pre>

<p>
	لنطبّق على جدول المقالات كذلك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_14" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">id</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">title</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="lit">1</span><span class="pln"> content </span><span class="pun">&gt;</span><span class="pln">  </span></pre>

<p>
	لاحظ أنّ ترتيب القيم وفق عمودٍ يحتوي على سلسلة نصيّة يكون أبجديا، أمّا الأعمدة التّي تحمل أعدادا كقيمة فتُرتّب من أصغر عدد إلى الأكبر، أمّا التّاريخ فحسب الأقدم إلى الأحدث.
</p>

<p>
	<strong>ملاحظة:</strong> أستخدمُ التّابع <code>first</code> فقط لكي لا يكون الخرج كبيرا، ولو أردتَ جميع السّجلات على شكل قائمة فتستطيع استخدام التّابع <code>all</code>.
</p>

<h3>
	الترتيب عكسيّا
</h3>

<p>
	يبدو بأنّك لاحظت بأنّنا لم نصل بعد إلى كيفيّة ترتيب المقالات حسب الأحدث، وذلك لأنّ التّرتيب حسب التّاريخ يُرجع المقالات الأقدم. يُمكننا عكس التّرتيب في SQLAlchemy للحصول على المقالات الأحدث والمُستخدمين المُنضمّين حديثا، وذلك من بإضافة التّابع <code>desc</code> بعد اسم العمود:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_16" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">()).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user12 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user12@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span><span class="pln">  </span></pre>

<p>
	لاحظ بأنّنا حصلنا على المُستخدم <code>user12</code> وهو آخر مُستخدم أضيف باستعمال حلقة التّكرار في درس سابق. إن استعملت الطّريقة الأخرى في التّرتيب فتستطيع عكسه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_18" style="">
<span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="str">"created_date desc"</span><span class="pun">)</span><span class="pln">  </span></pre>

<p>
	هذا يعني أنّ السّطرين التّاليين سيُرجعان قائمتين، القائمة الأولى عبارة عن جميع المُستخدمين مُرتّبين حسب آخر مُستخدم أضيف إلى أقدم مُستخدم، والقائمة التّاليّة عبارة عن جميع المقالات المُضافة بنفس التّرتيب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_20" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">()).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">()).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  </span></pre>

<p>
	هكذا استطعنا الوصول إلى قائمة بالمقالات المُضافة حديثا وآخر المُستخدمين المُنضمّين، لكنّنا لا نمتلك سوى طريقتين للحصول على النّتائج، إمّا بالحصول على أول نتيجة أو جميع النّتائج، فكيف يُمكن الحصول على عدد معيّن فقط من السّجلات؟
</p>

<h2>
	تحديد الناتج بعدد معين من السجلات
</h2>

<p>
	لنقل بأنّ تطبيقنا وصل إلى آلاف المقالات والمُستخدمين، وبالتّالي فعرض جميع المُستخدمين المُنضمّين حديثا وأحدث المقالات سيجعل صفحتنا طويلة وقد يأخذ وقتا كبيرا، هذا بالإضافة إلى أنّه أمر غير ضروري.<br>
	قطعًا يُمكنك الحصول على جميع المقالات على شكل قائمة واستعمال لغة بايثون لتحديد جزء منها فقط (أول خمسة عناصر مثلا)، لكنّ الحصول على جميع السّجلات وإسنادها إلى مُتغيّر قد يأخذ مساحة كبيرة، وكذلك ستستغرق مُعالجتها وقتًا طويلا.
</p>

<p>
	وبما أنّ قواعد بيانات SQL تُمكّننا من الحصول على عدد معيّن من السجلّات بجملة <code>LIMIT</code> فمن الأفضل أن نستخدمها عوضا عن معالجة آلاف البيانات لعرض جزء صغير منها.
</p>

<p>
	ولتحديد عدد معيّن من النّتائج في SQLAlchemy، استعمل التّابع <code>limit</code> مع تمرير عدد صحيح كمُعامل ليُمثّل عدد النّتائج، فمثلا للحصول على خمسة مقالات وخمسة مُستخدمين فقط يُمكنك استخدام التّابع <code>limit()</code> مع تمرير العدد 5:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_22" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> five_posts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">5</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> five_users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">5</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  </span></pre>

<p>
	لاحظ أنّنا نستخدم التّابع <code>all</code> مرة أخرى للحصول على جميع النّتائج.
</p>

<p>
	سيحمل الآن كلا المُتغيّرين<code>five_posts</code> و <code>five_users</code> خمسة سجلّات في كل متغيّر، ويُمكنك أن تصل إلى كل سجل وبياناته من خلال استخدام حلقة <code>for</code> كما في السّابق. كذلك يُمكنك تغيير المُعامل المُمرّر إلى التّابع <code>limit</code> إلى أي عدد تريده:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_24" style="">
<span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">10</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">7</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">8</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">1</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">  </span></pre>

<p>
	لعلك لاحظت أننا نحصل في آخر سطر على سجل واحد فقط، يُمكنك استعمال هذه الطّريقة إن لم تكن مُهتما بالحصول على سجل مُعيّن من قاعدة البيانات (باستعمال إمّا <code>get</code> أو <code>filter_by</code>).
</p>

<h2>
	مزج ما سبق لنتائج أكثر دقة
</h2>

<p>
	الشّيء المُميّز في قواعد بيانات SQL هو أنّها تُوفّر لنا طريقة لمزج العديد من الشّروط في استعلام واحد، فمثلًا يُمكنك إخبار قاعدة البيانات أنّك تريد الحصول على مقالات مُستخدم رقم مُعرّفه كذا، لكن بدلًا من جلب جميع مقالاته، أعطني مقالين فقط.
</p>

<p>
	وتستطيع مزج التوابع في SQLAlchemy للحصول على هذه النّتيجة، فالسّطر التّالي مثلًا يستعلم عن المقالات من المُستخدم <code>abdelhadi</code> عن طريق رقم مُعرّفه، ثمّ يطبّق حدّا على النّتائج للحصول على سجلّين فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_26" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts_from_abdelhadi </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">author_id</span><span class="pun">=</span><span class="lit">2</span><span class="pun">).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  </span></pre>

<p>
	هنا مزجنا كلّا من التّابعين <code>filter_by</code> و<code>limit</code>، الأول للحصول على المقالات التّي يحمل عمود <code>author_id</code> فيها القيمة 2 (أي رقم مُعرّف المُستخدم عبد الهادي)، والثاني لحدّ النّتائج في مقالين فقط.<br>
	لاحظ أن التّابع <code>all</code> هو آخر ما يُضاف إلى الاستعلام للحصول على قائمة بجميع النّتائج، لذا لا تضعه والتّابع <code>first</code> في وسط الشّيفرة.
</p>

<p>
	وهذا مثال آخر نقوم فيه بترتيب المُستخدمين حسب تاريخ إضافتهم عكسيا ثمّ نُحدّد ثلاثة نتائج.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_28" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">User</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">.</span><span class="pln">desc</span><span class="pun">()).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">3</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user12 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user12@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user11 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user11@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user10 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user10@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span><span class="pln">  </span></pre>

<p>
	تلاحظ في الشّيفرة أعلاه أنّ الخرج قد رُتّب عكسيا حسب تاريخ الإضافة ثمّ حُدّد بثلاثة سجلّات فقط، يُمكنك تطبيق هذه الطّريقة في عدّة مواضع لعرض عدد محدّد من المُستخدمين المُنضمّين حديثا أو ترتيب المقالات حسب تاريخ إضافتها وتحديد عددها، وكذلك يمكنك إضافة تقييم لكل مقال وترتب المقالات حسب الأفضل (أي الأكثر تقييما إيجابيا).
</p>

<p>
	يُمكنك مزج ما تشاء من التّوابع للحصول على نتائج أكثر دقّة من قاعدة بياناتك، لكن احترس، فمكتبة SQLAlchemy لا تسمح بتطبيق بعض التّوابع إلّا بترتيب خاص، فمثلا لا يُمكنك وضع حدّ لعدد النّتائج قبل ترتيبها، أي أنّ الشّيفرة التّاليّة خاطئة:
</p>

<pre class="ipsCode">
User.query.limit(3).order_by(User.created_date).all()  
</pre>

<p>
	إن جرّبت تنفيذ الشّيفرة فستحصل على خطأ يُشبه نصّه ما يلي:
</p>

<pre class="ipsCode">
sqlalchemy.exc.InvalidRequestError: Query.order_by() being called on a Query which already has LIMIT or OFFSET applied. To modify the row-limited results of a  Query, call from_self() first.  Otherwise, call order_by() before limit() or offset() are applied.  
</pre>

<p>
	لذا تأكّد دائما من أنّك تُطبّق التّابع <code>limit</code> في مكانه الصّحيح، والأغلب أنّك ستحتاج إليه في آخر الشّيفرة لتحديد عدد النّتائج بعد إجراء العمليّات الأخرى. يُمكن أن تواجهك بعض المشاكل من هذا القبيل، فإن واجهتك فاقرأ نص الخطأ أولا ثمّ ابحث عن حل له في الويب، فإن لم تجد فيمكنك طرح سؤال في قسم الأسئلة والأجوبة في الأكاديميّة، وتأكّد أن تضع نص الخطأ كاملا والجزء الذي سبّب الخطأ من شيفرتك.
</p>

<h2>
	الحصول على سجلات بشكل عشوائي
</h2>

<p>
	يُمكن أن تجد نفسك بحاجة إلى بناء تطبيق يتطلّب الحصول على سجلّات من قاعدة البيانات بشكل عشوائي، صحيح أنك تستطيع استخدام بايثون والوحدة <code>random</code> للقيام بالأمر، لكن تذكر قولي أن استخدام بايثون لمعالجة بيانات كبيرة فكرة سيّئة، لذا لا تقم بذلك.
</p>

<p>
	الحصول على سجلّات بشكل عشوائي ممكن، لكن للأسف فالطّريقة مُختلفة في قواعد بيانات SQL المُتعدّدة، وبما أنّنا نستعمل هنا قاعدة البيانات PostgreSQL فسأشرح طريقة القيام بالأمر فيها فقط، وإن أردت الحصول على كيفيّة القيام بالأمر في قواعد البيانات الأخرى فيُمكنك الرّجوع إلى توثيق SQLAlchemy.<br>
	للحصول على سجلّات عشوائيّة في كلّ مرّة ننفّذ فيها الاستعلام في SQLAlchemy و PostgreSQL (نفس الطّريقة تعمل على SQLite كذلك) يُمكنك استعمال التّابع <code>func</code> المتواجد في الكائن<code>db</code> الذي أنشأناه بمُساعدة إضافة Flask-SQLAlchemy ، لذا إن لم تستورده فلن تعمل الشّيفرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_30" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user11 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">11</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user12 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">12</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">first</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> user7 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln">  </span></pre>

<p>
	الشّيفرة الأساسيّة لترتيب السّجلات بشكل عشوائي هي باستعمال التّابع func المتواجد في الكائن <code>db</code> ثمّ التّابع <code>random</code> مع تمرير كل شيء إلى التّابع <code>order_by</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_32" style="">
<span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">())</span><span class="pln">  </span></pre>

<p>
	لاحظ بأنّنا في كل مرّة نقوم فيها بتنفيذ الشّيفرة تختلف النّتيجة بشكل غير مُتوقّع. أيضًا، لعلك لاحظت أننا نقوم هنا بتطبيق التّابع <code>first</code> للحصول على أول سجل، ويُمكنك قطعًا الوصول إلى جميع السّجلات عبر التّابع <code>all</code>، وكذلك تحديد عدد من السّجلات بالتّابع <code>limit</code> بعد ترتيبها عشوائيّا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_34" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">3</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">    
</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user5@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user11 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user11@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">3</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">    
</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user9 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user9@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> abdelhadi@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> dyouri </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> dyouri@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()).</span><span class="pln">limit</span><span class="pun">(</span><span class="lit">3</span><span class="pun">).</span><span class="pln">all</span><span class="pun">()</span><span class="pln">  
</span><span class="pun">[&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user8 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user8@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user5 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user5@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;,</span><span class="pln">  
 </span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> user6 </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> user6@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;]</span><span class="pln">  </span></pre>

<p>
	النّتائج عشوائيّة كما ترى، وكل نتيجة تختلف عن النّتيجة السّابقة، لذا تستطيع الآن التّفكير في إضافة قسم بالتّطبيق الذي سنبنيه لعرض مقالات ومُستخدمين بشكل عشوائي لتُساعد زوارك على اكتشاف المقالات والمُستخدمين الذين لا يُمكن أن تصل إليهم إلا بهذه الطّريقة (مثل المقالات التي مرت عليها سنوات أو مُستخدمون لم يُشاركوا منذ مدّة طويلة حتى اختفوا من الصّفحات الرّئيسية).
</p>

<h2>
	ترشيح السجلات حسب شروط منطقية
</h2>

<p>
	لم تعد تطبيقات الويب بسيطة كالسابق حين كان المستخدم يطلب صفحة المقال فيحصل عليها، أما الآن فقد كثرت الخيارات المنطقية في التطبيقات، فبعد أن كانت خيارات المستخدم محدودة جدًا بين الحصول على المقالات بترتيب معيّن أو مقالات كاتب محدد، صارت تطبيقات الويب تُتيح للمُستخدم حريّة كبيرة في كيفيّة حصوله على النّتائج.<br>
	فالصّفحة والنّتائج المعروضة عليها يُمكن أن تتغيّر طبقا لعدّة شروط، وهناك خيارات كثيرة للحصول على نتائج دقيقة، فمثلا يُمكن أن يطلب المُستخدم مقالات أضيفت في شهر معيّن، أو الحصول على جميع المقالات المُضافة من السّنة الفلانيّة إلى يومنا الحالي، أو كل مقال يبدأ عنوانه بكلمة "تحديث" وفي نفس الوقت يكون كاتبه المُستخدم فلان بالإضافة إلى أنّه أضيف قبل 5 أيام مع وجوب تجاوزه المئة تعليق وهكذا…، وإن نظرنا إلى آخر مثال وحلّلناه فسنجد أنّه يحتوي على العديد من الشّروط المنطقيّة:
</p>

<p>
	فالمقال يبدأ بكلمة "تحديث” وكاتب المقال هو المُستخدم "فلان” وتاريخ إضافته قبل خمسة أيام وعدد تعليقاته مئة أو أكثر. لاحظ الآن كلّا من حرفي "و” و"أو” في التّحليل السّابق، هل يُذكّرك ذلك بشيء معيّن في لغة بايثون؟ الجواب هو المعاملات المنطقيّة <code>and</code> و<code>or</code>، التّي تعمل كما يلي:
</p>

<p>
	<strong><code>and</code></strong>: إن تحقّق هذا الشّرط <em>و</em> الشّرط الآخر فالجملة صحيحة، ولو تحقّق شرط دون آخر أو لم يتحقّق أي شرط فالجملة خاطئة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_36" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  </span></pre>

<p>
	<strong><code>or</code></strong>: إن تحقّق هذا الشّرط <em>أو</em> الشّرط الآخر فالجملة صحيحة إن كانت جميع الشّروط خاطئة فالجملة خاطئة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_38" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  </span></pre>

<p>
	لاحظ أن استعمال الأقواس أمر اختياري وستصل إلى نفس النّتيجة، لكن الأقواس مهمّة إن كنت تستعمل أكثر من عامل منطقي للتأكد من أنّ جملة تحتوي على العديد من الشّروط صحيحة بالفعل.
</p>

<p>
	يُمكنك استعمال أحدها أكثر من مرّة:
</p>

<pre class="ipsCode">
&gt;&gt;&gt; 1 == 2 or 2 == 3 or 3 == 3  
&gt;&gt;&gt; True  
&gt;&gt;&gt; 1 == 2 or 2 == 3 or 3 == 4  
&gt;&gt;&gt; False  
&gt;&gt;&gt;  2 == 2 and 3 == 3 and 4 == 4  
&gt;&gt;&gt;  True  
</pre>

<p>
	يُمكن مزج هذه الشّروط المنطقيّة الواحد داخل الآخر لتصل إلى نتائج أكثر دقّة أو نتائج تستوفي شروطا عديدة والقوانين هنا كقوانين الرّياضيّات البسيطة (ما بداخل القوسين منعزل عن بقيّة الجملة):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_40" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  </span></pre>

<p>
	يُمكنك كذلك اختبار هذه القواعد عبر استعمال كل من القيمتين <code>True</code> و <code>False</code> فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6534_42" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">    
</span><span class="kwd">True</span><span class="pln">  
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">True</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">  
</span><span class="kwd">True</span><span class="pln">  
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">False</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">  
</span><span class="kwd">False</span><span class="pln">  </span></pre>

<h2>
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة استعمال مكتبة SQLAlchemy لترتيب السّجلات والحدّ من عددها والحصول على سجلات عشوائيّا من قاعدة البيانات، و كذلك ألقينا نظرة على كيفيّة استعمال المعامليْن <code>and</code> و<code>or</code> في لغة بايثون، واللذيْن يُعدان أساسًا سنبني عليه بقية معارفنا في الدّروس القادمة للحصول على نتائج أكثر دقّة من قاعدة البيانات، ومن ثم إتاحة إمكانية ترشيح النّتائج لتجربة استخدام أكثر أريحيّة.
</p>
]]></description><guid isPermaLink="false">828</guid><pubDate>Fri, 21 Feb 2020 16:45:13 +0000</pubDate></item><item><title>&#x645;&#x644;&#x621; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x628;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x62A;&#x62C;&#x631;&#x64A;&#x628;&#x64A;&#x629; &#x648;&#x627;&#x644;&#x637;&#x631;&#x642; &#x627;&#x644;&#x645;&#x628;&#x62F;&#x626;&#x64A;&#x629; &#x644;&#x644;&#x62D;&#x635;&#x648;&#x644; &#x639;&#x644;&#x64A;&#x647;&#x627; &#x641;&#x64A; SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D9%85%D9%84%D8%A1-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A8%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%AA%D8%AC%D8%B1%D9%8A%D8%A8%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%B7%D8%B1%D9%82-%D8%A7%D9%84%D9%85%D8%A8%D8%AF%D8%A6%D9%8A%D8%A9-%D9%84%D9%84%D8%AD%D8%B5%D9%88%D9%84-%D8%B9%D9%84%D9%8A%D9%87%D8%A7-%D9%81%D9%8A-sqlalchemy-r827/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_02/25.jpg.c2d2627121101273dd3ef088493c49d4.jpg" /></p>

<p>
	تعرّفنا في <a href="https://academy.hsoub.com/tags/flask_cms/" rel="">الدّروس السّابقة</a> على ماهيّة أداة SQLAlchemy وكيفيّة الاعتماد عليها في تطبيقات Flask باستعمال إضافة Flask-SQLAlchemy للتعامل مع قواعد بيانات SQL، وسنتعرّف في هذا الدّرس على كيفيّة ملء قاعدة البيانات التي أنشأناها ببيانات تجريبيّة وكذلك كيفيّة الحصول على السّجلات من قاعدة البيانات باستعمال لغة بايثون.
</p>

<h2>
	إضافة عدة سجلات في نفس الوقت
</h2>

<p>
	قد ترغب أحيانا في إضافة أكثر من سجل في نفس الوقت، إمّا لأنّك تحصل على الكثير من السّجلات من نفس الزّائر في صفحتك أو أنّك ترغب في توفير بعض الوقت والأسطر البرمجيّة، ولإضافة أكثر من كائن إلى الجلسة، استعمل التّابع <code>add_all</code> عوضا عن <code>add</code>، وذلك عبر تمرير قائمة من الكائنات إلى التّابع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_8" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">'abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'abdelhadi@example.com'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'secret_pass'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">'dyouri'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dyouri@example.com'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'p_not_found'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> users_list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">user2</span><span class="pun">,</span><span class="pln"> user3</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add_all</span><span class="pun">(</span><span class="pln">users_list</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span></pre>

<p>
	كذلك يُمكنك تمرير القائمة مُباشرة دون إسنادها إلى متغيّر سابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_10" style="">
<span class="pln">db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add_all</span><span class="pun">([</span><span class="pln">user2</span><span class="pun">,</span><span class="pln"> user3</span><span class="pun">])</span></pre>

<p>
	إن عُدت الآن إلى أداة <code>psql</code> ونفّذت الاستعلام <code>select</code> للحصول على جميع المُستخدمين فستجد أنّ المُستخدمَيْن <code>abdelhadi</code> و <code>dyouri</code> قد أُضيفا إلى قاعدة البيانات بنجاح. لِنُضف بضعة مقالات لكل مُستخدم من المُستخدمين اللّذين أضفناهما للتو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_12" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> post2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'a post from abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'content of a post'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'another post from abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'some other content for the post'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post4 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'a post from dyouri'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'other content'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts_list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">post2</span><span class="pun">,</span><span class="pln"> post3</span><span class="pun">,</span><span class="pln"> post4</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add_all</span><span class="pun">(</span><span class="pln">posts_list</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span></pre>

<p>
	<strong>لاحظ</strong> أنك إن أضفت وحذفت بضعة مُستخدمين من قاعدة بياناتك قبل تنفيذ الشّيفرة، فقد يكون مُعرّف كلا المُستخدمَيْن مغايرا لما حدّدته بالشّيفرة أعلاه، لذا تأكّد من أنّ الأرقام صحيحة.<br>
	كذلك يمكنك إضافة المقالات والمُستخدمين بشكل مُختلط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_14" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add_all</span><span class="pun">([</span><span class="pln">user2</span><span class="pun">,</span><span class="pln"> user3</span><span class="pun">,</span><span class="pln"> post2</span><span class="pun">,</span><span class="pln"> post3</span><span class="pun">])</span></pre>

<h2>
	استغلال حلقة For لإضافة عدة سجلات
</h2>

<p>
	سنحتاج في هذا الدّرس إلى العديد من السّجلات في قاعدة البيانات من أجل التجربة عليها سواء تعديلا أو قراءة أو حتى حذفًا، بإمكاني أن أطلب منك إضافة بضعة مُستخدمين وبضعة مقالات مُستفيدا مما تعلّمته سابقا (أتمنى أنّك فعلت ذلك بالفعل) لكن الأمر سيأخذ بعض الوقت، ونحن لا يهمنا أسماء المُستخدمين ولا بيانات المقالات، بل كل ما نُريده هو بيانات مزيّفة لأغراض تجريبيّة، لذا لمَ لا نستغل البرمجة في شيء مُفيد ونُضيف المُستخدمين والمقالات بحلقة <code>for</code> بحيث يكون لكل سجل من البيانات رقم يميزه عن السّجلات الأخرى، أي سنضيف مُستخدمين بالأسماء التّاليّة:
</p>

<pre class="ipsCode">
user1, user2, user3, user4 ...
</pre>

<p>
	<strong>جرب حل الاختبار دون النظر إلى الشيفرة التالية</strong>: اكتب حلقة لإضافة مُستخدمين ومقالات بالطّريقة السّابقة.
</p>

<p>
	<strong>الحلّ</strong>
</p>

<p>
	الشّيفرة التّي سنُضيف بها المُستخدمين ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_16" style="">
<span class="kwd">for</span><span class="pln"> u </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'user{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> </span><span class="str">'user{}@example.com'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln">  </span><span class="str">'password{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> email</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span></pre>

<p>
	وهذه لإضافة مقال لكل مُستخدم من المُستخدمين :
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_18" style="">
<span class="kwd">for</span><span class="pln"> p </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">):</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Post from user{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Content {}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">
    author_id </span><span class="pun">=</span><span class="pln"> p
    post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> author_id</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">post</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span></pre>

<p>
	تفترض شيفرة المقالات أنّ آخر مُستخدم تمت إضافته أو حذفه من جدول المُستخدمين يمتلك الرقم المُعرّف <code>3</code>، مما يعني أنّ المُستخدم <code>user4</code> الذي يُعد أول مُستخدم يُضاف باستخدام حلقة التّكرار سيكون رقمُ مُعرّفه <code>4</code>.
</p>

<p>
	<strong>مُلاحظة:</strong> سنحذف كثيرًا من المُستخدمين والمقالات التّي أضفناها للتو فيما بعد، لذا توجّب علينا إضافة هذا العدد، كما يجب عليك إدراك أنّ تطبيقات الويب الحاليّة تستطيع جمع كم هائل من البيانات دون أن يؤثّر ذلك على الأداء بشكل ملحوظ، لذا لا تخف من اختبار قاعدة بياناتك بحلقات التّكرار لإضافة وحذف العديد من البيانات.
</p>

<h2>
	الحصول على البيانات، والطرق المختلفة للتحكم بالنّتائج
</h2>

<p>
	إن اتّبعت ما سبق وأضفت المُستخدمين والمقالات التّي أضفناها لقاعدة البيانات فسيكون لديك الآن في قاعدة بياناتك العديد من المقالات والمُستخدمين، وسنتمكّن من الحصول على هذه البيانات لقراءتها والتّعامل معها بعمليّات CRUD الأخرى.
</p>

<p>
	والبيانات التّي تتواجد في قاعدة بياناتنا الآن هي كالآتي:
</p>

<pre class="ipsCode">
Users:  
 id |   name    |
----+-----------+
  1 | khalid    |
  2 | abdelhadi |
  3 | dyouri    |
  4 | user4     |
  5 | user5     |
  6 | user6     |
  7 | user7     |
  8 | user8     |
  9 | user9     |
 10 | user10    |
 11 | user11    |
 12 | user12    |

-----------------

Posts:  
 id |            title            |
----+-----------------------------+
  1 | Post 1                      |
  2 | a post from abdelhadi       |
  3 | another post from abdelhadi |
  4 | a post from dyouri          |
  5 | Post from user4             |
  6 | Post from user5             |
  7 | Post from user6             |
  8 | Post from user7             |
  9 | Post from user8             |
 10 | Post from user9             |
 11 | Post from user10            |
 12 | Post from user11            |
 13 | Post from user12            |
</pre>

<p>
	مُجدّدا، تجاهلت الأعمدة الأخرى لأنّها غير مهمّة، كما أنّ الجدول سيكون كبيرا إن لم أتجاهلها، وتستطيع الحصول على البيانات كاملة إن شئت عبر أداة <code>psql</code> وأمريْ <code>select</code> السّابقين.
</p>

<p>
	لا بأس إن لم تمتلك نفس البيانات في قاعدة بياناتك، فالمهم أن تفهم العلاقة الأساسيّة بين كلّ مقال والمُستخدم الذي أضافه. أمّا إن كنت ترغب اتّباع هذا الدّرس بحذافيره، فنفِّذ الشيفرة التالية لحذف جميع بياناتك وإضافة البيانات أعلاه.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_21" style="">
<span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
db</span><span class="pun">.</span><span class="pln">drop_all</span><span class="pun">()</span><span class="pln">
db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">
db</span><span class="pun">.</span><span class="pln">create_all</span><span class="pun">()</span><span class="pln">
db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">

user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">'khalid'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'khalid@example.com'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'password'</span><span class="pun">)</span><span class="pln">
user2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">'abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'abdelhadi@example.com'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'secret_pass'</span><span class="pun">)</span><span class="pln">
user3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="str">'dyouri'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dyouri@example.com'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'p_not_found'</span><span class="pun">)</span><span class="pln">
post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'Post 1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'post 1 content'</span><span class="pun">,</span><span class="pln"> author_id</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
post2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'a post from abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'content of a post'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
post3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'another post from abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'some other content for the post'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
post4 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="str">'a post from dyouri'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'other content'</span><span class="pun">,</span><span class="pln"> author_id </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln">

db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add_all</span><span class="pun">([</span><span class="pln">user</span><span class="pun">,</span><span class="pln">
                user2</span><span class="pun">,</span><span class="pln">
                user3</span><span class="pun">,</span><span class="pln">   
                post</span><span class="pun">,</span><span class="pln">  
                post2</span><span class="pun">,</span><span class="pln">  
                post3</span><span class="pun">,</span><span class="pln">  
                post4</span><span class="pun">,</span><span class="pln">  
                </span><span class="pun">])</span><span class="pln">
db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> u </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'user{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> </span><span class="str">'user{}@example.com'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln">  </span><span class="str">'password{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
    user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> email</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> p </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">):</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Post from user{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Content {}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">
    author_id </span><span class="pun">=</span><span class="pln"> p
    post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> author_id</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">post</span><span class="pun">)</span><span class="pln">
    db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span></pre>

<h2>
	طريقة العمل
</h2>

<p>
	الآن وبعد أن أدخلنا بعض المُستخدمين والمقالات إلى قاعدة البيانات، صار بإمكاننا الحصول على كل سجل وبيانات أعمدته، وسنحصل في أغلب الحالات على السّجل أو السّجلّات إن كانت مُتعدّدة ومن ثم إسنادها إلى مُتغيّر، فإن كان سجلّا واحدا (مثلا المُستخدم خالد) يُمكننا الوصول إلى بيانات الأعمدة ببساطة بإلحاق اسم العمود بالمُتغيّر الذي يحمل السّجل وفصلهما بنُقطة (<code>user.name</code> للحصول على اسم المُستخدم على سبيل المثال)، أمّا إن كان المُتغيّر يحمل سجلّات عديدة، فسنستخدم حلقة <code>for</code> بسيطة للدّوران حول السّجلات واستخراج بيانات كلّ سجل على حدة.<br>
	تلك الطّريقة هي التي سنعتمد عليها في ما بعد، أمّا الاختلاف فسيكون في كيفيّة الحصول على السّجل (أو السّجلات) لإسنادها إلى المُتغيّر.
</p>

<h2>
	الحصول على سجل
</h2>

<p>
	سنستعمل خاصيّة الاستعلام (querying) في SQL للحصول على السّجلات، ويُوفّر لنا SQLAlchemy طريقة بسيطة للوصول إلى الاستعلام وبقيّة العمليّات عليه.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_23" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">method</span></pre>

<p>
	الآن يُمكنك استبدال <code>method</code> بالعديد من التّوابع التّي تُوفّرها لنا مكتبة SQLAlchemy مثل <code>all</code> للحصول على جميع السّجلات من الجدول و <code>filter_by</code> لترشيح السّجلات والوصول إلى سجل يوافق شروطا معيّنة والمزيد من الطّرق المُتعدّدة التّي توفّرها قواعد بيانات SQL، وسنتطرّق إلى بعض أهم تلك الطّرق بالتّفصيل، وكما قلت من قبل فإني لن أشرح كل شيء توفّره المكتبة، لذا إن أردت الحصول على معلومة لم أذكرها فيُمكنك طرح سؤال في الأكاديميّة.
</p>

<h2>
	كيفيّة الوصول إلى جداول قاعدة البيانات من مفسر لغة بايثون
</h2>

<p>
	ذكرنا في الدروس السابقة أنه من أجل التعامل مع جدول معين فإن علينا استعمال اسم الصنف الخاص بالجدول والذي سبق وأنشأناه في ملفّ <code>models.py</code>. وسنبدأ أولًا بقراءة البيانات من جدول المُستخدمين، لكن يجب أن تستدعي الصّنف <code>User</code> أولًا من وحدة <code>models</code> كي نستطيع الوصول إليه.<br>
	تأكد من أن البيئة الوهمية مُفعّلة ثمّ افتح مُفسّر لغة بايثون واكتب ما يلي:
</p>

<pre class="ipsCode">
&gt;&gt;&gt; from project.models import User
</pre>

<p>
	بعد استيراد الصّنف <code>User</code>، ستتمكن من استخدامه للتعامل مع جدول المُستخدمين.
</p>

<h2>
	الحصول على سجل برقم مُعرّفه
</h2>

<p>
	أول طريقة قد تطرأ على ذهنك للحصول على سجلّ معيّن هي استخدام مفتاحه الأولي، أي رقم المُعرّف في أغلب الحالات، ذلك أن رقم المُعرّف يعبّر عن كلّ سجل بشكل فريد، فمن المُستحيل أن يحمل أكثر من مُستخدم مثلا رقم المُعرّف <code>1</code>، وبالمثل في حالة المقالات.
</p>

<p>
	وللحصول على المُستخدم الذي يحمل رقم المُعرّف <code>1</code>، استعمل التّابع <code>get()</code> بعد <code>User.query</code> مع تمرير الرّقم 1:
</p>

<pre class="ipsCode">
&gt;&gt;&gt; User.query.get(1)  
&lt;username: khalid | email: khalid@example.com &gt;
</pre>

<p>
	كما تُلاحظ، حصلنا على نبذة عن المُستخدم ذو رقم المُعرّف <code>1</code> بمُجرّد أن قمنا بتنفيذ الشّيفرة، لهذا من المُهم أن يتواجد التّابع <code>__repr__</code> في جداولك ولو لم يكن إضافته ضروريا.
</p>

<p>
	ولأنّنا سنقوم بالعديد من العمليّات على المُستخدم "خالد"، لنقم بإسناده إلى مُتغيّر باسم <code>user</code> ثم لننظر إلى بعض من البيانات الخاصّة بخالد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_25" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">name
u</span><span class="str">'khalid'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">email
u</span><span class="str">'khalid@example.com'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">password
u</span><span class="str">'password'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"password"</span><span class="pln">
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"wrong_password"</span><span class="pln">
</span><span class="kwd">False</span></pre>

<p>
	لاحظ آخر سطرين حيث نقوم بإجراء عمليّة تحقّق بسيطة لتفهم أنّ البيانات التّي تحصل عليها مجرّد سلاسل نصيّة عاديّة، وأنّك تستطيع القيام بمُختلف العمليّات التّي يُمكنك استعمال بايثون لإنجازها.
</p>

<p>
	وبالمُناسبة، إن كنت ترغب بالحصول على أول سجل من الجدول فقط بغض النّظر عن رقم مُعرّفه يُمكنك استخدام التّابع <code>first</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_27" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">&gt;</span></pre>

<h2>
	الحصول على عدد السجلات داخل جدول
</h2>

<p>
	للحصول على العدد الإجمالي للسجلات في جدول مُعين، استعمل التّابع <code>count()</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_29" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">count</span><span class="pun">()</span><span class="pln">
</span><span class="lit">12</span></pre>

<p>
	يوضح المثال التالي كيفية الحصول على العدد الإجمالي للمقالات في قاعدة بياناتنا (بعد استيراد الصّنف <code>Post</code> بالطّبع):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_31" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">count</span><span class="pun">()</span><span class="pln">
</span><span class="lit">13</span></pre>

<p>
	وكما تُلاحظ، فالنتيجة عبارة عن عدد صحيح (Integer)، لذا يُمكنك التعامل معه بلغة بايثون بشكل عادي.
</p>

<h2>
	الحصول على سجل بقيمة عمود معين
</h2>

<p>
	لا يكفي رقم المعرِّف وحده لإجراء العمليات الشّائعة في تطبيقات الويب، عمليات مثل الحصول على مُستخدم عن طريق اسمه، أو الحصول على مقالات حسب تاريخ إنشائها، أو ترتيب المُستخدمين وفق قيم أعمدة مختلفة -تاريخ الانضمام، ترتيب المُستخدمين حسب أسمائهم أبجديًا-، والعديد من العمليات الأخرى التّي تستطيع القيام بها بلغة SQL في قواعد البيانات التّي تستخدمها.
</p>

<p>
	يُمكنك الحصول على سجلّ أو عدّة سجلّات حسب قيمة عمود معيّن باستخدام التّابع <code>filter_by</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_33" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">column</span><span class="pun">=</span><span class="pln">value</span><span class="pun">)</span></pre>

<p>
	حصلنا هنا على نتيجة عبر ترشيح النّتائج وفق العمود وقيمته، أي أنّك لو أردت أن تحصل على مُستخدم حسب اسمه فتستطيع استبدال <code>column</code> ب<code>name</code> و <code>value</code> باسم المُستخدم. وإن أردت الحصول على القيم الفعليّة فاستعمل إمّا التّابع <code>first</code> للحصول على أول نتيجة أو التّابع <code>all</code> للحصول على جميع السّجلات داخل قائمة.
</p>

<pre class="ipsCode">
&gt;&gt;&gt; result.first()
&gt;&gt;&gt; result.all()
</pre>

<p>
	كتطبيق على هذا المفهوم، لنحصل على المُستخدم عبد الهادي ونُسنده إلى مُتغيّر باسم <code>user</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_35" style="">
<span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'abdelhadi'</span><span class="pun">).</span><span class="pln">first</span><span class="pun">()</span></pre>

<p>
	لاحظ بأنّنا نقوم بإضافة التّابع <code>first</code> لنحصل على المُستخدم الأول، وذلك لأنّ التّابع <code>filter_by</code> يُمكن أن يُرجع أكثر من سجل واحد. فمثلا لو كان لمقالين نفس العنوان -Post على سبيل المثال- فيُمكن أن يُرجع الاستعلام التّالي مقالين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_38" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">filter_by</span><span class="pun">(</span><span class="pln">title</span><span class="pun">=</span><span class="str">'Post'</span><span class="pun">)</span></pre>

<p>
	لذا فمن أجل الحصول عليها جميعًا، عليك إلحاق ما سبق بالتّابع <code>all</code>، أمّا لو أردت أول مقال فقط، فيُمكنك استعمال التّابع <code>first</code>.
</p>

<p>
	بعد أن حصلنا على المُستخدم عبد الهادي وأسندناه إلى المُتغيّر <code>user</code>، نستطيع الحصول على اسمه وكلمة مروره وبقيّة بياناته كما ذكرنا سابقا، ويُمكننا كذلك الحصول على مقالاته، وقد أضفنا مقالين كما تعلم برقم المُعرّف الخاص بهذا المُستخدم، لذا لنحصل على مقالات المُستخدم عبد الهادي باستخدام التّابع <code>posts</code> الذي ذكرته سابقا.
</p>

<p>
	إليك الآن أهم طريقتين لمُعالجة المقالات: للوصول إلى المقال الأول وقيّمه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_40" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> post1 </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">.</span><span class="pln">first</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post1
</span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post1</span><span class="pun">.</span><span class="pln">title
u</span><span class="str">'a post from abdelhadi'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post1</span><span class="pun">.</span><span class="pln">content
u</span><span class="str">'content of a post'</span></pre>

<p>
	وللوصول إلى جميع المقالات على شكل قائمة يُمكنك الدّوران حولها باستعمال حلقة <code>for</code>، يُمكنك استخدام التّابع <code>all</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_42" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts </span><span class="pun">=</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts
</span><span class="pun">[&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;,</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;]</span></pre>

<p>
	يُمكنك الآن الوصول إلى كل مقال على حدة بحلقة <code>for</code> بسيطة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_44" style="">
<span class="kwd">for</span><span class="pln"> post </span><span class="kwd">in</span><span class="pln"> posts</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">title</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'-----------------------'</span><span class="pun">)</span></pre>

<p>
	يكون الخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_46" style="">
<span class="pln">a post </span><span class="kwd">from</span><span class="pln"> abdelhadi
content of a post
</span><span class="pun">-----------------------</span><span class="pln">
another post </span><span class="kwd">from</span><span class="pln"> abdelhadi
some other content </span><span class="kwd">for</span><span class="pln"> the post
</span><span class="pun">-----------------------</span></pre>

<p>
	سنتطرّق إلى الدّوران حول العديد من السّجلات بتفصيل أكثر فيما بعد.
</p>

<p>
	للوصول إلى مقال معيّن يُمكنك إضافة علامات <code>[]</code> مع رقم العنصر، فللوصول إلى المقال الأول مثلًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_48" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title a post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> content of a post </span><span class="pun">&gt;</span></pre>

<p>
	والمقال الثّاني:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_50" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title another post </span><span class="kwd">from</span><span class="pln"> abdelhadi </span><span class="pun">|</span><span class="pln"> some other content </span><span class="kwd">for</span><span class="pln"> the post </span><span class="pun">&gt;</span></pre>

<h2>
	الدّوران حول قيم مجموعة من السجلات
</h2>

<p>
	في هذا القسم، سنستعلم عن بعض القيم من قاعدة بياناتنا ومن ثم ندور حولها للوصول إلى كل سجلّ على حدة:
</p>

<p>
	سنبدأ بالحصول على جميع القيم في جدول معيّن، وسنحتاج في حالتنا إلى استخدام هذه الطّريقة من أجل الحصول على جميع المقالات لعرضها على الصّفحة الرّئيسيّة للمقالات. وللوصول إلى جميع السجلّات في جدول مُعيّن في Flask-SQLAlchemy يُمكنك ببساطة أن تستخدم كلّا من التّابعين <code>query</code> ثمّ <code>all</code> على الصّنف المرتبط بالجدول، فمثلا للوصول إلى جميع المقالات المُتواجدة في الجدول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_52" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> posts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	الآن، سيحمل المُتغيّر <code>posts</code> قائمةً بجميع المقالات، ونستطيع الوصول إلى كلّ قيمة من القيم في أعمدة الجدول بالإضافة إلى بيانات المُستخدم الذي أضاف المقال بحلقة <code>for</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_54" style="">
<span class="kwd">for</span><span class="pln"> post </span><span class="kwd">in</span><span class="pln"> posts</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'-----------------------'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">title</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">email</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">password</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span></pre>

<p>
	تستطيع تُنفيذ حلقة التّكرار أعلاه لترى النّتيجة.
</p>

<p>
	وكما هو مُتوقّع، ستلاحظ أنّنا نستطيع الوصول إلى بيانات كل مقال على حدة وكذلك بيانات المُستخدم الذي أضاف المقال.
</p>

<p>
	كمثال إضافي، سنحصل على جميع المُستخدمين مع عرض بيانات كل مُستخدم ثمّ المقالات التّي كتبها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5276_56" style="">
<span class="pln">users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">.</span><span class="pln">query</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> user </span><span class="kwd">in</span><span class="pln"> users</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'-----------------------'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">email</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">password</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> post </span><span class="kwd">in</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="str">'----'</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">title</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
            </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">post</span><span class="pun">.</span><span class="pln">created_date</span><span class="pun">)</span></pre>

<p>
	إن أمعنت النّظر في الشّيفرة فستبدو لك بسيطة جدّا، مجرد حلقة للحصول إلى كل مُستخدم ثمّ حلقة أخرى للوصول إلى كل مقال من مقالاته.
</p>

<p>
	سنستخدم محرّك القوالب Jinja2 للدّوران حول البيانات وعرضها بطريقة مُشابهة من أجل الوصول إلى القيم وعرضها في ملفّات HTML داخل تطبيق الويب الذي نبنيه بإطار Flask، لذا أقترح أن تُحاول عرض المقالات وكاتب كلّ مقال منذ الآن لتختبر مدى فهمك للموضوع.
</p>

<p>
	في الدروس التالية، سنستخدم طرقًا أخرى للحصول على عدة سجلات وإسنادها إلى مُتغيّر، وستكون طريقة الوصول إلى كل قيمة من بيانات السّجل هي نفسها ما قد ذكرناه ها هنا.
</p>
]]></description><guid isPermaLink="false">827</guid><pubDate>Fri, 21 Feb 2020 16:44:43 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x645;&#x643;&#x62A;&#x628;&#x629; SQLAlchemy &#x641;&#x64A; &#x645;&#x64F;&#x641;&#x633;&#x651;&#x631; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x644;&#x644;&#x62A;&#x651;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x651;&#x637;&#x628;&#x64A;&#x642;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-sqlalchemy-%D9%81%D9%8A-%D9%85%D9%8F%D9%81%D8%B3%D9%91%D8%B1-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%84%D9%84%D8%AA%D9%91%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%91%D8%B7%D8%A8%D9%8A%D9%82-r516/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_07/main.png.a2bc8ae88e90dd67c841b80b29655385.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	بعد إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات في <a href="https://academy.hsoub.com/programming/python/flask/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AC%D8%AF%D9%88%D9%84%D9%8A-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r514/" rel="">الدّرس السّابق</a>، حان الوقت للتّعامل مع البيانات وإدارتها باستعمال لغة بايثون عوضا عن لغة SQL؛ في هذا الدّرس سنتعرّف على كيفيّة الوصول إلى مُفسّر بايثون في مجلّد مشروعنا وكذلك كيفيّة إضافة البيانات وجلبها من قاعدة البيانات.
</p>

<h2 id="الوصول-إلى-مفسر-بايثون-داخل-مجلد-المشروع">
	الوصول إلى مُفسّر بايثون داخل مُجلّد المشروع
</h2>

<p>
	سنقوم في هذا الدّرس بالتّعامل مع قاعدة البيانات باستعمال Flask-SQLAlchemy مُباشرة من مُفسّر بايثون، إن كنت على نظام Windows فهو في الغالب متواجد في قائمة ابدأ، أمّا إن كنت على <a href="https://academy.hsoub.com/devops/linux/" rel="">لينكس</a> أو OSX فادخل إلى الطّرفيّة Terminal واكتب <code>python</code> تأكّد فقط من أنّك في مُجلّد <code>kalima</code> قبل أن تقوم بالوصول إلى مُفسّر بايثون، وتأكّد كذلك بأنّك قد فعّلت البيئة الوهميّة.
</p>

<p>
	إن لم تستطع الوصول إلى مُفسّر بايثون في مُجلّد <code>kalima</code> فيُمكنك تنفيذ الأمر <code>chdir</code> من وحدة <code>os</code> لتغيير المُجلّد الحالي إلى مسار مُجلّد <code>kalima</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> os

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">chdir</span><span class="pun">(</span><span class="str">'path/to/kalima'</span><span class="pun">)</span></pre>

<p>
	مع تغيير <code>path/to/kalima</code> إلى مسار مُجلّد <code>kalima</code> في حاسوبك.
</p>

<p>
	<strong>مُلاحظة:</strong> الشّيفرة التّي سأقوم بتنفيذها ستُسبق بعلامة <code>&gt;&gt;&gt;</code> أمّا المُخرج/النّتيجة فلن يُسبق بشيء.
</p>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">site </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Hsoub Academy'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">site
</span><span class="hljs-string"><span class="str">'Hsoub Academy'</span></span></code></pre>

<p>
	بما أنّنا في مُفسّر بايثون نستطيع الوصول إلى قيمة المُتغيّر دون طباعتها، فقط اكتب اسم المُتغيّر ثم اضغط مفتاح ENTER.
</p>

<p>
	سنستعمل كلّا من <code>db</code> والصّنفين اللذ]ن يُشكلان كلّا من جدول المقالات والمُستخدمين للتّعامل مع البيانات فيها، وللوصول إلى كلّ من الكائن <code>db</code> والصّنفين <code>Post</code> و <code>User</code> يجب عليك أن تقوم باستيرادها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> project </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> db
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span></code></pre>

<p>
	إن حصلت على خطأ كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs sql"><span class="typ">Traceback</span><span class="pln"> </span><span class="pun">(</span><span class="pln">most recent </span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">call</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">last</span></span><span class="pun">):</span><span class="pln">
  </span><span class="typ">File</span><span class="pln"> </span><span class="hljs-string"><span class="str">"&lt;stdin&gt;"</span></span><span class="pun">,</span><span class="pln"> line </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> </span><span class="str">&lt;</span><span class="hljs-keyword"><span class="str">module</span></span><span class="str">&gt;</span><span class="pln">
</span><span class="typ">ImportError</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">No</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">module</span></span><span class="pln"> named project</span></span></code></pre>

<p>
	فهذا يعني بأنّك لست في مجلّد <code>kalima</code> لذا تأكّد من أنّك اتّبعت الإرشادات السّابقة على نحو صحيح.
</p>

<h2 id="إدخال-البيانات-إلى-قاعدة-البيانات">
	إدخال البيانات إلى قاعدة البيانات
</h2>

<p>
	الآن، بعد استيراد كلّ من الكائن <code>db</code> والصّنفين <code>Post</code> و<code>User</code> نستطيع القيام بأول عمليّة، ألا وهي عمليّة الإضافة، وسنُضيف أولا مُستخدما باسم <code>khalid</code> وبعدها سنُضيف مقالا له بعنوان <code>Post 1</code>.
</p>

<h3 id="إضافة-المستخدم">
	إضافة المُستخدم
</h3>

<p>
	لإضافة مُستخدم سنُنشئ أولا كائنا من الصّنف <code>User</code> مع المعاملات التّي حدّدناها سابقا في دالّة <strong>init</strong> الخاصّة بالصّنف، ما يعني بأنّنا سنُنشئ مُستخدما كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs nginx"><span class="hljs-title"><span class="pln">user</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="hljs-string"><span class="str">'khalid'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'email</span><span class="hljs-variable"><span class="str">@example</span></span><span class="str">.com'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'password'</span></span><span class="pun">)</span></code></pre>

<p>
	وهنا يكون التّرتيب مُهمّا ومُطابقا لترتيب المُعاملات في الدّالة <code>__init__</code>، ويُمكنك كذلك تسميّة كلّ معامل وتغيير التّرتيب إن لم تتذكّر سوى أسماء المعاملات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs nginx"><span class="hljs-title"><span class="pln">user</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="pln">password</span><span class="pun">=</span><span class="hljs-string"><span class="str">'password'</span></span><span class="pun">,</span><span class="pln"> email</span><span class="pun">=</span><span class="hljs-string"><span class="str">'email</span><span class="hljs-variable"><span class="str">@example</span></span><span class="str">.com'</span></span><span class="pun">,</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'khalid'</span></span><span class="pun">)</span></code></pre>

<p>
	كما تُلاحظ عندما تذكر اسم كلّ معامل، فالتّرتيب غير مهم خلافا للمثال الأول.
</p>

<p>
	بعد إنشاء الكائن من صنف المُستخدم بالبيانات التّي نُريدها، يُمكننا الوصول إلى كل قيمة أو تغييرها ببساطة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user </span><span class="pun">=</span><span class="pln"> </span><span class="typ">User</span><span class="pun">(</span><span class="hljs-string"><span class="str">'khalid'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'email@example.com'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'password'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user</span><span class="pun">.</span><span class="pln">name
</span><span class="hljs-string"><span class="str">'khalid'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user</span><span class="pun">.</span><span class="pln">email
</span><span class="hljs-string"><span class="str">'email@example.com'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user</span><span class="pun">.</span><span class="pln">password
</span><span class="hljs-string"><span class="str">'password'</span></span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user</span><span class="pun">.</span><span class="pln">email </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'khalid@example.com'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user</span><span class="pun">.</span><span class="pln">email
</span><span class="hljs-string"><span class="str">'khalid@example.com'</span></span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">user
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid</span><span class="hljs-decorator"><span class="pln">@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></span>
</code></pre>

<p>
	كما تُلاحظ، يُمكننا الوصول إلى كل قيمة من القيم التّي حدّدناها سابقا وكذا تعديلها بإسناد قيمة جديدة بكل بساطة.
</p>

<p>
	لاحظ كذلك مُخرجات آخر أمر، يُمكنك أن ترى بأنّ طريقة التّنسيق هذه هي نفسها ما قد حدّدناه سابقا في الدّالة <code>__repr__</code> بالصّنف <code>User</code>، وإليك تذكيرا سريعا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__repr__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'&lt;username: {} | email: {} &gt;'</span></span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">email</span><span class="pun">)</span></code></pre>

<p>
	وأنبّه إلى أنّنا لم نغيّر أي شيء بعد في قاعدة البيانات، وإنشاء الكائن ليس سوى تمهيد لإضافته إلى جلسة تتواجد في الكائن <code>db</code> ثمّ تأكيد التّغييرات لإضافة المُستخدم إلى قاعدة البيانات حقيقة، ولإضافة الكائن <code>user</code> الذي أنشأناها قبل قليل إلى الجلسة نقوم بما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs avrasm"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">session</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">add</span></span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span></code></pre>

<p>
	والجلسة هنا عبارة عن مكان لإضافة البيانات لوضعها بعد ذلك في قاعدة البيانات، وعند إضافة كل كائن إلى الجلسة لا يُضاف إلى قاعدة البيانات حقيقة إلى أن تنفّذ الأمر <code>db.session.commit</code>.<br>
	لذا لإضافة المُستخدم خالد إلى قاعدة البيانات PostgreSQL فسننفّذ الأمر التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs avrasm"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> db</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">session</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">commit</span></span><span class="pun">()</span></code></pre>

<p>
	بعد تنفيذ الأمر والعودة إلى أداة psql لعرض جميع البيانات في جدول المُستخدمين فستلاحظ بأنّ المُستخدم الذي أضفناه موجود بالفعل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs asciidoc"><span class="pln">kalima</span><span class="pun">=#</span><span class="pln"> </span><span class="kwd">select</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> users</span><span class="pun">;</span><span class="pln">


</span><span class="hljs-header"><span class="pln"> id </span><span class="pun">|</span><span class="pln">  name  </span><span class="pun">|</span><span class="pln">       email        </span><span class="pun">|</span><span class="pln"> password </span><span class="pun">|</span><span class="pln">        created_date        
</span><span class="pun">----+--------+--------------------+----------+----------------------------</span></span><span class="pln">
</span><span class="hljs-code"><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> khalid@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">|</span><span class="pln"> password </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2017</span><span class="pun">-</span><span class="lit">04</span><span class="pun">-</span><span class="lit">08</span><span class="pln"> </span><span class="lit">18</span><span class="pun">:</span><span class="lit">48</span><span class="pun">:</span><span class="lit">05.316805</span></span><span class="pln">
</span><span class="pun">(</span><span class="lit">1</span><span class="pln"> row</span><span class="pun">)</span></code></pre>

<p>
	لاحظ بأنّ العمود <code>id</code> أخذ القيمة <code>1</code> رغم أنّنا لم نُحدّدها، ولو أضفنا مُستخدما آخر الآن لكان رقم مُعرّفه <code>2</code> ولو حذفت مثلا المُستخدم الذي يحمل رقم المعرّف <code>1</code> وأضفت مُستخدما آخر، فرقم مُعرّف هذا المُستخدم لن يأخذ مكان المُستخدم الأول بل سيأخذ رقما جديدا مُخالفا للأرقام السّابقة؛ ولاحظ كذلك بأنّ تاريخ الإضافة قد أضيف دون أن نقوم بتحديده يدويا.
</p>

<h3 id="إضافة-المقال">
	إضافة المقال
</h3>

<p>
	بعد أن قُمنا بإضافة المُستخدم، حان الوقت لإضافة مقال خاص به، بالطّبع في التّطبيق المُستخدِم هو من سيُضيف مقالاته، وبعد تسجيله الدّخول، سنستطيع إضافة المقال ووضع قيمة مفتاح مُعرّفه كقيمة للمُعامل <code>author_id</code>، وسنقوم في هذا الجزء بإعطاء مثال لكيفيّة إضافة مقال وإسناد كاتب له، وفي الجزء التّالي سوف نضيف المزيد من المقالات والمُستخدمين لشرح كيفيّة الوصول إلى بيانات كل مُستخدم بما فيها مقالاته، وكذا كاتب كلّ مقال.
</p>

<p>
	لإضافة المقال ذي العنوان <code>Post 1</code> نقوم بنفس الشّيء، أولا نُنشئ كائنا من الصّنف <code>Post</code> ثمّ نُسند له القيم التّي حدّدناها سابقا في الدّالة <code>__init__</code> الخّاصّة بالصّنف، لكن هذه المرّة نقوم بإضافة مُعامل آخر، وهو عبارة عن قيمة رقم مُعرّف المُستخدم الذي أضاف المقال، وبما أنّنا نمتلك مُستخدما رقم مُعرّفه <code>1</code> فهذا يعني بأنّنا نستطيع أن نُسند له هذا المقال بصفته كاتبا له.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Post 1'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'post 1 content'</span></span><span class="pun">,</span><span class="pln"> author_id</span><span class="pun">=</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> content </span><span class="pun">&gt;</span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">post</span><span class="pun">)</span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">db</span><span class="pun">.</span><span class="pln">session</span><span class="pun">.</span><span class="pln">commit</span><span class="pun">()</span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid</span><span class="hljs-decorator"><span class="pln">@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">name
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'khalid'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">email
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'khalid@example.com'</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">password
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'password'</span></span>
</code></pre>

<p>
	كما تُلاحظ، يُمكنك تحديد أسماء معاملات إن أردت، وترك أسماء أخرى على شرط أن تكون القيم مُرتّبة، فقد ذكرت اسم المُعامل <code>author_id</code> فقط لكي تفهم القيمة الثّالثة، وسيتوجّب عليك ذكر الاسم إن كان لك العديد من المفاتيح الأجنبيّة (أرقام مُعرّف تُشير إلى جداول كثيرة) لأنّها ستكون كلّها عبارة عن أرقام لا معنى لها لمن يقرأ الشّيفرة، ويجب عليك أن تتذكّر ترتيبها باستمرار، لذا من المُفضّل تجنّب هذا بذكر اسم كلّ معامل.
</p>

<p>
	لاحظ كذلك عندما نستدعي الكائن، فإنّ الدّالة <code>__repr__</code> تستبدل كلّا من المنطقتين بالعنوان والمحتوى كما هو مُتوقّع.<br>
	بعد إضافة المقال إلى الجلسة ثمّ تأكيد التّغييرات وكتابتها إلى قاعدة البيانات، أصبح بإمكاننا الآن الوصول إلى كاتب المقال عن طريق <code>post.author</code> والمُخرج عبارة عن كائن يحمل بيانات المُستخدم الذي أدخل البيانات كما لو أنّك حصلت عليه من قاعدة البيانات، إذ تستطيع الوصول إلى قيمة أي عمود في جدول المُستخدمين والنّتيجة تكون عبارة عن سلسلة نصيّة مسبوقة بحرف <code>u</code> للإشارة إلى أنّها عبارة عن Unicode وبالطّبع يُمكنك التّعامل معها كما تتعامل مع سلسلة نصيّة عاديّة.
</p>

<p>
	بعد الوصول إلى المُستخدم كاتب المقال، يُمكنك الحصول على مقالاته الأخرى كذلك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs avrasm"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> post</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">author</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">posts</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">all</span></span><span class="pun">()</span><span class="pln">
</span><span class="pun">[&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> content </span><span class="pun">&gt;]</span></code></pre>

<p>
	المُخرج عبارة عن قائمة من المقالات يُمكنك الدّوران حولها باستخدام حلقة <code>for</code> ولأنّنا لا نمتلك سوى مقال واحد حاليّا، سنقوم بالوصول إليه مُباشرة برقم العنصر في القائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">]</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">title </span><span class="typ">Post</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln"> post </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> content </span><span class="pun">&gt;</span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">title
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'Post 1'</span></span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">content
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'post 1 content'</span></span><span class="pln">

</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author
</span><span class="pun">&lt;</span><span class="pln">username</span><span class="pun">:</span><span class="pln"> khalid </span><span class="pun">|</span><span class="pln"> email</span><span class="pun">:</span><span class="pln"> khalid</span><span class="hljs-decorator"><span class="pln">@example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">&gt;</span></span></code></pre>

<p>
	لاحظ أنّنا استطعنا الوصول إلى كاتب المقال مُجدّدا في آخر سطر، يُمكنك الاستمرار إلى ما لانهاية، المقال –&gt; كاتبُه –&gt; مقال كَتَبه –&gt; كاتبُه –&gt; مقال كَتَبه –&gt; كاتبُه وهكذا…<br>
	ما يعني بأنّ السّطر التّالي مُمكن:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4954_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="pln">post</span><span class="pun">.</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">author</span><span class="pun">.</span><span class="pln">name
</span><span class="hljs-string"><span class="pln">u</span><span class="str">'khalid'</span></span></code></pre>

<p>
	بالطّبع، لا فائدة من استعمال SQLAlchemy بهذه الطّريقة، إنّما يجب عليك أن تفهم كيف يعمل، وبأنّ مثل هذه الأمور مُمكنة فربّما تُفيدك في تفادي بعض الأخطاء البرمجيّة.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة استعمال مُفسّر لغة بايثون للتّعامل مع قاعدة البيانات الخاصّة بنا، وتمكّنّا من إضافة سجلّ إلى جدول المُستخدمين وسجلّ آخر إلى جدول المقالات. في الدّرس القادم، سنطّلع على كيفيّة إنشاء العديد من السّجلات لنتمكّن من العمل معها في بقيّة الدّروس الخاصّة بالتّعامل مع قاعدة البيانات باستعمال مكتبة SQLAlchemy لتتمكّن من تطوير تطبيقات ويب أفضل وأكثر تعقيدا باستعمال إطار العمل Flask.
</p>
]]></description><guid isPermaLink="false">516</guid><pubDate>Mon, 31 Jul 2017 18:16:54 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x62C;&#x62F;&#x648;&#x644;&#x64A; &#x627;&#x644;&#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x645;&#x64F;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x64A;&#x646; &#x641;&#x64A; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AC%D8%AF%D9%88%D9%84%D9%8A-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r514/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_07/main.png.3a875923022661b1f1239c68a3230878.png" /></p>

<h2 id="مقدمة">
	مقدّمة
</h2>

<p>
	بعد أن تعرّفنا على كيفيّة تجهيز جدولي المقالات والمُستخدمين اللّذين سيُشكّلان أساس بيانات تطبيقنا، وبعد أن تعرّفنا في الدّرس السّابق على كيفيّة الرّبط بين الجدولين ليكون لكلّ كاتب مقالاته ولكل مقال كاتب خاص به، حان الوقت لإنشاء الجدولين في قاعدة البيانات والتّعرّف على كيفيّة استغلال كلّ من مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy للتّعامل مع البيانات.
</p>

<h2 id="لماذا-الدروس-القادمة-أساسية">
	لماذا الدّروس القادمة أساسيّة؟
</h2>

<p>
	هذا الدّرس والدّروس القادمة مُهمّة لك إن كنت ترغب بالاعتماد على قواعد بيانات <a href="https://academy.hsoub.com/devops/servers/databases/" rel="">SQL</a> ومكتبة SQLAlchemy في تطوير تطبيقاتك، وما ستتعلّمه من هذه الدروس سيُفيدك في حالات كثيرة، وستتمكّن من القيام بأكثر العمليّات شيوعا باستخدام SQLAlchemy عوضا عن لغة SQL ما سيبقي شفرتك نظيفة وسيُمكّنك من العمل مع بياناتك بأريحيّة أكثر.
</p>

<p>
	ورغم أنّنا لن نستعمل الكثير من الأشياء التّي سأذكرها في تطبيق “كلمة”، إلّا أنّ الإلمام بها مهم جدّا، وعندما أقول بأنّ هذه المفاهيم مهمّة فأنا لا أعني أن تحفظها عن ظهر قلب، إذ يُمكنك أن تعود إلى درس مُعيّن في كلّ مرّة تُريد أن تتذكّر كيفيّة القيام بعمليّة معيّنة باستخدام مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy، وأشجّعك على توظيف كل ما ستتعلّمه لإضافة ميّزات جديدة إلى التّطبيق الذي سنبنيه سويّا (مثلا إضافة جزء لعرض مقال عشوائي في كلّ مرّة يُعاد فيها تحميل الصّفحة)، وإن أردت أن تعرف كيفيّة القيام بعمليّة أخرى من عمليّات SQL التّقليديّة باستخدام SQLAlchemy فعد أولا إلى التّوثيق الرّسمي للمكتبة أو ضع سؤالا مصاغا بوضوح ولغة سليمة في قسم <a href="https://academy.hsoub.com/questions/c3-programming/" rel="">الأسئلة والأجوبة</a> للحصول على إجابة كافيّة.
</p>

<h2 id="إنشاء-جدولي-المقالات-والمستخدمين-في-قاعدة-البيانات">
	إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات
</h2>

<p>
	بعد أن أنشأنا الصّنفين المسؤولين عن إنشاء الجدولين في ملفّ <code>models.py</code> الذي يقع تحت مُجلّد <code>project</code> أصبح بإمكاننا إنشاء الجدولين عن طريق مكتبة SQLAlchemy اعتمادا على محتويات ملفّ <code>models.py</code> والكائن <code>db</code> الذي سبق لنا وأنشأناها بمُساعدة إضافة Flask-SQLAlchemy.
</p>

<p>
	بعد إنشاء الجدولين، ستُطبّق التّغييرات مُباشرة إلى خادوم PostgreSQL الذي نُصّب بجهازك المحلي، ما يعني بأنّك ستتمكّن من التّعامل مع قاعدة البيانات باستخدام لغة SQL والميّزات التي تُوفّرها قاعدة البيانات PostgreSQL.
</p>

<p>
	لإنشاء الجدولين في قاعدة بياناتنا، سنقوم أولا بإنشاء ملف باسم <code>create_db.py</code> في المجلّد الرّئيسي <code>kalima</code> وسنضع به ثلاثة أسطر فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<span class="com"># create_db.py</span><span class="pln">

</span><span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db
</span><span class="kwd">from</span><span class="pln"> project</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> </span><span class="typ">User</span><span class="pln">

db</span><span class="pun">.</span><span class="pln">create_all</span><span class="pun">()</span></pre>

<p>
	تأكّد فقط من أنّ إعداد <code>SQLALCHEMY_DATABASE_URI</code> يُشير إلى قاعدة بيانات PostgreSQL التّي أنشأناها سابقا باسم <code>kalima</code> وأنّ اسم المُستخدم وكلمة المرور صحيحان في ذات الإعداد، وللمزيد أعد إلقاء نظرة على درس تجهيز قاعدة البيانات PostgreSQL ودرس إنشاء جداول البيانات.
</p>

<p>
	كما تُلاحظ، الشّفرة بسيطة، أولا نستدعي الكائن db من حزمة المشروع، ثمّ نستدعي كلّا من الصّنف <code>Post</code> و<code>User</code> لإعلام SQLAlchemy بأنّنا قد حدّدنا هذه الجداول والأعمدة الأساسيّة فيها، وبعد ذلك نقوم بإنشاء الجداول في قاعدة البيانات باستعمال الدّالة <code>db.create_all</code>.<br>
	وبنفس الطّريقة لو أردت حذف الجداول يُمكنك استدعاء الدّالة <code>db.drop_all</code> عوضا عن <code>db.create_all</code>.
</p>

<p>
	وإن أمكنك الوصول إلى سطر أوامر PostgreSQL عن طريق أداة psql فيُمكنك الاتّصال بقاعدة البيانات <code>kalima</code> وعرض الجداول فيه، بالأمرين التّاليين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs livecodeserver"><span class="pln">postgres</span><span class="pun">=</span><span class="hljs-comment"><span class="pun">#</span><span class="pln"> \c kalima</span></span><span class="pln">
</span><span class="typ">You</span><span class="pln"> are now connected </span><span class="hljs-built_in"><span class="pln">to</span></span><span class="pln"> database </span><span class="hljs-string"><span class="str">"kalima"</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> user </span><span class="hljs-string"><span class="str">"postgres"</span></span><span class="pun">.</span><span class="pln">

kalima</span><span class="pun">=</span><span class="hljs-comment"><span class="pun">#</span><span class="pln"> \d</span></span><span class="pln">
</span><span class="typ">No</span><span class="pln"> relations found</span><span class="pun">.</span></code></pre>

<p>
	الأمر الأول للاتّصال بقاعدة البيانات الخاصّة بتطبيقنا، وذلك لأنّ الخادوم يحتوي على أكثر من قاعدة بيانات واحدة، أمّا الأمر الثّاني فهو لعرض الجداول المُتواجدة بقاعدة البيانات، وبما أنّنا لم ننفّذ ملفّ <code>create_db.py</code> بعد فالنّتيجة هي بطبيعة الحال أنّنا لا نمتلك أية جداول أو علاقات كما تُلاحظ من الرّسالة <code>No relations found</code>.<br>
	الآن، نفّذ الملفّ عبر الأمر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs avrasm"><span class="pln">python create_db</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span></code></pre>

<p>
	إن لم تلاحظ أية رسالة، فهذا يعني بأنّ كل شيء بخير، ولو عدت إلى سطر أوامر psql وأعدت تنفيذ الأمر <code>\d</code> للاحظت ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs smalltalk"><span class="pln">              </span><span class="hljs-class"><span class="typ">List</span></span><span class="pln"> of relations
 </span><span class="hljs-class"><span class="typ">Schema</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln">     </span><span class="hljs-class"><span class="typ">Name</span></span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="hljs-class"><span class="typ">Type</span></span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="hljs-class"><span class="typ">Owner</span></span><span class="pln">   
</span><span class="pun">--------+--------------+----------+----------</span><span class="pln">
 </span><span class="kwd">public</span><span class="pln"> </span><span class="hljs-localvars"><span class="pun">|</span><span class="pln"> posts        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> posts_id_seq </span><span class="pun">|</span><span class="pln"> sequence </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users_id_seq </span><span class="pun">|</span><span class="pln"> sequence </span><span class="pun">|</span><span class="pln"> postgres</span></span></code></pre>

<p>
	ربّما تختلف قيمة العمود <code>Owner</code> لديك لأنّها تُشير إلى اسم المُستخدم الذي أنشأ الجداول أو مالكها، وهذا الاسم هو نفسه الذي تُحدّده في إعداد قاعدة البيانات الذي سبق وأن أشرنا إليه، لاحظ معي فقط كلّا من الجدول <code>posts</code> و الجدول <code>users</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs smalltalk"><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="hljs-localvars"><span class="pun">|</span><span class="pln"> posts        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> postgres
 </span><span class="kwd">public</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> users        </span><span class="pun">|</span><span class="pln"> table    </span><span class="pun">|</span><span class="pln"> postgres</span></span></code></pre>

<p>
	بما أنّ نوع العلاقة هو <code>table</code> (جدول)، فهذا يعني بأنّنا استطعنا إنشاء الجدولين بنجاح، ونستطيع الآن التّعامل معه بلغة SQL مباشرة من أداة psql. في ما يلي استعلامان يُمكنك تنفيذهما للحصول على جميع السّجلات في كلّ جدول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">select</span></span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> posts</span><span class="pun">;</span></span><span class="pln">
</span><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">select</span></span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> users</span><span class="pun">;</span></span></code></pre>

<p>
	بالطّبع، لأنّنا لم نُضف أية سجلّات بعد، فالمُخرج سيكون كما يلي في كلتا الحالتين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8736_7" style="">
<code class="hljs asciidoc"><span class="pln">
</span><span class="typ">Posts</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">:</span><span class="pln">

</span><span class="hljs-header"><span class="pln"> id </span><span class="pun">|</span><span class="pln"> title </span><span class="pun">|</span><span class="pln"> content </span><span class="pun">|</span><span class="pln"> created_date </span><span class="pun">|</span><span class="pln"> author_id 
</span><span class="pun">----+-------+---------+--------------+-----------</span></span><span class="pln">
</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> rows</span><span class="pun">)</span><span class="pln">

</span><span class="typ">Users</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">:</span><span class="pln">

</span><span class="hljs-header"><span class="pln"> id </span><span class="pun">|</span><span class="pln"> name </span><span class="pun">|</span><span class="pln"> email </span><span class="pun">|</span><span class="pln"> password </span><span class="pun">|</span><span class="pln"> created_date 
</span><span class="pun">----+------+-------+----------+--------------</span></span><span class="pln">
</span><span class="pun">(</span><span class="lit">0</span><span class="pln"> rows</span><span class="pun">)</span></code></pre>

<p>
	وكما تُلاحظ، جميع الأعمدة التّي سبق وأن حدّدناها في ملفّ <code>models.py</code> باستعمال <code>db.Column</code> متواجدة في هذين الجدولين.
</p>

<p>
	يُمكنك بالطّبع إضافة بعض السّجلّات بلغة SQL إن أردت ذلك بالاعتماد على جملة <code>INSERT INTO</code> وكذا التّعامل مع البيانات بمُختلف الطّرق التّي تُتيحها PostgreSQL، ولكنّنا لن نستعمل لغة SQL لأنّنا نمتلك أداة SQLAlchemy وإضافة فلاسك الخاصّة به.
</p>

<h2 id="ختاما">
	ختاما
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة إنشاء جدولي المقالات والمُستخدمين في قاعدة البيانات مُباشرة باستعمال الدّالة <code>db.create_all()</code> التّي توفّرها لنا إضافة Flask-SQLAlchemy. في الدّرس القادم، سنتعرّف على كيفيّة استعمال مُفسّر لغة <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون </a>للتعامل مع قاعدة البيانات بمُساعدة من مكتبة SQLAlchemy، وبذلك سنتمكّن من التواصل مع قاعدة البيانات وإدارة سجلات الجداول فيها. 
</p>
]]></description><guid isPermaLink="false">514</guid><pubDate>Fri, 28 Jul 2017 11:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x631;&#x651;&#x628;&#x637; &#x628;&#x64A;&#x646; &#x62C;&#x62F;&#x648;&#x644;&#x64A; &#x627;&#x644;&#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x645;&#x64F;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x64A;&#x646; &#x628;&#x639;&#x644;&#x627;&#x642;&#x629; &#x648;&#x627;&#x62D;&#x62F; &#x644;&#x644;&#x639;&#x62F;&#x64A;&#x62F; One-to-Many Relationship</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%B1%D9%91%D8%A8%D8%B7-%D8%A8%D9%8A%D9%86-%D8%AC%D8%AF%D9%88%D9%84%D9%8A-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D8%A8%D8%B9%D9%84%D8%A7%D9%82%D8%A9-%D9%88%D8%A7%D8%AD%D8%AF-%D9%84%D9%84%D8%B9%D8%AF%D9%8A%D8%AF-one-to-many-relationship-r512/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_07/main.png.4f5bb399033244ac9380eb5fa6e570d8.png" /></p>

<h2 id="مقدمة">
	مُقدّمة:
</h2>

<p>
	بعد أن عرّفنا كلّا من جدول المقالات وجدول المُستخدمين، بقيت لنا خطوة الرّبط بينهما ليُشير كلّ مقال إلى كاتبه ونستطيع الوصول إلى مقالات كلّ مُستخدم، وسنقوم بهذا الأمر باستغلال خصائص قواعد بيانات SQL العلائقيّة لإنشاء علاقة واحد للعديد، بحيث يُمكن لكلّ مُستخدم أن يمتلك العديد من المقالات ويكون لكلّ مقال كاتب واحد فقط.
</p>

<h2 id="المشكلة">
	المُشكلة
</h2>

<p>
	عند تصفّحك لتطبيقات الوب في وقتنا الحالي، ستُلاحظ بأنّ المُستخدمين يمتلكون بياناتهم الخاصّة، مثلا يُمكن للمُستخدم الواحد أن يمتلك عدّة مقالات وتدرج تحت اسمه، ويُمكن أن يمتلك كذلك عدّة تعليقات باسمه، إذن كيف يُمكن أن نُدرج مقالات من جدول المقالات الخاصّ بنا إلى المُستخدم الذي يقوم بإضافتها؟ بمعنى آخر، كيف يُمكن للمُستخدم الواحد أن يمتلك عدّة مقالات مُندرجة باسمه؟
</p>

<h2 id="الحل-الخاطئ">
	الحل الخاطئ
</h2>

<p>
	الطّريقة التّي يُمكن أن تُفكّر فيها هي بإدراج رقم مُعرّف كل مقال يُضيفه المُستخدم إلى عمود خاص به مع الفصل بينها بمسافة أو شيء من هذا القبيل، بعدها تحصل عليها وتقوم باستخراج مقالات كل مُستخدم.<br>
	الجدول سيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<code class="hljs r"><span class="pln">id </span><span class="pun">|</span><span class="pln"> name </span><span class="pun">|</span><span class="pln"> posts
 </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Ali</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pun">...</span></span></code></pre>

<p>
	أهملت هنا عمودي البريد الإلكتروني وكلمة المرور لأنّها غير مُهمّة في مثالنا.<br>
	الآن إن نظرت إلى العمود <code>posts</code> فستجد بأنّ المقالات ذات المُعرّفات 1 و 3 و 5 قد أضافها المُستخدم <code>Ali</code>.
</p>

<p>
	هذه الطّريقة فكرة سيّئة جدّا، فلو أردنا حذف مقال فحذف علاقته بالمُستخدم أمر مُعقّد، وهناك العديد من المشاكل مع استخدام هذه الطّريقة، وقد أشرت إليها لأنّها شائعة جدّا ويجب أن تحذفها من ذهنك قبل أن تحدث أمور أسوأ، فإن أردت أن تكون مُطوّر وب جيّدا فعليك تعلّم الطّرق الصّحيحة وعليك كذلك الإلمام بالطّرق الخاطئة في التّطوير.
</p>

<h2 id="الطريقة-الصحيحة-لربط-سجل-واحد-بالعديد-من-السجلات-في-جدولين-مختلفين">
	الطّريقة الصّحيحة لربط سجلّ واحد بالعديد من السّجلّات في جدولين مُختلفين
</h2>

<p>
	علاقة الواحد-للعديد أو One-to-Many Relationship هي طريقة لربط جدولين أو أكثر بحيث يمتلك كلّ فرد في جدول العديد من السّجلّات في جدول آخر. في مثالنا، سيمتلك المُستخدم الواحد عدّة مقالات باسمه. للقيام بهذا الأمر، نقوم بوضع عمود آخر في الجدول الذي سيمتلك العديد من السّجلّات الخاصّة بفرد واحد من جدول آخر ليحمل قيمة رقم مُعرّف هذا الفرد، أي أننا سنُضيف عمودا آخر في جدول المقالات ليحمل رقم مُعرّف المُستخدم الذي أضاف المقال ليكون جدول المقالات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> title  </span><span class="pun">|</span><span class="pln"> user_id
</span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
</span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> 
</span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
</span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Post</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span></pre>

<p>
	لنفترض بأنّ لدينا ثلاثة مُستخدمين في جدول المُستخدمين كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<code class="hljs 1c"><span class="hljs-string"><span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> name  </span></span><span class="pln">
</span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Ali</span></span><span class="pln">
</span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Abdelhadi</span></span><span class="pln">
</span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Hassan</span></span></code></pre>

<p>
	مُجدّدا، قمت بإهمال الأعمدة الأخرى لأنّها لا تهمّنا في هذا المثال، وكما تُلاحظ لكل مقال قيمة في عمود <code>user_id</code> لتُشير إلى المُستخدم الذي أنشأ هذا المقال، وعند النّظر إلى جدولي المقالات والمُستخدمين والسّجلّات المتواجدة فيها حاليّا، يتبيّن لنا بأنّ المستخدم <code>Ali</code> قد أضاف مقالين، المقال ذو رقم المُعرّف 1 و المقال ذو رقم المُعرّف 3، أمّا <code>Abdelhadi</code> فهو صاحب المقال ذي المُعرّف 2 أمّا المقال الأخير فمن الواضح بأنّ المُستخدم <code>Hassan</code> هو من أضافه.
</p>

<p>
	هذه هي علاقة الواحد للعديد ببساطة، عندما يمتلك سجلّ واحد من جدول العديد من السّجلّات في جدول آخر، فإنّنا نُضيف عمودا إلى الجدول الذي يحمل العديد من السّجلات ليحمل كل سجلّ منه قيمة المفتاح الأولي Primary Key للسّجل الواحد في الجدول الآخر والذي يُسمّى فيه مفتاحا أجنبيا Foreign Key، أي أنّ العمود <code>user_id</code> عبارة عن مفتاح أجنبي لأنّه يحمل قيمة المفتاح الأولي الخاصّ بالمُستخدم، وعندما نقوم بتحديد عمود على أنّه مفتاح أجنبي، فالعلاقة بين الجدولين تكون مفهومة بالنّسبة لقاعدة البيانات لدينا، كما يُساعدنا ذلك على تخطّي بعض المشاكل في حالة ما أضيفت قيمة خاطئة إلى العمود عوضا عن قيمة صحيحة.
</p>

<p>
	في SQLAlchemy يُمكننا إنشاء علاقة واحد للعديد بسهولة وبساطة بإضافة سطرين فقط إلى الشفرة التّي حدّدناها سابقا، سطر في صنف (جدول) المقالات لإضافة عمود باسم <code>author_id</code> والذي سيكون عبارة عن مفتاح أجنبي يُشير إلى قيمة المفتاح الأولي للمُستخدم، وسطر في صنف المُستخدم لنتمكّن من الوصول إلى مقالات كل مُستخدم ببساطة.
</p>

<p>
	أضف هذا السّطر في آخر الصّنف <code>Post</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<code class="hljs mathematica"><span class="com"># project/models.py</span><span class="pln">

author_id </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="hljs-keyword"><span class="typ">Column</span></span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="hljs-keyword"><span class="typ">Integer</span></span><span class="pun">,</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">ForeignKey</span><span class="pun">(</span><span class="hljs-string"><span class="str">'users.id'</span></span><span class="pun">),</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span></code></pre>

<p>
	لتعريف مفتاح أجنبي، نستعمل الدّالة <code>db.ForeignKey</code> مع تمرير اسم الجدول واسم المفتاح الأولي مفصولين بنُقطة (في هذا المثال <code>users.id</code>) ونقوم كذلك بإضافة المُعامل <code>nullable</code> وإسناد القيمة المنطقيّة <code>False</code> له للتأكّد من أنّ الحقل الذي يربط بين المُستخدم والمقال الذي أضافه لا يحمل قيمة فارغة.
</p>

<p>
	بعد إضافة المفتاح الأجنبي، حان الوقت لإخبار SQLAlchemy بأنّنا نريد الحصول على مقالات كلّ مُستخدم، والمُستخدم الذي أضاف كلّ مقال انطلاقا من العلاقة بين الجدولين، لذا أضف السّطر التّالي في آخر الصّنف <code>User</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># project/models.py</span></span><span class="pln">

posts </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="pln">relationship</span><span class="pun">(</span><span class="hljs-string"><span class="str">"Post"</span></span><span class="pun">,</span><span class="pln"> backref</span><span class="pun">=</span><span class="hljs-string"><span class="str">"author"</span></span><span class="pun">,</span><span class="pln"> lazy</span><span class="pun">=</span><span class="hljs-string"><span class="str">"dynamic"</span></span><span class="pun">)</span></code></pre>

<p>
	في هذا السّطر، نقوم بتعريف العلاقة بين المُستخدم والمقال عن طريق الدّالّة <code>db.relationship</code> مع تمرير ثلاثة مُعاملات، الأول عبارة عن اسم الصّنف الذي يشير لجدول المقالات، والمُعامل <code>backref</code> يُمكّننا من الوصول إلى المُستخدم الذي كتب المقال عن طريق الاسم <code>author</code> أمّا المعامل الأخير فهو لتحديد نوعيّة النّتيجة التّي سنحصل عليها عند طلب جميع المقالات التّي كتبها أحد المُستخدمين، وقد وضعنا القيمة <code>dynamic</code> لتكون النّتيجة عبارة عن استعلام ديناميكي لجميع المقالات التّي كتبها المُستخدم، وهكذا سنحصل على مرونة أكثر عند طلب المقالات وسنتمكّن من التّعامل معها على أنّها كائنات يُمكننا استغلالها بجميع ما توفّره مكتبة SQLAlchemy من طرق ودوال مُساعدة، وسنرى تطبيقا لهذا الكلام فيما بعد.
</p>

<p>
	سنُضيف كذلك عمود <code>author_id</code> إلى التّابع <code>__init__</code> الخاصّة بالصّنف <code>Post</code> وبالتّالي سيُصبح التّابع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8961_9" style="">
<code class="hljs python"><span class="pln">    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__init__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> author_id</span><span class="pun">,</span><span class="pln"> created_date </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> title
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">content </span><span class="pun">=</span><span class="pln"> content
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">author_id </span><span class="pun">=</span><span class="pln"> author_id
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">created_date </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">utcnow</span><span class="pun">()</span></code></pre>

<p>
	بعد تحديد العلاقة بين الجدولين، سنستطيع إضافة مقال وإسناد رقم مُعرّف المُستخدم أو المُستخدم ككاتب للمقال الذي أضافه لنتمكّن فيما بعد من الحصول على كاتب كل مقال بجميع معلوماته (بريده الإلكتروني، اسمه …)، وكذا المقالات التّي كتبها كلّ مُستخدم مع مرونة في التّعامل معها عبر ما تُوفّره لنا مكتبة SQLAlchemy من مُساعدة.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	بعد أن تعرّفنا على طريقة ربط المُستخدم ومقالاته والمقالات وكاتبها، أصبحنا نستطيع تطبيق التّغييرات إلى قاعدة بياناتنا والتّعامل مع السّجلّات بعمليّات قواعد البيانات المعروفة اختصارا بـCRUD أو Create, Read, Update, Delete، أي الإضافة/الإنشاء، القراءة/العرض، التّعديل والحذف.<br>
	 
</p>
]]></description><guid isPermaLink="false">512</guid><pubDate>Thu, 20 Jul 2017 06:12:18 +0000</pubDate></item><item><title>&#x62A;&#x62C;&#x647;&#x64A;&#x632; &#x62C;&#x62F;&#x648;&#x644;&#x64A; &#x627;&#x644;&#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645;&#x64A;&#x646; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x625;&#x636;&#x627;&#x641;&#x629; Flask-SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%AC%D9%87%D9%8A%D8%B2-%D8%AC%D8%AF%D9%88%D9%84%D9%8A-%D8%A7%D9%84%D9%85%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-flask-sqlalchemy-r510/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_07/main.png.ac6cb5a23495898c30edbbf236701721.png" /></p>

<h2>
	مُقدّمة
</h2>

<p>
	بعد تجهيز قاعدة بيانات PostgreSQL التي سنستعملها في تطبيقنا، وبعد أن تعرّفنا في <a href="https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%AC%D9%87%D9%8A%D8%B2-%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-flask-sqlalchemy-r508/" rel="">الدرس السابق</a> على كيفيّة تنصيب وتجهيز كل من مكتبة SQLAlchemy و إضافة Flask-SQLAlchemy، حان الوقت لتجهيز جدولين من أهم جداول تطبيقات إدارة المحتوى، ألا وهي جدول المقالات الذي يمثل المحتوى بعينه وجدول المُستخدمين الذين سيُدِيرُون المحتوى، وبالتالي فسنقوم في هذا الدرس بوضع أساس لتطبيق “إدارة المحتوى” عبر تجهيز الطرف الذي سيقوم بالإدارة والطرف الذي يُمثل المحتوى.
</p>

<h2 id="تذكير">
	تذكير
</h2>

<p>
	نعلم بأنّ قاعدة البيانات تحتوي على عدة جداول، كل جدول يمثل نوعا من المحتوى، وكل جدول يشمل عدة أعمدة، فمثلا جدول المُستخدمين سيحتوي على عمود لأسماء المستخدمين، وعمود لكلمات المرور، بحيث تكون قيمة كل عمود مربطة بمستخدم واحد فقط.
</p>

<p>
	تعرّفنا في الدرس السابق على الشكل العام لجداول قاعدة البيانات عند استعمال إضافة Flask-SQLAlchemy وقلنا بأنّ جدولا باسم <code>table_name</code> سيكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4656_7" style="">
<span class="kwd">from</span><span class="pln"> project </span><span class="kwd">import</span><span class="pln"> db

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">TableName</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    __tablename__ </span><span class="pun">=</span><span class="pln"> </span><span class="str">'table_name'</span><span class="pln">
    column_name </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Type</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	الجدول به عمود واحد باسم <code>column_name</code> ونقوم بإخبار SQLAlchemy بأنّ هذا عمود في الجدول عبر استخدام التّابع <code>db.Column</code> الذي يقبل عدّة معاملات لتحديد نوعية العمود وما يمكن له أن يقبل من قيم.
</p>

<p>
	نقوم بتحديد نوع البيانات التي يجب أن يقبلها العمود عبر استخدام المعامل <code>db.Type</code> مع استبدال <code>Type</code> بأحد الأنواع التي يدعمها SQLAlchemy.
</p>

<p>
	ما يلي أكثر أنواع القيم استخداما والتي يدعمها SQLAlchemy:
</p>

<ul>
<li>
		<p>
			Integer<br>
			الأعداد الصّحيحة
		</p>
	</li>
	<li>
		<p>
			String(size)<br>
			سلسلة نصيّة، <code>size</code> مُعامل يشير إلى أقصى قيمة لعدد المحارف في السّلسلة النّصيّة، مثلاString(25) يشير إلى أنّ العمود يُمكن أن يحمل سلسلة نصيّة بحدود خمسة وعشرين محرفا فقط ولا يُمكن تجاوز هذا الحد.
		</p>
	</li>
	<li>
		<p>
			Text<br>
			نوع للإشارة إلى أنّ هذا العمود يُمكن أن يحتوي على النّصوص الطّويلة.
		</p>
	</li>
	<li>
		<p>
			DateTime<br>
			نوع يُشير إلى أنّ العمود سيحمل تواريخ مُعبّر عنها بالكائن <code>datetime</code> في لغة بايثون، وسنستخدم هذا النّوع لوضع تاريخ نشر للمقال وتاريخ لانضمام مُستخدم معيّن.
		</p>
	</li>
</ul>
<p>
	يُساعد تحديد نوع القيم في العمود على تجنّب الكثير من الأخطاء، ومن المُفضّل أن تختار دائما النّوع الذي يُناسبك أكثر لتحفظ المساحة وتتجنّب بعض الهجمات المُمكنة، فمثلا لو كان نوع القيمة <code>Text</code> في حقل اسم المُستخدم لتمكّن أحدهم من وضع نص كاسم مُستخدم له، وإن عرضناه في صفحة لكانت تلك الصّفحة بشعة لوجود نص عوضا عن كلمة أو كلمتين، هذا بالإضافة إلى أنّ المساحة في الخادوم ستُستهلك بشكل غير معقول.
</p>

<p>
	أعلم بأنّ الكلام النّظري مُمل بعض الشّيء، لكنّه مهم جدّا لتفهم ما سنقوم به تاليّا، وسنرى تطبيقا لهذا الكلام عند إنشاء جدولي المقالات والمُستخدمين في ما بعد وأتمنّى أن تُساعد هذه المُقدّمة على تقليص الصّداع الذي يحدث عندما تتعلّم شيئا لأول مرّة.
</p>

<h2 id="تجهيز-جدول-المقالات">
	تجهيز جدول المقالات
</h2>

<p>
	بعد أن وضّحنا المفاهيم الأساسيّة، حان الوقت لتطبيق هذه المفاهيم وإنشاء الجداول التّي سنتعامل معها في تطبيقنا، تذكر بأنّ هذه الجداول عبارة عن أصناف بايثون عادية، ويجب عليك وضعها داخل ملفّ <code>models.py</code> المتواجد بمُجلّد <code>project</code>.
</p>

<p>
	سنبدأ بجدول المقالات الذي سيكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4656_7" style="">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/models.py</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> datetime </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> datetime
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> project </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> db

</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Post</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    __tablename__ </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"posts"</span></span><span class="pln">
    id </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Integer</span><span class="pun">,</span><span class="pln"> primary_key</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pun">)</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">String</span><span class="pun">(</span><span class="hljs-number"><span class="lit">255</span></span><span class="pun">),</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span><span class="pln">
    created_date </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">DateTime</span><span class="pun">)</span><span class="pln">

    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__init__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> title</span><span class="pun">,</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> created_date </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">title </span><span class="pun">=</span><span class="pln"> title
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">content </span><span class="pun">=</span><span class="pln"> content
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">created_date </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">utcnow</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__repr__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'&lt;title {} | {} &gt;'</span></span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span></code></pre>

<p>
	<strong>مُلاحظة:</strong> تذكّر بأنّ جميع الجداول التّي نعرّفها عبارة عن أصناف في ملفّ <code>project/models.py</code>.
</p>

<p>
	أولا، نقوم باستيراد الكائن <code>datetime</code> لنستعمله في تأريخ إضافة المقال، بعدها نستدعي الكائن <code>db</code> الذي عرّفناه سابقا، بعد ذلك نقوم بتطبيق مفهوم الصّنف كجدول لإنشاء جدول المقالات باسم <code>Post</code> الذي يرث من <code>db.Model</code>، بعدها نقوم بتحديد اسم الجدول <code>posts</code> ثمّ نعرّف عمود رقم المُعرّف كمفتاح أولي، ثمّ العنوان كسلسلة نصيّة بحدود 255 حرفا، محتوى المقال كنصّ، تاريخ إضافة المقال من نوع <code>db.DateTime</code>.<br>
	بعد تعريف جميع الأعمدة، نعرّف الأعمدة التّي يُمكننا إدارتها عبر الدّالة <code>__init__</code>، وتشمل هذه الأعمدة حاليا العنوان والمحتوى وتاريخ الإضافة فقط، وإدارة تاريخ الإضافة اختياري لأنّنا سبق وأن وضعنا له قيمة افتراضيّة عبارة عن تاريخ إضافة السّجل إلى قاعدة البيانات والذي نصل إليه من الدّالة <code>datetime.utcnow</code>، الآن إن أردنا إضافة قيم إلى الجدول فسنحتاج إلى توفير عنوان المقال ومحتواه فقط، أمّا العمودان الآخران فيهتمّ بهما SQLAlchemy.<br>
	بعد الانتهاء من التّابع الخاص <code>__init__</code> نعرّف التّابع الخاص <code>__repr__</code> ليُساعدنا على عرض عنوان المقال ومحتواه بعد استعلامه بـSQLAlchemy ككائن، وقد سبق وأن شرحت وظيفة هذه الدّالة الخاصّة في درس البرمجة كائنيّة التوجّه ضمن سلسلة تعلّم بايثون، وسنرى في ما بعد نتيجة هذه الدّالة وبماذا ستُفيدنا.
</p>

<h2 id="تجهيز-جدول-المستخدمين">
	تجهيز جدول المُستخدمين
</h2>

<p>
	سنقوم بإنشاء جدول المُستخدمين بنفس الطريقة، صنف باسم <code>User</code>، جدول باسم <code>users</code>، رقم مُعرّف كقيمة أوليّة، اسم مُستخدم، بريد إلكتروني، كلمة المرور، وتاريخ الانضمام.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4656_7" style="">
<code class="hljs python"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">User</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    __tablename__ </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"users"</span></span><span class="pln">
    id </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">Integer</span><span class="pun">,</span><span class="pln"> primary_key</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pun">)</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">String</span><span class="pun">(</span><span class="hljs-number"><span class="lit">25</span></span><span class="pun">),</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">String</span><span class="pun">(</span><span class="hljs-number"><span class="lit">25</span></span><span class="pun">),</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">String</span><span class="pun">(</span><span class="hljs-number"><span class="lit">25</span></span><span class="pun">),</span><span class="pln"> nullable</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pun">)</span><span class="pln">
    created_date </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">(</span><span class="pln">db</span><span class="pun">.</span><span class="typ">DateTime</span><span class="pun">)</span><span class="pln">

    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__init__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> email</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">,</span><span class="pln"> created_date </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">email </span><span class="pun">=</span><span class="pln"> email
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">password </span><span class="pun">=</span><span class="pln"> password
        </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">created_date </span><span class="pun">=</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">utcnow</span><span class="pun">()</span><span class="pln">

    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__repr__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'&lt;username: {} | email: {} &gt;'</span></span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">email</span><span class="pun">)</span></code></pre>

<p>
	هذه المرّة سيتوجّب علينا تحديد كلّ من اسم المُستخدم، كلمة المرور وبريده الإلكتروني إذا أردنا إضافة سجل مُستخدم إلى قاعدة البيانات، أمّا الدّالّة <code>__repr__</code> فستعرض كلّا من اسم المُستخدم وبريده الإلكتروني.
</p>

<p>
	<em>مُلاحظة:</em> حاليّا نقوم بتخزين كلمات المرور على شكل نصوص واضحة، ويُمكن لأي شخص أن يحصل عليها ببساطة إن استطاع الوصول إلى قاعدة بيانات التّطبيق، وهذا أمر خطير جدّا، إذ أنّ حماية بيانات مُستخدمي التّطبيق أمر مهم جدّا، ولابد من تشفير كلمات المرور قبل إدخالها إلى قاعدة البيانات، وسنقوم بذلك فيما بعد، فالهدف الرّئيسي من هذا الدّرس هو إعطاؤك مقدّمة لكيفيّة تجهيز الجداول في قاعدة البيانات أمّا الحماية فسنتطرّق إليها لاحقا، لذا لا تحاول القيام بتخزين كلمات المرور بهذه الطّريقة، وتابع السّلسلة إلى نهايتها لتتعلّم كيفيّة تطوير تطبيقاتك بإطار العمل Flask بشكل آمن.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	بعد أن تعرّفنا على كيفيّة تجهيز جداول قاعدة البيانات التّي سنتعامل معها في تطبيقنا باستعمال مكتبة SQLAlchemy وإضافة Flask-SQLAlchemy وتعرّفنا على بعض المفاهيم المُهمّة في التّعامل مع قواعد البيانات بهذه المكتبة، بقيت نقطة مهمّة يجب الإشارة إليها قبل إنشاء الجداول في قاعدة البيانات وجلب، إضافة وتعديل وحذف السّجلات منها، ألا وهي علاقة الواحد للعديد One-to-Many Relationship، وهي العلاقة التّي سنستكشفها وسنستعملها لربط كلّ مقال بالمُستخدم الذي أضافه وربط المقالات بكاتبها في الدّرس القادم.
</p>
]]></description><guid isPermaLink="false">510</guid><pubDate>Fri, 14 Jul 2017 06:28:00 +0000</pubDate></item><item><title>&#x62A;&#x62C;&#x647;&#x64A;&#x632; &#x625;&#x636;&#x627;&#x641;&#x629; Flask-SQLAlchemy</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%AC%D9%87%D9%8A%D8%B2-%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-flask-sqlalchemy-r508/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_07/main.png.00565e569fcf088be79b8630f31efe5a.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	لا شك بأنّ معظم تطبيقات اليوم تعتمد على نوع من أنواع البيانات، لذا لا بدّ من حفظها في مكان مُناسب، وتعتبر <a href="https://academy.hsoub.com/devops/servers/databases/" rel="">قواعد البيانات</a> التّي يُمكن التّعامل معها بلغة SQL أحد أفضل الطّرق لحفظ بيانات تطبيقات الويب، وبما أنّنا أنشأنا قاعدة بيانات خاصّة بنا، فقد حان الوقت للتعرف على كيفية استعمال مكتبة SQLAlchemy لإدارة قاعدة بيانات تطبيقنا. في هذا الدرس، سنتعرف على كيفية تجهيز إضافة Flask-SQLAlchemy لتسهيل العمل مع مكتبة SQLAlchemy.
</p>

<h2 id="تنصيب-إضافة-flask-sqlalchemy">
	تنصيب إضافة Flask-SQLAlchemy
</h2>

<p>
	تأكّد أولا من أنّ البيئة الوهميّة مفعّلة عندك وأنّك في مُجلّد <code>kalima</code>، وبعدها نفّذ الأمر التّالي لتنصيب الإضافة مع مكتبة <code>psycopg2</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<span class="pln">pip install </span><span class="typ">Flask</span><span class="pun">-</span><span class="typ">SQLAlchemy</span><span class="pln"> psycopg2</span></pre>

<p>
	لكي نتمكّن من التّعامل مع قاعدة بيانات PostgreSQL باستعمال SQLAlchemy يجب تنصيب مكتبة <code>psycopg2</code> التّي تُمكنّنا من ذلك.
</p>

<p>
	<strong>مُلاحظة:</strong> تعتمد الإضافة أساسا على مكتبة SQLAlchemy لذا ستُنصّب كذلك، هذا يعني بأنّك تستطيع الوصول إلى جميع الدّوال والكائنات المُتواجدة في المكتبة إن أردت ذلك.
</p>

<p>
	لاختبار نجاح التّنصيب، افتح مفسّر بايثون وقم باستيراد الحزم التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs java"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> flask_sqlalchemy
</span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> sqlalchemy</span></code></pre>

<p>
	إن لم يحدث أي خطأ فالحزمة مُنصّبة بنجاح، وإن واجهت أي خطأ فحاول التّأكد من أنّك اتّبعت ما ذكرته في الدّروس الأولى من السّلسلة بشكل صحيح.
</p>

<h3 id="تذكير">
	تذكير
</h3>

<p>
	قواعد البيانات من نوع SQL تعتمد بشكل رئيسيّ على الجداول Tables، كلّ جدول يحمل أعمدة مُختلفة، وكلّ عمود يحمل قيما معيّنة، وهناك عمود خاصّ يسمى برقم المُعرّف وعادة ما يُشار إليه بـid ولأنّ كل مُدخل من المُدخلات يحمل رقم مُعرّف فريدا، فسيُمكّننا من تمييز المُستخدمين والمقالات وبقيّة الأجزاء المُهمّة في تطبيقاتنا، وقد سبق وأن شرحت هذا في درس ربط تطبيق <a href="https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-sqlite-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r346/" rel="">Flask مع قاعدة بيانات SQLite</a>، لذا عد إلى ذلك الدّرس لتفهم أكثر.
</p>

<h2 id="ربط-التطبيق-بإضافة-flask-sqlalchemy">
	ربط التّطبيق بإضافة Flask-SQLAlchemy
</h2>

<p>
	لربط التّطبيق مع إضافة Flask-SQLAlchemy نقوم أولا باستيراد SQLAlchemy من حزمة الإضافة بالسّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/__init__.py</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> flask_sqalchemy </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">SQLAlchemy</span></code></pre>

<p>
	وبعدها نقوم بتمرير كائن التّطبيق <code>app</code> إلى ما قمنا باستيراده وإسناد النّاتج إلى مُتغيّر باسم <code>db</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># project/__init__.py</span></span><span class="pln">

db </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SQLAlchemy</span><span class="pun">(</span><span class="pln">app</span><span class="pun">)</span></code></pre>

<p>
	سنقوم كذلك بإضافة سطرين لإعدادات التّطبيق <code>app.config</code>، السّطر الأول سيكون عبارة عن رابط قاعد البيانات، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs bash"><span class="pln">app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="hljs-string"><span class="str">'SQLALCHEMY_DATABASE_URI'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'postgresql://username:password@127.0.0.1/kalima'</span></span></code></pre>

<p>
	استبدل <code>username</code> بالمُستخدم الذي أنشأت به قاعدة البيانات وكلمة المرور بكلمة المرور التّي سبق أن حدّدتها، إن كنت على أحد أنظمة لينكس فالمُستخدم المبدئي هو <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-postgresql-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D8%B9%D9%84%D9%89-ubuntu-1404-r147/#%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D9%88%D8%A3%D8%AF%D9%88%D8%A7%D8%B1%D9%87-roles" rel=""><code>postgres</code></a> والعنوان <code>127.0.0.1</code> يُشير إلى أنّنا سنعتمد على قاعدة بياناتنا المحليّة، أمّا <code>kalima</code> فهو اسم قاعدة البيانات التّي أنشأناها سابقا.
</p>

<p>
	السّطر الثّاني غير مُهم وقد لا تحتاج إليه في قادم النّسخ من إضافة <code>Flask-SQLAlchemy</code>، وقد قمت بإضافته لإخفاء تنبيه يظهر بعد تشغيل الخادوم.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs mathematica"><span class="pln">app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="hljs-string"><span class="str">'SQLALCHEMY_TRACK_MODIFICATIONS'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">True</span></span></code></pre>

<p>
	<strong>مُلاحظة:</strong> من المعروف بأنّ التّطبيق يمر عبر عدّة مراحل، مرحلة التّطوير، الاختبار ثمّ مرحلة الإنتاج (النّشر إلى العالم الخارجي)، وعادة ما تُعزل كلّ مرحلة عن الأخرى فيما يُسمّى بالبيئة، ولذا تسمع مُصطلحات كبيئة التّطوير Development Environment، بيئة الاختبار Testing Environment، <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A9-%D9%84%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%A7%D8%AC-r132/" rel="">بيئة الإنتاج Production Environment</a>، وإعدادات كلّ بيئة تكون مختلفة عن البيئات الأخرى، ولهذا يعدّ تخزين الإعدادات في الملفّ الرّئيسي للمشروع أمر سيئا لأنّك ستضطر إلى تغيير الإعدادات في كل مرّة تنتقل فيها من بيئة إلى أخرى، وقد يُشكل إعداد خاطئ واحد خطرا كبيرا على تطبيقك، خاصّة إن كان التّطبيق ذا وظائف مُتعدّدة، والحل الأمثل هو تخزين هذه الإعدادات في ملفّ مُستقل وهذا الأمر مهم جدا وقد <a href="https://academy.hsoub.com/programming/python/flask/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-pythonanywhere-r423/" rel="">سبق وأن شرحت</a> طريقة بسيطة للقيام بذلك، وسنتطرّق إليه بالتّفصيل في ما بعد، المهم الآن أن تُدرك بأنّ كل ما يقع تحت قاموس <code>app.config</code> عبارة عن إعداد من إعدادات التّطبيق.
</p>

<p>
	بعد ربط كائن التّطبيق بإضافة <code>Flask-SQLAlchemy</code> سنتمكّن من استغلال الكائن <code>db</code> للاستفادة من كل ما تمنحه لنا الإضافة من تسهيلات للعمل مع مكتبة SQLAlchemy.
</p>

<p>
	ومع التّغييرات التّي قُمنا بها سيُصبح الجزء العلوي من ملفّ <code>project/__init__.py</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/__init__.py</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> flask </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Flask</span><span class="pun">,</span><span class="pln"> render_template

app </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Flask</span><span class="pun">(</span><span class="pln">__name__</span><span class="pun">)</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="hljs-string"><span class="str">'SQLALCHEMY_DATABASE_URI'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'postgresql://username:password@127.0.0.1/kalima'</span></span><span class="pln">
app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="hljs-string"><span class="str">'SQLALCHEMY_TRACK_MODIFICATIONS'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> flask_sqlalchemy </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">SQLAlchemy</span><span class="pln">
db </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SQLAlchemy</span><span class="pun">(</span><span class="pln">app</span><span class="pun">)</span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> project</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">.</span><span class="pln">views </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> posts
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> project</span><span class="pun">.</span><span class="pln">users</span><span class="pun">.</span><span class="pln">views </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> users

app</span><span class="pun">.</span><span class="pln">register_blueprint</span><span class="pun">(</span><span class="pln">posts</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">register_blueprint</span><span class="pun">(</span><span class="pln">users</span><span class="pun">)</span></code></pre>

<p>
	تأكّد فقط من أنّ الإعدادين يقعان مُباشرة بعد تعريف الكائن <code>app</code> وأنّ استيراد الطّبعات الزّرقاء Blueprints وتسجيلها يقع بعد تعريف المُتغيّر <code>db</code> لتجنّب بعض المشاكل التّي قد تحدث عندما تعتمد كل حزمة على الأخرى أثناء الاستيراد أو ما يُسمى بـ circular imports أو الاستيرادات الدّائريّة.
</p>

<h2 id="الجداول-في-flask-sqlalchemy">
	الجداول في Flask-SQLAlchemy
</h2>

<p>
	لتجهيز الجداول في التّطبيق، سنفتح أولا ملفّا جديدا باسم <code>models.py</code> في مجلّد <code>project</code>، وسنضع فيه كل ما يتعلّق بالجداول وطريقة تسجيلها والبيانات المبدئية.
</p>

<p>
	وطريقة إنشاء الجداول في Flask-SQLAlchemy هي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs haskell"><span class="hljs-title"><span class="kwd">from</span></span><span class="pln"> project </span><span class="hljs-import"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> db</span></span><span class="pln">
</span><span class="hljs-class"><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-type"><span class="typ">TableName</span></span><span class="hljs-container"><span class="pun">(</span><span class="hljs-title"><span class="pln">db</span></span><span class="pun">.</span><span class="hljs-type"><span class="typ">Model</span></span><span class="pun">)</span></span><span class="pun">:</span><span class="pln">
    __tablename__ </span><span class="pun">=</span><span class="pln"> </span><span class="str">'table_name'</span><span class="pln">
    column_name </span><span class="pun">=</span><span class="pln"> db</span><span class="pun">.</span><span class="hljs-type"><span class="typ">Column</span></span><span class="hljs-container"><span class="pun">(</span><span class="hljs-title"><span class="pln">db</span></span><span class="pun">.</span><span class="hljs-type"><span class="typ">Type</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-title"><span class="pln">args</span></span><span class="pun">)</span></span>
</span></code></pre>

<p>
	كما ترى، نقوم أولا باستيراد الكائن <code>db</code> من حزمة المشروع ثمّ نقوم بإنشاء صنف باسم الجدول، ولابد لهذا الصّنف أن يرث من الصّنف <code>db.Model</code> الذي تُوفّره لنا إضافة Flask-SQLAlchemy، بعدها نقوم بتسميّة الجدول عبر وضع اسمه على شكل سلسلة نصيّة وإسنادها للمُتغيّر الخاصّ <code>__tablename__</code>، ثمّ بعد ذلك نقوم بتعريف مُختلف أسماء الأعمدة وإسنادها قيمة عن طريق التّابع <code>db.Column</code>، ثمّ نُخصّص نوع قيم العمود وبعض المُعاملات الإضافيّة، وأحد أشهر المُعاملات هو مُعامل <code>primary_key</code> الذي يجعل من العمود مفتاحا أوليا إن أسندت له القيمة المنطقيّة <code>True</code> وعادة ما يُستخدم مع عمود رقم المُعرّف <code>id</code>، والمُعامل الآخر الذي ستصادفه كثيرا هو مُعامل <code>nullable</code> ويقبل كذلك القيمتين المنطقيّتين <code>True</code> و <code>False</code> فإن كانت قيمة المُعامل <code>False</code> فهذا يعني بأنّ العمود لا يمكن أن يحمل قيمة فارغة، ويُستعمل في الأعمدة المُهمّة كالبريد الإلكتروني وكلمة المرور، ويُمكن أن تسمح بأن تكون قيم العمود فارغة إن لم يكن توفير المعلومة ضروريا مثل نبذة عن المُستخدم وصورته الشّخصيّة أو اسمه الحقيقي وهذه الأمور تختلف حسب نوعيّة التّطبيق بكل تأكيد.
</p>

<p>
	المفتاح الأولي Primary Key عبارة عن عمود يحمل قيما فريدة في الجدول بأكمله، ولا يُمكن أن تكون قيمته فارغة ولكنّنا لا نحتاج إلى إضافة المُعامل <code>nullable</code> عند تعريف العمود، ويُستعمل لتعريف كل سجلّ من سجلّات الجدول على حدة، ومن المُفضّل أن يكون نوعه عددا صحيحا لحفظ بعض المساحة، ولإبقاء القيم فريدة ومُختلفة عن بعضها البعض، يضاف واحد إلى القيمة السّابقة عند كل إضافة إلى قاعدة البيانات، وكما قُلت سابقا، الطّريقة الشّائعة لاستخدامه هو بوضع عمود باسم <code>id</code> في الجدول ليحمل القيم الفريدة على شكل أعداد صحيحة، فمثلا لو كان لدينا قاعدة بيانات بأسماء ما كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7625_7" style="">
<code class="hljs 1c"><span class="pln">id </span><span class="hljs-string"><span class="pun">|</span><span class="pln"> name</span></span><span class="pln">
 </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="pun">أحمد</span></span><span class="pln">
 </span><span class="hljs-number"><span class="lit">2</span></span><span class="pln"> </span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="pun">مُحمّد</span></span><span class="pln">
 </span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="hljs-string"><span class="pun">|</span><span class="pln"> </span><span class="pun">أحمد</span></span></code></pre>

<p>
	للوهلة الأولى يبدو بأنّ سجلّ أحمد قد كرّر مرّتين، لكن لاحظ رقم المُعرّف الخاص بكل سجلّ، أحمد الأول رقم مُعرّفه 1 والآخر 3، هذا يعني بأنّهما شخصان مُختلفان بنفس الاسم، لا بد أنّك أدركت الآن مدى أهميّة المفتاح الأولي، فلو كان تطبيقنا يسمح بتسجيل المُستخدمين بأسمائهم لوجدنا مُشكلة مع أحمد هذا، لكنّ رقم المُعرّف يقوم بحل المُشكلة.
</p>

<p>
	أمّا عن <code>db.Type</code> فهو لتحديد نوع القيم التي سيحملها العمود، وهي مُشابهة لأنواع القيم المُتاحة في لغة SQL، مثل العدد الصّحيح Integer والسّلسلة النّصيّة String (VARCHAR في لغة SQL) والتّاريخ وغير ذلك من أنواع القيم.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	قمنا في هذا الدرس بتجهيز أداة SQLAlchemy وتعرّفنا على كيفيّة استخدام إضافة Flask-SQLAlchemy للتعامل معها وألقينا نظرة بسيطة إلى الصورة العامة لجدول SQL مكتوب بلغة بايثون. في الدرس القادم، سنقوم بإنشاء جدولي المقالات والمُستخدمين في قاعدة بياناتنا.
</p>
]]></description><guid isPermaLink="false">508</guid><pubDate>Thu, 06 Jul 2017 11:48:59 +0000</pubDate></item><item><title>&#x62A;&#x62C;&#x647;&#x64A;&#x632; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; PostgreSQL &#x648;&#x627;&#x644;&#x62A;&#x651;&#x639;&#x631;&#x64A;&#x641; &#x628;&#x645;&#x641;&#x647;&#x648;&#x645;&#x64A; ORM &#x648;&#x625;&#x636;&#x627;&#x641;&#x627;&#x62A; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%AC%D9%87%D9%8A%D8%B2-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D9%88%D8%A7%D9%84%D8%AA%D9%91%D8%B9%D8%B1%D9%8A%D9%81-%D8%A8%D9%85%D9%81%D9%87%D9%88%D9%85%D9%8A-orm-%D9%88%D8%A5%D8%B6%D8%A7%D9%81%D8%A7%D8%AA-flask-r506/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.4df799222bc6180d2fb0b6b4045180a8.png" /></p>

<h2 id="تجهيز-قاعدة-البيانات">
	تجهيز قاعدة البيانات
</h2>

<p>
	بما أنّنا سنستخدم قاعدة البيانات PostgreSQL لهذا التّطبيق، عليك أولا أن تقوم بتنصيبها، إن كنت تستخدم Ubuntu فيُمكنك مُراجعة <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-postgresql-%D9%88%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87-%D8%B9%D9%84%D9%89-ubuntu-1404-r147/" rel="">درس كيفيّة تنصيب PostgreSQL على Ubuntu</a>، أمّا إن كنت على نظام Windows أو نظام Mac OS فتستطيع تحميلها من الموقع الرّسمي وتنصيبها، يُمكنك كذلك استخدام برنامج pgAdmin لإدارة قواعد بياناتك عن طريق برنامج رسومي.
</p>

<p>
	يُمكنك استعمال البرنامج الرّسومي لإنشاء قاعدة البيانات إن أردت ذلك، لكنّنا سنستعمل أداة psql لتنفيذ أوامر PostgreSQL واستعمال لغة <a href="https://academy.hsoub.com/tags/sql/" rel="">SQL</a> مباشرة من سطر الأوامر، لذا تأكّد من أنّك تستطيع الوصول إلى أداة psql.
</p>

<h3 id="إنشاء-قاعدة-البيانات">
	إنشاء قاعدة البيانات
</h3>

<p>
	لإنشاء قاعدة البيانات، يكفي أن ننفّذ الأمر التّالي على سطر أوامر psql :
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1261_7" style="">
<span class="pln">CREATE DATABASE kalima</span><span class="pun">;</span></pre>

<p>
	بعد تنفيذ الأمر، سيكون المُخرج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1261_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">CREATE</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">DATABASE</span></span></span></code></pre>

<h3 id="كلمة-المرور">
	كلمة المرور
</h3>

<p>
	للاتّصال بقاعدة البيانات، سنحتاج إلى كلمة مرور، إن سبق لك وأن خصّصت كلمة مرور أثناء التّنصيب، تستطيع تخطي هذه الخطوة، أمّا إن لم تمتلك كلمة مرور أو أنّك نسيتها، فيُمكنك ببساطة تغييرها في سطر أوامر psql بالأمر التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1261_7" style="">
<code class="hljs tex"><span class="hljs-command"><span class="pln">\password</span></span></code></pre>

<p>
	بعد تنفيذ الأمر سيُطلب منك كتابة كلمة مرور جديدة وإعادة كتابتها للتّأكد من أنّك لم تُخطئ.<br>
	كلمة المرور هذه مُهمّة جدا للاتّصال بقاعدة البيانات من تطبيق فلاسك باستخدام أداة SQLAlchemy لذا تأكّد من أنّها مُتاحة.
</p>

<h3 id="ما-معنى-orm">
	ما معنى ORM؟
</h3>

<p>
	ORM اختصار Object-Relational Mapper أي رابط الكائنات بالعلاقات (الجداول)، الهدف منه ببساطة التّعامل مع قواعد بيانات SQL باستعمال الكائنات Objects والأصناف Classes عوضا عن تعليمات SQL، فعوضا عن إنشاء البيانات وجلبها وتعديلها وحذفها عن طريق تعليمات SQL التّي ستتكرّر كثيرا في الشّفرة يُمكن ببساطة استخدام لغة بايثون للوصول إلى نفس الهدف، كما أنّ استعمالها مع لغة برمجة يخلق شيئا من عدم التّناسق.<br>
	لو تابعت <a href="https://academy.hsoub.com/tags/flask%20101/" rel="">سلسلة دروس Flask للمُبتدئين</a>، للاحظت بأنّنا استعملنا ملفّا باسم <code>manage_db</code> للتّعامل مع قواعد البيانات عن طريق الدّوال عوضا عن كتابة تعليمات SQL عند الرّغبة في إجراء كل عمليّة، ولو استعملنا SQL الخام لكان تكرار الشّفرة كثيرا.<br>
	بالإضافة إلى ميّزة تعريف الأصناف التّي تُمثّل الجداول والتّعامل معها عن طريق التّوابع (الدوال) لتجنّب تكرار الشّفرة، يقوم الـORM بالكثير من الأشياء المُملّة خلف الكواليس، فعوضا عن الاهتمام بالتّفاصيل الصّغيرة بأنفسنا، يقوم الـORM بالاهتمام بها من أجلنا لنهتمّ بالأمور الأكثر أهميّة، وفي النّهاية، مُعظمنا لا يتقن لغة SQL كثيرا لذا من المُفضّل استعمال مكتبة للتّعامل مع قواعد البيانات باللغة التّي نُجيدها.<br>
	وبما أنّ استعمال الـORM يُتيح لنا عزل الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في معزل عن التّطبيق فهذا يُتيح لنا تعديل الخصائص وإضافة الميّزات للتّطبيقات دون التّأثير على تطبيق معيّن بحد ذاته، ومن الشّائع جمع الشّفرة المسؤولة عن التّعامل مع قاعدة البيانات في ملف باسم <code>models.py</code> في مجلّد المشروع.
</p>

<p>
	يُساعدنا الـORM كذلك على تحقيق مبدأ <a href="https://academy.hsoub.com/programming/php/laravel/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-laravel-5-r218/#%D8%A8%D9%86%D9%8A%D8%A9-mvc" rel="">MVC</a> أو Model-View-Controller أي “نموذج، عرض، مُتحكّم ” وهو مبدأ يقوم على عزل جزء العرض، المُتحكّمات، والنّماذج في تطوير التّطبيقات لمرونة أكثر في التّطوير، أي أنّ كلّا من العرض (الذي يُمثّل القوالب في تطبيقنا) والمُتحكّم (الذي يُمثّل دوال الموجّهات في ملفّات <code>views.py</code>) والنّموذج (أي الجزء الذي يتعامل مع البيانات) أجزاء منفصلة حسب الوظيفة متّصلة في التّطبيق ويُمكن أن تنتقل البيانات بينها ببساطة، ورغم أنّ إطار Flask يمنحك الحريّة الكاملة في طريقة تسميّة أجزاء تطبيقك، إلّا أن أطر عمل أخرى مثل <a href="https://academy.hsoub.com/programming/python/django/" rel="">Django</a> و Rails تفرض عليك تسميّات محدّدة.
</p>

<h3 id="ما-هو-sqlalchemy">
	ما هو SQLAlchemy؟
</h3>

<p>
	بعد أن عرّفنا معنى الـORM بقي تعريف مكتبة SQLAlchemy، وهي مكتبة تُسهّل علينا التّعامل مع قواعد البيانات المُختلفة، كما أنّها تحتوي على ORM قوي ومُعتمد عليه من طرف المشاريع الكبيرة.
</p>

<p>
	تحتوي SQLAlchemy على الكثير من الدّوال المُساعدة والكائنات التّي تُسهّل عليك كتابة SQL بلغة بايثون، والORM المبني فيه يُستعمل لربط الكائنات بالبيانات في قاعدة البيانات.
</p>

<p>
	سنستعمل في غالب هذا المشروع الـORM الخاص بـSQLAlchemy ولن نتطرّق إلى بقيّة ميّزات المكتبة، لذا إن أردت معرفة المزيد عن المكتبة فعليك بالتّوثيق الرّسمي.
</p>

<h2 id="إضافات-flask">
	إضافات Flask
</h2>

<p>
	Flask Extensions أو إضافات فلاسك عبارة عن مكتبات وأطر عمل Frameworks مبنيّة لتُسهّل على المُطوّر القيام بالأشياء المُفصّلة وتجنّب التّعامل مع كل شيء بأنفسنا، فمثلا، يُمكننا أن نستعمل مكتبة SQLAlchemy مع تطبيق Flask مُباشرة، إلّا أن في هذه الطّريقة الكثير من الأمور غير المُهمّة والكثير من الإعدادات، وبما أنّنا في مسيرة تعلّم إطار فلاسك لا كيفيّة استعمال SQLAlchemy، ولتسهيل استعمال SQLAlchemy مع المشاريع المبنيّة بإطار العمل فلاسك، قام كاتب الإطار Armin Ronacher بتطوير إضافة للإطار باسم Flask-SQLAlchemy التّي أصبحت أحد أشهر الإضافات على موقع Github.
</p>

<p>
	بالإضافة إلى Flask-SQLAlchemy هناك الكثير من الإضافات التّي يُمكننا استعمالها لتطوير تطبيقات فلاسك، وإليك بعضا من هذه الإضافات:
</p>

<ul>
<li>
		<p>
			Flask-Login<br>
			إضافة لتسهيل التّعامل مع جلسات المُستخدمين Sessions، تُتيح إمكانيّة تسجيل دخول مُستخدم وتسجيل خروجه، لكنّها لا تقوم بالتّحقق من صحّة البيانات (اسم المُستخدم وكلمة المرور مثالا) وتترك المُطوّر للاهتمام بالأمر.
		</p>
	</li>
	<li>
		<p>
			Flask-Bcrypt<br>
			إضافة لتشفير كلمات المرور باستعمال خوارزميّة Bcrypt قبل حفظها بقاعدة البيانات لحماية أكثر، هذا لمنع المُخترق من سرقة كلمات المرور حتى بعد وصوله إلى قاعدة البيانات، وكلّما كانت خوارزميّة التّشفير أعقد كلّما كان من الصّعب فك التّشفير عن كلمة المرور ما يُوفّر حماية أكثر.
		</p>
	</li>
	<li>
		<p>
			Flask-WTF<br>
			بما أنّ مُعظم التّطبيقات تعتمد على نماذج HTML (حقول النّصوص، كلمات المرور و مساحة النّص TextArea) وبما أنّها تُسبّب الكثير من الثّغرات الأمنيّة في التّطبيقات والتّي يُمكن أن يُساء استغلالها، فلا بد من توفير طريقة آمنة وبسيطة للتأكّد من أنّ ما يُدخله المُستخدم في هذه الحقول آمن.<br>
			يُمكنك بالطّبع التّأكد من مُدخلات المُستخدم بنفسك، لكنّ الأمر يأخذ وقتا، كما أنّه ممل في الحقيقة، إذ عليك تكرار نفس الشّيء كلّ مرّة.<br>
			عوضا عن الاعتماد على مهاراتك البرمجيّة للتأكّد من سلامة المُدخلات، يُمكنك أن تترك إضافة Flask-WTF للاهتمام بالأمر في تطبيقاتك المبنيّة بإطار فلاسك، الإضافة مبنيّة على مكتبة WTForms التّي يُمكنك استعمالها مع أطر عمل أخرى، وأنصحك بالاطلاع على توثيق المكتبة الرّسمي للمزيد من المعلومات عن كيفيّة مُعالجة النّماذج.
		</p>
	</li>
	<li>
		<p>
			Flask-Migrate<br>
			ببساطة، Flask-Migrate إضافة تُتيح لك تهجير البيانات Migrations عند تطوير تطبيقك.<br>
			هذه الإضافة مهمّة جدّا إن كنت تطوّر تطبيقا سبق وأن نشرته على نحو مُتواصل، إذ تُتيح لك تهجير البيانات في كل مرّة تُضيف جدولا جديدا أو علاقة بين الجداول إلى قاعدة البيانات. تخيّل أنّك تمتلك تطبيقا يحتوي جدول المُستخدمين فيه على أكثر من ألف مُدخل، إن أردت إتاحة إمكانيّة إضافة تاريخ ازدياد للمُستخدمين فستضطر إلى حذف كلّ شيء في هذا الجدول وإضافة العمود الجديد ثمّ إعادة البيانات من جديد، الأمر مُعقّد بعض الشّيء وفقدان البيانات أمر غير مرغوب فيه بتاتا.<br>
			مُجدّدا عوضا عن القيام بكل شيء بنفسك، دع إضافة Flask-Migrate لتهتمّ بكل هذا التّعقيد من أجلك، فبسطر أو سطرين تستطيع تطبيق الميّزة الجديدة لتطبيقك وتهجير البيانات القديمة بكل بساطة.
		</p>
	</li>
	<li>
		<p>
			Flask-Testing<br>
			إضافة لتسهيل إجراء اختبارات وحدة Unit tests لتطبيقك، إذ أنّ اختبار التّطبيق مُهمّ جدّا للتأكّد من أنّ كلّ شيء بخير وأنّ المُستخدمين لا يواجهون أية مشاكل، خاصّة إذا كان مشروعك كبيرا، فاختبار كل وظيفة يدويّا قد يأخذ منك وقتا طويلا، وإن لم تختبره آليا فنسبة الخطأ كبيرة جدّا.<br>
			إذا أضفت خاصيّة جديدة لتطبيقك فأنت بذلك تُعرّض أجزاء أخرى من التّطبيق إلى الخطأ، وستُسهّل عليك الاختبارات معرفة ما إذا كان التّطبيق لا يزال يعمل كما ينبغي له أو لا، وبما أنّ اختبارات الوحدة تختبر كلّ وظيفة على نحو مُستقل، فسيسهل عليك معرفة أي جزء يجب عليك الاهتمام به لإصلاح التّطبيق.
		</p>
	</li>
	<li>
		<p>
			Flask-Gravatar<br>
			هذه الإضافة تُسهّل لنا استعمال خدمة Gravatar لتمكين المُستخدمين من إضافة صورة شخصيّة لهم، إذ تكون الصّورة الشّخصيّة مُرتبطة بالبريد الإلكتروني للمُستخدم وتُستعمل هذه الخدمة في الكثير من التّطبيقات في وقتنا الحالي.
		</p>
	</li>
</ul>
<p>
	هناك مئات الإضافات الخاصّة بإطار Flask لذا لا يُمكنني ذكرها كلّها، إن أردت الاطّلاع على إضافات أخرى، تستطيع البحث عنها عن طريق أداة pip كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1261_7" style="">
<code class="hljs "><span class="pln">pip search flask</span></code></pre>

<p>
	سنتعرّف على معظم هذه الإضافات في قادم الدّروس مع التّقدم في المشروع، وهذا الهدف الأساسي من هذه الإضافات، كلّما تقدّمت أكثر وكبر المشروع كلّما احتجت إلى التّعامل مع الكثير من المهام المُملّة كالتّأكد من أنّ ما يرسله المُستخدم إلى قاعدة بياناتك آمن، وكالتّعامل مع الجلسات لتوفير نظام تسجيل دخول آمن دون الاضطرار للقيام بكل التّفاصيل؛ كما أنّ الإضافات تُقلّل من حجم الخطأ في التّطوير، فالاعتماد على إضافة لتسجيل دخول المُستخدمين بشكل آمن أفضل من مُحاولة إنشاء طريقة خاصّة بك قد تكون مليئة بالثّغرات الأمنيّة.
</p>

<p>
	وبما أنّ فلاسك إطار عمل مُصغّر، فبإضافاته يُمكنك أن تستخدمه كما تُستخدم أطر العمل الضّخمة كـDjango و Rails و Laravel وغيرها من الأطر المشهورة.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	بعد أن أنشأنا قاعدة البيانات وتعرّفنا على بعض المفاهيم المُهمّة في تطوير تطبيقات الويب مع إطار فلاسك، حان الوقت لإنشاء الجداول الأساسيّة في قاعدة البيانات لنتمكّن من التّعامل معها عن طريق إضافة Flask-SQLAlchemy وهذا بالضّبط ما سنقوم به في الدّرس القادم.<br>
	 
</p>
]]></description><guid isPermaLink="false">506</guid><pubDate>Thu, 29 Jun 2017 09:11:36 +0000</pubDate></item><item><title>&#x62D;&#x644;&#x642;&#x629; &#x627;&#x644;&#x62A;&#x651;&#x643;&#x631;&#x627;&#x631; for &#x641;&#x64A; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AD%D9%84%D9%82%D8%A9-%D8%A7%D9%84%D8%AA%D9%91%D9%83%D8%B1%D8%A7%D8%B1-for-%D9%81%D9%8A-%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-r503/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.9393f825b1badc740712baf4ecb8fce6.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	تعرّفنا سابقا على حلقة التّكرار <code>for</code> للدّوران على عناصر قائمة أو مفاتيح وقيم قاموس بايثون، سنتعرّف الآن على تقنيات مُتقدّمة ستُساعدك على التّعامل مع حلقة <code>for</code> على نحو أفضل لتتمكّن من تصميم قوالب HTML مع مُحرّك القوالب Jinja بطريقة أسرع وأكثر إتقانا.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23742" data-unique="flhog08q4" src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.479f842b8ce37928381f068b00fe3c0e.png"></p>

<h2 id="استعمال-حلقة-for-مع-قائمة-بايثون">
	استعمال حلقة for مع قائمة بايثون
</h2>

<p>
	تُستعمل حلقة <code>for</code> مع قوائم بايثون عاديّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<span class="pun">{%</span><span class="pln"> set names </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Ahmed'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Khalid'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Ali'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Abdelhadi'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Yasser'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> name </span><span class="kwd">in</span><span class="pln"> names </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{{</span><span class="pln"> name </span><span class="pun">}}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endfor </span><span class="pun">%}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs "><span class="typ">Ahmed</span><span class="pln"> 
</span><span class="typ">Khalid</span><span class="pln"> 
</span><span class="typ">Ali</span><span class="pln"> 
</span><span class="typ">Abdelhadi</span><span class="pln"> 
</span><span class="typ">Yasser</span><span class="pln"> </span></code></pre>

<p>
	بهذه الطّريقة، يُمكنك عرض كل عنصر من القائمة داخل وسم HTML مُعيّن وتطبيق تنسيق باستخدام <a href="https://academy.hsoub.com/programming/css/" rel="">CSS</a> كما تشاء.
</p>

<h2 id="استعمال-حلقة-for-مع-قواميس-بايثون">
	استعمال حلقة for مع قواميس بايثون
</h2>

<p>
	بالإضافة إلى استعمالها مع قائمة عاديّة، يُمكنك كذلك استعمال حلقة for مع قاموس ما للوصول إلى مفاتيحه وقيّم كلّ مفتاح بحيث تدور حول القاموس لتحصل على كل مفتاح وقيمته، يُمكنك القيام بذلك ببساطة كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> website </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'academy.hsoub.com'</span><span class="pun">,</span><span class="pln">
                   </span><span class="str">'company'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hsoub'</span><span class="pun">,</span><span class="pln">
                   </span><span class="str">'description'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Learn new skills </span><span class="hljs-keyword"><span class="str">for</span></span><span class="str"> free'</span><span class="pln">
                 </span><span class="pun">}</span><span class="pln">
</span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">ul</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> website</span><span class="pun">.</span><span class="pln">iteritems</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">li</span></span><span class="str">&gt;</span></span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> key </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> value </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">li</span></span><span class="pun">&gt;</span></span><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pun">&gt;</span></span></span></code></pre>

<p>
	لاحظ بأنّنا نقوم بالوصول إلى محتويات القاموس عبر تطبيق التّابع <code>iteritems()</code> على المُتغيّر <code>website</code>، بحيث نحصل على المفتاح والقيمة عبر المُتغيّرين <code>key</code> و <code>value</code> على التّوالي، داخل حلقة <code>for</code> نقوم بعرض كلّ من المفتاح وقيمته داخل وسم <code>&lt;li&gt;</code>.
</p>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs cpp"><span class="pln">    url </span><span class="pun">:</span><span class="pln"> academy</span><span class="pun">.</span><span class="pln">hsoub</span><span class="pun">.</span><span class="pln">com

    company </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Hsoub</span><span class="pln">

    description </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Learn</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="pln"> skills </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">free</span></span></code></pre>

<p>
	يُمكنك كذلك استخدام تنسيقات <a href="https://academy.hsoub.com/programming/css/bootstrap/" rel="">إطار العمل Bootstrap</a> لعرض مُحتويات قاموس ما بشكل جميل.
</p>

<p>
	بالإضافة إلى ما سبق، يُمكنك كذلك إسناد قائمة بايثون على هيئة قيمة لمفتاح مُعيّن من القاموس، على سبيل المثال، يُمكن لمقال ما أن يحمل عنوانا واحدا وأكثر من تعليق واحد، بحيث تكون التّعليقات عناصر من قائمة بايثون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs livecodeserver"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">set</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">post</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'title'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Introduction to Flask'</span></span><span class="pun">,</span><span class="pln">
               </span><span class="hljs-string"><span class="str">'comments'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'Great!'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Thank you!'</span></span><span class="pun">]</span><span class="pln">
               </span><span class="pun">}</span></code></pre>

<h2 id="مثال-تطبيقي">
	مثال تطبيقي
</h2>

<p>
	لنجمع الآن الأفكار السّابقة ولنُصمّم صفحة HTML بسيطة لعرض معلومات شخص ما:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="xml"><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">'first_name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Ali'</span><span class="pun">,</span><span class="pln">
               </span><span class="str">'last_name'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Sayed'</span><span class="pun">,</span><span class="pln">
               </span><span class="str">'age'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'27'</span><span class="pun">,</span><span class="pln">
               </span><span class="str">'languages'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Arabic'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'English'</span><span class="pun">],</span><span class="pln">
               </span><span class="str">'Children'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Hassan'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Fatima'</span><span class="pun">],</span><span class="pln">
             </span><span class="pun">}</span><span class="pln">
</span><span class="pun">%}</span></span><span class="xml"><span class="pln">


</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"col-sm-4"</span></span><span class="pun">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group"</span></span><span class="pun">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group-item active"</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> person</span><span class="pun">[</span><span class="str">'first_name'</span><span class="pun">]}}</span></span><span class="xml"><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> person</span><span class="pun">[</span><span class="str">'last_name'</span><span class="pun">]}}</span></span><span class="xml"><span class="pln">
  </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">li</span></span><span class="pun">&gt;</span></span><span class="pln">
  </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> value </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> person</span><span class="pun">.</span><span class="pln">iteritems</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> value </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
         </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group-item"</span></span><span class="pun">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> key </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> value </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">li</span></span><span class="pun">&gt;</span></span><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
         </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group-item"</span></span><span class="pun">&gt;</span></span><span class="pln">
             </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> key </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> item </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> value </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><span class="pun">,</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
         </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">li</span></span><span class="pun">&gt;</span></span><span class="pln">
  </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pun">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">div</span></span><span class="pun">&gt;</span></span></span></code></pre>

<p>
	رغم أنّ الشّفرة مُعقّدة بعض الشّيء، إلّا أنّها في الحقيقة بسيطة، وستبدو لك كذلك إن تابعت الفقرتين السّابقتين من هذا الدّرس.
</p>

<p>
	إليك ما يحدث في الشّفرة أعلاه، أولا نُعرّف قاموسا باسم <code>person</code> ليحمل المفاتيح التّالية:
</p>

<ul>
<li>
		الاسم الأول للشّخص،
	</li>
	<li>
		الاسم العائلي (النّسب)،
	</li>
	<li>
		العمر،
	</li>
	<li>
		اللغات التي يُتقنها الشّخص،
	</li>
	<li>
		أطفاله.
	</li>
</ul>
<p>
	لاحظ بأنّ قيم اللغات والأطفال عبارة عن قوائم بايثون.
</p>

<p>
	في شفرة HTML نقوم بالدّوران حول مُحتويات القاموس <code>person</code>، بعدها نستعمل الاختبار <code>string</code> المُعرّف قياسيا في Jinja للتّحقق ممّا إذا كانت القيمة عبارة عن سلسلة نصيّة أو لا، إن كانت كذلك فإنّنا نعرضها مع مفتاحها بشكل طبيعي، إن لم تكن القيمة سلسلة نصيّة فهذا يعني بأنّها قائمة من عناصر مُتعدّدة وأنّ الجزء الذي يلي الكلمة المفتاحيّة <code>else</code> هو الذي سيُعرَض.
</p>

<p>
	في الجزء <code>else</code> نقوم بعرض المفتاح ثمّ نستعمل الحلقة <code>for</code> مُجدّدا للدّوران على عناصر القائمة المُتواجدة في قيمة المفتاح المذكور آنفا.
</p>

<p>
	هذا هو الجزء الخاص بعرض عناصر قائمة بعد قيمة المفتاح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group-item"</span></span><span class="pun">&gt;</span></span><span class="pln">
        </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> key </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> item </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> value </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><span class="pun">,</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	إن استخدمت إطار العمل Bootstrap فستكون النّتيجة مُشابهة لما في الصّورة التّاليّة:
</p>

<p style="text-align: center;">
	<img alt="01_person_info.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23738" data-unique="9lhnrti8p" src="https://academy.hsoub.com/uploads/monthly_2017_06/01_person_info.png.5a1a0243befde5ad5302711cec6efd06.png"></p>

<p>
	لاحظ بأنّ القاموس غير مُرتّب على نحو صحيح، ذلك لأنّ قواميس بايثون ليست مُرتّبة مبدئيًّا، لكن يُمكنك ترتيب مُحتويات القاموس أبجديا عبر استعمال المُرشّح <code>dictsort</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs cs"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> key</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">value</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> person </span><span class="pun">|</span><span class="pln"> dictsort </span><span class="pun">%}</span></code></pre>

<p>
	مع مُلاحظة أنّك لن تحتاج إلى التّابع <code>iteritems()</code> عند استعمال المُرشّح.
</p>

<h2 id="المتغير-loop-عند-استخدام-الحلقة-for">
	المُتغيّر loop عند استخدام الحلقة for
</h2>

<p>
	حلقة <code>for</code> تعمل بطريقة بسيطة، إذ تأخذ عدّة قيم وتمنحك كل قيمة داخل مُتغيّر مؤقّت، وفي كلّ دورة تتغيّر قيمة المُتغيّر.
</p>

<p>
	يوفّر مُحرّك القوالب Jinja عند التّعامل مع حلقة <code>for</code> مُتغيّرا خاصّا داخل الحلقة باسم <code>loop</code>؛ باستعمال هذا المُتغيّر الخاص، يُمكنك الوصول إلى معلومات خاصّة بالدورة الحاليّة وتُمكّننا كذلك من استعمال تقنيّات الاستدعاء الذّاتي (Recursion) لتضمين عناصر قائمة داخل عناصر قائمة أخرى خاصّة بالدّورة الحاليّة (ستتضّح الصّورة أكثر عندما ننتقل إلى الأمثلة التّطبيقية).
</p>

<h3 id="الوصول-إلى-رقم-الدورة-الحالية">
	الوصول إلى رقم الدّورة الحاليّة
</h3>

<p>
	يُمكنك استخدام الخاصيّة <code>index</code> مع المُتغيّر <code>loop</code> في الحلقة <code>for</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> item </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> items </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">index </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs livecodeserver"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">set</span></span><span class="pln"> list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'Python'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Flask'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Jinja'</span></span><span class="pun">,</span><span class="pln">
               </span><span class="hljs-string"><span class="str">'Programming'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Web developement'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">item</span></span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">in</span></span><span class="pln"> list </span><span class="pun">%}</span><span class="pln">
   </span><span class="str">&lt;p&gt;</span><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">index </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="pun">{{</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">item</span></span><span class="pln"> </span><span class="pun">}}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endfor </span><span class="pun">%}</span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs "><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Python</span><span class="pln">

</span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln">

</span><span class="lit">3</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Jinja</span><span class="pln">

</span><span class="lit">4</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Programming</span><span class="pln">

</span><span class="lit">5</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Web</span><span class="pln"> development</span></code></pre>

<p>
	لاحظ بأنّ العدّ يبدأ من واحد، إن أردت أن يبدأ العدّ من الصّفر، سيتوجّب عليك استخدام التّابع <code>index0</code> عوضا عن التّابع <code>index</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">loop</span><span class="pun">.</span><span class="pln">index</span></span><span class="pln">0 </span><span class="pun">}}</span></span></code></pre>

<p>
	بهذا التّعديل ستكون النّتيجة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs "><span class="lit">0</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Python</span><span class="pln">

</span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln">

</span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Jinja</span><span class="pln">

</span><span class="lit">3</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Programming</span><span class="pln">

</span><span class="lit">4</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Web</span><span class="pln"> developement</span></code></pre>

<h3 id="الوصول-إلى-رقم-الدورة-الحالية-عكسيا">
	الوصول إلى رقم الدّورة الحاليّة عكسيّا
</h3>

<p>
	يُمكنك كذلك عكس تأثير التّابع <code>index</code> عبر استعمال التّابع <code>revindex</code> كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">loop</span><span class="pun">.</span><span class="pln">revindex</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs "><span class="lit">5</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Python</span><span class="pln">

</span><span class="lit">4</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln">

</span><span class="lit">3</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Jinja</span><span class="pln">

</span><span class="lit">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Programming</span><span class="pln">

</span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Web</span><span class="pln"> developement</span></code></pre>

<p>
	وللانتهاء بالرّقم 0 يُمكنك استعمال التّابع <code>revindex0</code>.
</p>

<h3 id="التحقق-مما-إذا-كانت-الدورة-الحالية-هي-الأولى-أو-الأخيرة">
	التحقّق مما إذا كانت الدّورة الحاليّة هي الأولى أو الأخيرة
</h3>

<p>
	يُمكنك استعمال التّابع <code>first</code> الذي يُرجع القيمة <code>True</code> إذا كانت الدّورة الحاليّة هي أول دورة في حلقة <code>for</code>.
</p>

<p>
	وبنفس الطّريقة فإنّ التّابع <code>last</code> يُساعد على التّحقّق ممّا إذا كانت الدّورة الحاليّة هي الأخيرة أو لا.
</p>

<p>
	مثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> item </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> list </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">first </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
        </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">index </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">(</span><span class="typ">First</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">elif</span></span><span class="pln"> loop</span><span class="pun">.</span><span class="kwd">last</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
        </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">index </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">(</span><span class="typ">Last</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
        </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">.</span><span class="pln">index </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs mathematica"><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-keyword"><span class="typ">First</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Python</span><span class="pln">

</span><span class="hljs-number"><span class="lit">2</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln">

</span><span class="hljs-number"><span class="lit">3</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Jinja</span><span class="pln">

</span><span class="hljs-number"><span class="lit">4</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Programming</span><span class="pln">

</span><span class="hljs-number"><span class="lit">5</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-keyword"><span class="typ">Last</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Web</span><span class="pln"> developement</span></code></pre>

<h3 id="الوصول-إلى-عدد-عناصر-القيم-الإجمالي">
	الوصول إلى عدد عناصر القيم الإجمالي
</h3>

<p>
	بالإضافة إلى إمكانيّة الحصول على عدد عناصر قائمة ما باستعمال المُرشّح <code>count</code> أو المُرشّح <code>length</code>، يُمكنك كذلك استخدام <code>loop.length</code> للحصول على عدد عناصر القيم التي اِستُخْدِمَتْ مع حلقة <code>for</code> الحاليّة.
</p>

<p>
	يُمكنك التّحقق من الأمر عبر المثال التّالي (على افتراض أنّك تستعمل القائمة <code>list</code> السّابقة):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">list</span></span><span class="pln"> | </span><span class="hljs-variable"><span class="pln">length</span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">list</span></span><span class="pln"> | </span><span class="hljs-variable"><span class="pln">count</span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
{% for item in list %}
   </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">loop.length</span></span><span class="pln"> }}</span></span><span class="xml"><span class="pln"> - </span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">item</span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
{% endfor %}</span></span></code></pre>

<p>
	ستُلاحظ بأنّ النّتيجة هي نفسها سواء استخدمنا المرشّحات أو التّابع <code>loop.length</code>، بهذه الطّريقة يُمكنك الحصول على عدد عناصر قائمة من داخل حلقة <code>for</code>.
</p>

<h3 id="إعادة-استعمال-نفس-الحلقة-مع-قائمة-داخل-قائمة-أخرى">
	إعادة استعمال نفس الحلقة مع قائمة داخل قائمة أخرى
</h3>

<p>
	لنفترض بأنّنا نُريد عرض أسماء أشخاص مع أبنائهم بحيث تكون قائمة HTML الخاصّة بالأبناء تابعة للأب.
</p>

<p>
	إليك البيانات التّي سنستعملها في مثالنا هذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs bash"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> people </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Ali'</span></span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=[</span><span class="pln">dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Mohammed'</span></span><span class="pun">),</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Hassan'</span></span><span class="pun">)]),</span><span class="pln">
                 dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Khaled'</span></span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=</span><span class="kwd">None</span><span class="pun">),</span><span class="pln">
                 dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Fahd'</span></span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=[</span><span class="pln">dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Kamal'</span></span><span class="pun">),</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'Omar'</span></span><span class="pun">)])</span><span class="pln">
               </span><span class="pun">]</span><span class="pln">
</span><span class="pun">%}</span></code></pre>

<p>
	في القائمة أعلاه، لدينا ثلاثة قواميس، القاموس الأول خاصّ بعلي، وأطفاله (الذين يعتبرون قائمة من القواميس كذلك) محمد وحسن، أما القاموس الثّاني فخاص بخالد الذي ليس لديه أبناء، والقاموس الأخير خاص بفهد، وأبناؤه كمال وعمر.
</p>

<p>
	لعرض أسماء الآباء الذين يتواجدون في القواميس الثّلاثة، يُمكن أن نستخدم حلقة <code>for</code> بسيطة، لكن سيتوجّب علينا تكرار الشّفرة إذا ما أردنا الدوران حول أبناء كل شخص.
</p>

<p>
	عوضا عن استخدام أكثر من حلقة <code>for</code> واحدة، يُمكننا استخدام حلقة <code>for</code> خاصّة تُكرّر نفسها، ويُمكننا فعل هذا الأمر عبر إضافة الكلمة <code>recursive</code> عند استخدام حلقة <code>for</code> كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> person </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> people recursive </span><span class="pun">%}</span></span></code></pre>

<p>
	هكذا سنتمكّن من استعمال المُتغيّر <code>loop</code> لإعادة الدّوران حول قائمة أطفال كل شخص، لكن سنفعل ذلك فقط إن كان للشّخص أبناء بالفعل، لذا سنتحقّق من أنّ القيمة لا تُساوي القيمة <code>None</code> عبر الاختبار كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> person</span><span class="pun">.</span><span class="pln">children </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> none </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group"</span></span><span class="pun">&gt;</span></span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">(</span><span class="pln">person</span><span class="pun">.</span><span class="pln">children</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	المثال النّهائيّ سيكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> people </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Ali'</span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=[</span><span class="pln">dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Mohammed'</span><span class="pun">),</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Hassan'</span><span class="pun">)]),</span><span class="pln">
                 dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Khaled'</span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=</span><span class="kwd">None</span><span class="pun">),</span><span class="pln">
                 dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Fahd'</span><span class="pun">,</span><span class="pln"> children</span><span class="pun">=[</span><span class="pln">dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Kamal'</span><span class="pun">),</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'Omar'</span><span class="pun">)])</span><span class="pln">
               </span><span class="pun">]</span><span class="pln">
</span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"col-sm-4"</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group"</span></span><span class="pun">&gt;</span></span><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> person </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> people recursive </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
            </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group-item"</span></span><span class="pun">&gt;</span></span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> person</span><span class="pun">.</span><span class="pln">name </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> person</span><span class="pun">.</span><span class="pln">children </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> none </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
            </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"list-group"</span></span><span class="pun">&gt;</span></span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> loop</span><span class="pun">(</span><span class="pln">person</span><span class="pun">.</span><span class="pln">children</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pun">&gt;</span></span><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
            </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">li</span></span><span class="pun">&gt;</span></span><span class="pln">
        </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">ul</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">div</span></span><span class="pun">&gt;</span></span></span></code></pre>

<p>
	النّتيجة ستكون كما في الصّورة التّاليّة:
</p>

<p style="text-align: center;">
	<img alt="02_children.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23739" data-unique="osihg5c1z" src="https://academy.hsoub.com/uploads/monthly_2017_06/02_children.png.bb50dc3665e948e3e39e3ffc0e9ed461.png"></p>

<p>
	يُمكنك كذلك معرفة عمق الحلقة باستخدام التّابع <code>loop.depth</code> داخل حلقة <code>for</code> من النّوع <code>recursive</code> كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">span</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"badge"</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">loop.depth</span></span><span class="pln"> }}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">span</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	تأكّد فقط من أن تضع السّطر السّابق مُباشرة بعد السّطر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9790_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> person </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> people recursive </span><span class="pun">%}</span></span></code></pre>

<p>
	النّتيجة ستكون كالتّالي:
</p>

<p style="text-align: center;">
	<img alt="03_children_with_depth.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23740" data-unique="5ddf7oreh" src="https://academy.hsoub.com/uploads/monthly_2017_06/03_children_with_depth.png.f6f3743bd205c8f499cc81b867ac104c.png"></p>

<p>
	لاحظ بأنّ رقم العمق يبدأ من واحد، إن أردت أن يبدأ من الصّفر فاستعمل <code>loop.depth0</code>.
</p>

<p>
	يُمكنك كذلك استخدام هذه الميّزة مع تعليقات في مُدوّنة أو منصّة تتطلّب تفاعل الأعضاء بين بعضهم البعض.<br>
	الصّورة التّاليّة توضيح بسيط للنّتيجة النّهائيّة التي يُمكنك أن تصل إليها إن كنت تمتلك تعليقات متداخلة في قاعدة بياناتك:
</p>

<p style="text-align: center;">
	<img alt="04_comments.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23741" data-unique="cnxrs6iwx" src="https://academy.hsoub.com/uploads/monthly_2017_06/04_comments.png.2f9d48286f85911a903eb15247b10f0c.png"></p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة استخدام حلقة <code>for</code> في مُحرّك القوالب Jinja للحصول على قوالب HTML أحسن وتطويرها بسرعة. وبهذا نكون قد أكملنا أساسيّات دروس مُحرّك القوالب Jinja وسننتقل في الدّروس القادمة للتّعرف على جزء آخر مُهمّ في تطوير الويب، ألا وهو كيفيّة التّعامل مع قواعد البيانات في التّطبيقات المكتوبة بإطار العمل Flask.
</p>
]]></description><guid isPermaLink="false">503</guid><pubDate>Tue, 20 Jun 2017 21:34:20 +0000</pubDate></item><item><title>&#x627;&#x644;&#x633;&#x651;&#x64A;&#x627;&#x642; &#x641;&#x64A; &#x645;&#x64F;&#x62D;&#x631;&#x651;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%B3%D9%91%D9%8A%D8%A7%D9%82-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-r500/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.4e1d850130438252dea7fe74f248acfe.png" /></p>

<h2>
	مُقدّمة
</h2>

<p>
	تعرّفنا في الدّروس السّابقة على العديد من ميّزات مُحرّك القوالب Jinja وكيفيّة استخدامها لتصميم صفحات <a href="https://academy.hsoub.com/programming/html5/" rel="">HTML</a> بسرعة، إذ بدأنا بمبدأ المرشّحات ثمّ مررنا على الاختبارات لنُنهي مشوارنا عبر التّعرف على طرق لتفادي تكرار شفرة HTML وإعادة استخدام القوالب أو أجزاء منها في مشروع مُعيّن، بل يُمكنك كذلك كتابة شيفرة واحدة واستعمالها مع أكثر من مشروع لما يُوفّره لنا مُحرّك القوالب Jinja من مرونة في التّطوير وقابليّة إعادة استعمال الشّفرة في مُختلف الظّروف. في هذا الدّرس، سنتعرّف على السّياق (Context) في Jinja عند التّضمين والاستيراد لتتفادى الوقوع في أخطاء يصعب تصحيحها.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23658" data-unique="79v8we2mc" src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.6b4069dc917586d49b8520bea424c5a1.png"></p>

<p>
	لتطبيق أمثلة هذا الدّرس، يُمكنك إنشاء تطبيق Flask صغير ليقوم بتقديم قوالب HTML أو يُمكنك استعمال إطار عمل آخر مثل Pyramid أو Django أو Bottle لكن سيتوجّب عليك البحث عن كيفيّة استعمال Jinja مع إطار العمل الذي تختاره.
</p>

<h2 id="السياق-في-محرك-القوالب-jinja-عند-تضمين-قالب-في-قالب-آخر-أو-عند-الاستيراد">
	السّياق في مُحرّك القوالب Jinja عند تضمين قالب في قالب آخر أو عند الاستيراد
</h2>

<p>
	يعني مُختلف المُتغيّرات والدّوال المُعرّفة في جزء مُعيّن من الشّفرة. فمثلا، إن عرّفت مُتغيّرا في الجزء العلوي من قالب HTML كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<span class="pun">{%</span><span class="pln"> set website </span><span class="pun">=</span><span class="pln"> </span><span class="str">'academy.hsoub.com'</span><span class="pln"> </span><span class="pun">%}</span></pre>

<p>
	بعد تعريف المُتغيّر <code>website</code> في القالب، فسيُصبح هذا المُتغيّر مُتاحا في هذا القالب فقط، ما يعني بأنّك لن تستطيع الوصول إلى المُتغيّر <code>website</code> في قالب HTML آخر دون استيراده.
</p>

<h3 id="السياق-عند-تضمين-قالب-داخل-قالب-آخر">
	السّياق عند تضمين قالب داخل قالب آخر
</h3>

<p>
	فلنضع السّيناريو التّاليَ لتتوضّح الفكرة أكثر، لنقل بأنّ لدينا ملفّات HTML التّالية:
</p>

<ul>
<li>
		base.html
	</li>
	<li>
		index.html
	</li>
	<li>
		url.html
	</li>
</ul>
<p>
	مُحتويات ملفّ <code>base.html</code> ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="xml"><span class="hljs-doctype"><span class="dec">&lt;!DOCTYPE html&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">html</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">lang</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"en"</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">head</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">meta</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">charset</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"UTF-8"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">link</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">rel</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"stylesheet"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">title</span></span><span class="tag">&gt;</span></span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title %}</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> %}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">title</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">head</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">body</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body %}</span></span><span class="xml"><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> %}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">body</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">html</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	وملفّ <code>index.html</code> يرث من الملفّ <code>base.html</code> مع تعريف المُتغيّر <code>website</code> وتضمين الملفّ <code>url.html</code> باستعمال الجملة <code>include</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">extends</span></span><span class="pln"> </span><span class="str">'base.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">Application</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> website </span><span class="pun">=</span><span class="pln"> </span><span class="str">'academy.hsoub.com'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	لنقل بأنّك تُريد الوصول إلى قيمة المُتغيّر <code>website</code> داخل الملفّ <code>url.html</code> لعرض الرّابط داخل وسم <code>&lt;a&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs handlebars"><span class="xml"><span class="pun">{#</span><span class="pln"> </span><span class="str">'url.html'</span><span class="pln"> </span><span class="com">#}</span><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">'http://</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">website</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">'</span></span><span class="pun">&gt;</span></span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">website</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">a</span></span><span class="pun">&gt;</span></span></span></code></pre>

<p>
	ستكون النّتيجة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'http://academy.hsoub.com'</span></span><span class="tag">&gt;</span></span><span class="pln">academy.hsoub.com</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span>
</code></pre>

<p>
	نجح الأمر لأنّ السّياق قد مُرِّر من الملفّ <code>index.html</code> إلى الملفّ <code>url.html</code> عند استخدام التعليمة <code>include</code>، ما يعني بأنّ المُتغيّرات المُعرّفة في الملفّ الأصلي ستكون مُتاحة في الملفّ الفرعي الّذي ضُمِّن بالجملة <code>include</code>.
</p>

<p>
	لكنّك لن تستطيع الوصول إلّا إلى المُتغيّرات التي عُرّفت قبل استعمال الجملة <code>include</code>.<br>
	ما يعني بأنّك لو عرّفت المُتغيّر <code>website</code> بعد تضمين القالب <code>url.html</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs livecodeserver"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'url.html'</span></span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">set</span></span><span class="pln"> website </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'academy.hsoub.com'</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	فالقالب <code>url.html</code> لن يتعرّف على المُتغيّر <code>website</code> وسيعتبره سلسلة نصيّة فارغة لأنّه لا يستطيع الوصول إلى قيمته.<br>
	ستحصل بالتّالي على النّتيجة التّالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'http://'</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	لاحظ بأنّ مُحرّك القوالب Jinja لم يُصدر أية أخطاء، لذا كن حذرا من هذا النّوع من المشاكل الصّامتة، وتأكّد دائما من الاطّلاع على مصدر الصّفحة لتفهم ما يحدث وتستطيع حلّ المُشكلة.
</p>

<p>
	تضمين قالب داخل قالب آخر باستعمال التعليمة <code>include</code> يُمرّر السّياق مبدئيا من قالب لآخر ، لكن إن أردت منع حدوث هذا الأمر، يُمكنك استعمال التّعبير <code>without context</code> لمنع القالب الفرعي من الوصول إلى سيّاق القالب الأصلي، وبالتّالي لن يتمكّن من الوصول إلى المُتغيّرات التّي سبق تعريفها.
</p>

<p>
	لتجربة هذا، أضف التّعبير <code>without context</code> إلى صفحة <code>index.html</code> ليُصبح مُحتوى الملفّ كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">extends</span></span><span class="pln"> </span><span class="str">'base.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">Application</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> website </span><span class="pun">=</span><span class="pln"> </span><span class="str">'academy.hsoub.com'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">.html'</span><span class="pln"> without context </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	إن ألقيت نظرة على النّتيجة، ستجدها مُشابهة لما كانت عليه عندما عرّفنا المُتغيّر <code>website</code> بعد التعليمة <code>include</code> ما يعني أنّ القالب <code>url.html</code> لم يعد مُؤهّلا للوصول إلى قيمة المُتغيّر، ولهذا نفس التّأثير مع جميع المُتغيّرات والدّوال المُعرّفة في السّياق.
</p>

<h3 id="السياق-عند-الاستيراد">
	السّياق عند الاستيراد
</h3>

<p>
	يُمرّر السّياق مبدئيا بين القوالب عند استعمال الجملة <code>include</code>، لكنّ العكس يحدث عند استيراد قالب داخل قالب آخر.
</p>

<p>
	لتوضيح هذه الفكرة، لنُغيّر مُحتويات الملفّ <code>url.html</code> إلى الماكرو التّالي :
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> macro </span><span class="hljs-keyword"><span class="pln">url</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">'http://</span></span></span></span><span class="hljs-variable"><span class="str">{{ website }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">'</span></span><span class="pun">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> website </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">a</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> endmacro </span><span class="pun">%}</span></span></code></pre>

<p>
	لاحظ بأنّ الماكرو لا يقبل أية مُعاملات، لكنّنا نحاول أن نصل إلى المُتغيّر <code>website</code> داخل الماكرو.
</p>

<p>
	لنُغيّر الآن التعليمة <code>include</code> إلى جملة <code>import</code> لاستيراد هذا الماكرو من القالب <code>url.hmtl</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> website </span><span class="pun">=</span><span class="pln"> </span><span class="str">'academy.hsoub.com'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">.html'</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">url</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> url</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	لاحظ بأنّنا نقوم بالاستيراد بعد تعريف المُتغيّر.
</p>

<p>
	بما أنّ السّياق لا يُمرّر مبدئيا عند الاستيراد، فالنّتيجة ستكون كما لو أنّ قيمة المُتغيّر <code>website</code> فارغة.<br>
	استعمل التّعبير <code>with context</code> عند الاستيراد كما يلي، للتصريح برغبتك في تمرير السّياق :
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs python"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'url.html'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> url </span><span class="hljs-keyword"><span class="kwd">with</span></span><span class="pln"> context </span><span class="pun">%}</span></code></pre>

<p>
	التّعبير <code>with context</code> له تأثير مُعاكس لتأثير التّعبير <code>without context</code>، لذا فالمُتغيّر <code>website</code> سيُمرَّرُ إلى القالب <code>url.html</code> وبالتّالي فالماكرو <code>url()</code> يستطيع الوصول إلى قيمة المُتغيّر ومن ثمّ عرضه بصيغة رابط.
</p>

<p>
	<strong>ملحوظة:</strong> المثال أعلاه مُجرّد توضيح لفكرة السّياق عند الاستيراد، ومن الأفضل استعمال المُعاملات لنقل قيمة مُتغيّر إلى ماكرو مُعيّن عوضا عن تفعيل السّياق.
</p>

<p>
	الخلاصة أنّك تستطيع التّحكم في كيفيّة تعامل القوالب مع السّياق عند التضمين أو الاستيراد عبر استخدام كلّ من التّعبيرين <code>with context</code> و <code>without context</code>.
</p>

<p>
	الحالة المبدئية للتعليمة <code>include</code> هي كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">.html'</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">with</span></span><span class="pln"> context </span><span class="pun">%}</span></span></code></pre>

<p>
	والحالة االمبدئية للتعليمة <code>import</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="str">'</span><span class="hljs-keyword"><span class="str">url</span></span><span class="str">.html'</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">url</span></span><span class="pln"> without context </span><span class="pun">%}</span></span></code></pre>

<h2 id="تجاهل-تضمين-القوالب-إن-لم-تكن-متواجدة-أساسا">
	تجاهل تضمين القوالب إن لم تكن متواجدة أساسا
</h2>

<p>
	سأعرض لك في هذه الفقرة بشكل وجيز تقنيتين من التّقنيات التّي ستُساعدك على تصميم قوالب HTML أفضل عند استخدام التعليمة <code>include</code>.
</p>

<p>
	أولا، يُمكنك منح مُحرّك القوالب Jinja إمكانيّة تضمين قالب فقط إن كان موجودا عبر تمرير قائمة من أسماء القوالب إلى التعليمة <code>include</code> كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs ruby"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'page1.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'page2.html'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	إذا كان القالب <code>page1.html</code> موجودا فسيكون للمثال أعلاه نفس تأثير ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs ruby"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'page1.html'</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	سواء أكان القالب <code>page2.html</code> موجودا أم لا فهذا غير مُهمّ ما دام القالب <code>page1.html</code> أول قالب في القائمة وكان موجودا بالفعل داخل مُجلّد <code>templates</code>.
</p>

<p>
	أمّا في حالة لم يكن القالب <code>page1.html</code> موجودا داخل مُجلّد القوالب وكان القالب <code>page2.html</code> موجودا عوضا عنه، فهذا الأخير هو القالب الذي سيُضمّن.
</p>

<p>
	وفي حالة لم يكن أي قالب من القوالب المُوفَّرة موجودا، فستحصل على خطأ كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs avrasm"><span class="pln">jinja2</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">exceptions</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">TemplatesNotFound</span></span><span class="pln">

</span><span class="hljs-label"><span class="typ">TemplatesNotFound</span><span class="pun">:</span></span><span class="pln"> none of the templates given were found</span><span class="pun">:</span><span class="pln"> page1</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">html</span></span><span class="pun">,</span><span class="pln"> page2</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">html</span></span></code></pre>

<p>
	ولتجاهل هذا الخطأ وعرض مُحتويات القالب <code>index.html</code> رغم عدم وجود هذه القوالب المُضمَّنة، يُمكنك إضافة التّعبير <code>ignore missing</code> عند استعمال التعليمة <code>include</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs ruby"><span class="pln">
</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'page1.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'page2.html'</span></span><span class="pun">]</span><span class="pln"> ignore missing </span><span class="pun">%}</span></code></pre>

<p>
	التّعبير <code>ignore missing</code> ليس محصورا بقائمة قوالب فقط، بل تستطيع كذلك استخدامه عند تضمين قالب واحد فقط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs ruby"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"sidebar.html"</span></span><span class="pln"> ignore missing </span><span class="pun">%}</span></code></pre>

<p>
	عند استعمال التّعبير، سيتحقّق مُحرّك القوالب Jinja من أنّ القالب <code>sidebar.html</code> موجود في مُجلّد القوالب، إن كان كذلك فعمليّة التّضمين ستكون ناجحة دون أخطاء، وإن لم يكن القالب موجودا فلن تحدث أية أخطاء وسيبقى مكان التعليمة <code>include</code> فارغا عند عرض النّتيجة.
</p>

<p>
	<strong>تنبيه:</strong>
</p>

<p>
	عند استخدام التّعبير <code>ignore missing</code> مع كلّ من التّعبيرين <code>with context</code> و <code>without context</code> في آن واحد، تأكّد من أنّ التّعبير <code>ignore missing</code> يأتي أولا.
</p>

<p>
	ما يعني بأنّ الأمثلة أسفله صحيحة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs livecodeserver"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'page1.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'page2.html'</span></span><span class="pun">]</span><span class="pln"> ignore missing </span><span class="hljs-operator"><span class="kwd">with</span></span><span class="pln"> context </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"sidebar.html"</span></span><span class="pln"> ignore missing </span><span class="hljs-operator"><span class="kwd">with</span></span><span class="pln"> context </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"sidebar.html"</span></span><span class="pln"> ignore missing </span><span class="hljs-keyword"><span class="pln">without</span></span><span class="pln"> context </span><span class="pun">%}</span></code></pre>

<p>
	والأمثلة التّاليّة خاطئة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5548_9" style="">
<code class="hljs livecodeserver"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'page1.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'page2.html'</span></span><span class="pun">]</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">with</span></span><span class="pln"> context ignore missing </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"sidebar.html"</span></span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">with</span></span><span class="pln"> context ignore missing </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">include</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">"sidebar.html"</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">without</span></span><span class="pln"> context ignore missing </span><span class="pun">%}</span></code></pre>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة عمل السّياق في Jinja عند التّضمين والاستيراد، بعد قراءتك لهذا الدّرس، يجب أن تكون قادرا على إدارة السّياق باحترافيّة وتتجنّب المشاكل التي تقع في حالة إساءة فهم كيفيّة عمل السّياق، في الدّرس التّالي، سنتعرّف على تقنيات متقدّمة للتّعامل مع حلقات <code>for</code> من أجل تحسين تطبيقاتك وتكتب شفرة أكثر فعاليّة عند تطوير تطبيقات الويب باستعمال إطار العمل Flask أو أي إطار عمل يعتمد على Jinja.
</p>
]]></description><guid isPermaLink="false">500</guid><pubDate>Wed, 14 Jun 2017 11:34:57 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x633;&#x62A;&#x64A;&#x631;&#x627;&#x62F; &#x641;&#x64A;  &#x645;&#x64F;&#x62D;&#x631;&#x651;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%8A%D8%B1%D8%A7%D8%AF-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-r497/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.b7fdb8e593a3388ebcd7046568b9f577.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	تعرّفنا في <a href="https://academy.hsoub.com/programming/python/flask/%D8%AF%D9%85%D8%AC-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-%D8%A8%D8%B9%D8%B6%D9%87%D8%A7-%D8%A8%D8%A8%D8%B9%D8%B6-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AC%D9%85%D9%84%D8%A9-include-r494/" rel="">الدّرس السّابق</a> على التعليمة <code>include</code> وكيفيّة استخدامها في مُحرّك Jinja لتضمين قالب HTML داخل قالب آخر، في هذا الدّرس سنتعرّف على ميّزة أخرى ستُساعدك على تفادي تكرار الشّيفرة، إذ سنتعرّف على تعليمة <code>import</code> لاستيراد مكوّن ما من قالب واستعماله في قالب آخر.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23550" data-unique="urn3n3su6" src="https://academy.hsoub.com/uploads/monthly_2017_06/main.png.39dc54200b4c2ef40fe7a7122899c097.png"></p>

<h2 id="ما-الغرض-من-الاستيراد">
	ما الغرض من الاستيراد؟
</h2>

<p>
	تعرّفنا مُسبقا على خاصّية الماكرو في Jinja، وقلنا بأنّها مُفيدة لتفادي تكرار الشّفرة وأنّها تُستخدم كما تُستخدم الدّوال في لغة <a href="https://academy.hsoub.com/programming/python/" rel="">بايثون</a>، لكنّنا لم نتطرّق بالتّفصيل إلى جزئيّة مُهمّة، ألا وهي كيفيّة جمع عدّة دوال في قالب واحد ليعمل مثل الوحدة (Module) في بايثون، بحيث يشمل عدّة دوال يُمكنك استيرادها بسطر واحد واستخدامها في أكثر من قالب واحد عوضا عن كتابة الماكرو أعلى الصّفحة.
</p>

<p>
	يُمكنك كذلك استخدام قالب HTML مُعيّن كمخزن لإعدادات تطبيق، مثل اسم التّطبيق والمُعاملات التّي يُمكنك بها التّحكّم في جزئيّات مُعيّنة ممّا يُعرض على مُتصفّح المُستخدم، ومن ثمّ يُمكنك استيراد المُعاملات من هذا القالب واستغلالها في بقيّة القوالب كما تشاء لتوفير ديناميكيّة أفضل لتطبيقك.
</p>

<h2 id="التعليمة-import-لاستيراد-متغير-أو-ماكرو-من-قالب-معين">
	التعليمة import لاستيراد مُتغيّر أو ماكرو من قالب مُعيّن
</h2>

<p>
	كتابة شيفرة نماذج HTML أمر مُملّ، لذا قد ترغب في كتابة بعض الدّوال لتوليد النّماذج بشكل سريع اعتمادا على مُعاملات مُعيّنة.
</p>

<p>
	لنفترض بأنّ لدينا ما يلي في مُجلّد <code>templates</code> الخاصّ بتطبيق Flask:
</p>

<ul>
<li>
		ملفّ <code>base.html</code> .
	</li>
	<li>
		ملفّ <code>index.html</code> للصّفحة الرّئيسية.
	</li>
	<li>
		ملفّ باسم <code>forms.html</code>.
	</li>
</ul>
<p>
	سيحتوي ملفّ <code>base.html</code> على شفرة HTML بسيطة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<span class="pun">&lt;!</span><span class="pln">DOCTYPE html</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">html lang</span><span class="pun">=</span><span class="str">"en"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">head</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">meta charset</span><span class="pun">=</span><span class="str">"UTF-8"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">link href</span><span class="pun">=</span><span class="str">"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"</span><span class="pln"> rel</span><span class="pun">=</span><span class="str">"stylesheet"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">title</span><span class="pun">&gt;{%</span><span class="pln"> block title </span><span class="pun">%}{%</span><span class="pln"> endblock </span><span class="pun">%}&lt;/</span><span class="pln">title</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">head</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">body</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> block body </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endblock </span><span class="pun">%}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">body</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">html</span><span class="pun">&gt;</span></pre>

<p>
	أمّا ملفّ <code>index.html</code> فسيرث من الملفّ السّابق بالإضافة إلى عنوان داخل وسم <code>&lt;h1&gt;</code> لطلب تسجيل الدّخول من المُستخدم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">extends</span></span><span class="pln"> </span><span class="str">'base.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">Application</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"container"</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">h1</span></span><span class="str">&gt;</span></span><span class="typ">Please</span><span class="pln"> </span><span class="typ">Login</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">h1</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">div</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	أما <code>forms.html</code> فسيحتوي على ماكرو خاصّ بعرض النّماذج من نوع <code>input</code> و ماكرو آخر لعرض نموذج لمساحة النّص (TextArea):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pun">{%</span><span class="pln"> macro input</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">=</span><span class="str">''</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">=</span><span class="str">'text'</span><span class="pun">,</span><span class="pln"> placeholder</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">input</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"form-control"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">type</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">type</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> 
           </span><span class="hljs-attribute"><span class="pln">value</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">value</span></span><span class="str">|</span><span class="hljs-variable"><span class="str">e</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">name</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">name</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln">
           </span><span class="hljs-attribute"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">placeholder</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endmacro </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> macro textarea</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">=</span><span class="str">''</span><span class="pun">,</span><span class="pln"> rows</span><span class="pun">=</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> cols</span><span class="pun">=</span><span class="lit">40</span><span class="pun">,</span><span class="pln"> placeholder</span><span class="pun">=</span><span class="str">''</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
   </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">textarea</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"form-control"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">name</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">name</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> 
             </span><span class="hljs-attribute"><span class="pln">rows</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">rows</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">cols</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">cols</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> 
             </span><span class="hljs-attribute"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-expression"><span class="str">{{ </span><span class="hljs-variable"><span class="str">placeholder</span></span><span class="str"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pun">&gt;</span></span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">value</span></span><span class="pun">|</span><span class="hljs-variable"><span class="pln">e</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">textarea</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endmacro </span><span class="pun">%}</span></span></code></pre>

<p>
	ينشئ الماكرو الأول حقل إدخال من نوع <code>input</code>، يقبل الماكرو ثلاثة مُعاملات:
</p>

<ul>
<li>
		name لاسم الحقل.
	</li>
	<li>
		value لقيمة الحقل المبدئية.
	</li>
	<li>
		type لنوع الحقل (نصّ عادي، كلمة مرور، …إلخ).
	</li>
	<li>
		placeholder للنّص المبدئي.
	</li>
</ul>
<p>
	تُستعمل هذه المُعاملات إن وفّرها المُطوّر للتّحكم بكيفيّة توليد الحقل، فمثلا القيمة المبدئية للحقل <code>type</code> هي <code>text</code> ما يعني بأنّك إن لم تُمرّر قيمةً لهذا المُعامل فسيُولّد الماكرو حقلا نصّيا عاديّا، ولو غيّرت القيمة مثلا إلى <code>password</code> فسيكون الحقل المُولّد عبارة عن حقل كلمة مرور.
</p>

<p>
	قد تُلاحظ بأنّنا نستخدم المُرشّح <code>e</code> الذي هو اختصار لكلمة <code>escape</code> والذي يقوم بحماية الحقل من الهجمات الخبيثة عبر منع ترجمة شفرات HTML وJavascript.
</p>

<p>
	أمّا بالنّسبة للماكرو <code>textarea</code> فهو مُشابه لما سبق، إلّا أنّه يُولّد وسما من النّوع <code>textarea</code>الذي يُعبّر عن حقل لنصّ مُتعدّد الأسطر، كما أنّه يقبل كلّا من المُعاملين <code>rows</code> و <code>cols</code> لتحديد حجم مساحة النّص التي ستظهر في صفحة HTML.
</p>

<h3 id="استعمال-التعليمة-import-لاستيراد-الوحدة-formshtml">
	استعمال التعليمة import لاستيراد الوحدة forms.html
</h3>

<p>
	بعد أن أنشأنا قاعدة لمثالنا، وبعد أن كتبنا دوال خاصّة بتوليد حقول الإدخال وجمعها في ملفّ <code>forms.html</code> لتُمثّل وحدة كما في وحدات Python، لنستعملها في ملفّ <code>index.html</code>.
</p>

<p>
	أولا، ضع سطر الاستيراد في رأس صفحة <code>index.html</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs python"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'forms.html'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> forms </span><span class="pun">%}</span></code></pre>

<p>
	لاحظ بأنّنا استعملنا الكلمة المفتاحية <code>as</code> لإسناد اسم مُستعار للوحدة المُستوردة بحيث نتمكّن من الوصول إليها عبر الاسم <code>forms</code>.
</p>

<p>
	بعد استيراد الوحدة، يُمكنك استدعاء الدّوال المُتواجدة بداخلها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs avrasm"><span class="pln">forms</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">input</span></span><span class="pun">()</span><span class="pln">
forms</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">textarea</span></span><span class="pun">()</span></code></pre>

<p>
	لكن ستحتاج إلى تمرير مُعاملات حسب نوع الحقل الذي ترغب بتوليده.
</p>

<p>
	لنُضف الآن بضعة حقول إلى ملفّ <code>index.html</code> باستخدام الوحدة التّي قمنا باستيرادها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pln">    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">input</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">username</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Type</span></span><span class="str"> </span><span class="hljs-variable"><span class="hljs-keyword"><span class="str">in</span></span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">username</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">input</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Type</span></span><span class="str"> </span><span class="hljs-variable"><span class="hljs-keyword"><span class="str">in</span></span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">type</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">textarea</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">message</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Write</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">message</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">here.</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">button</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"btn btn-primary"</span></span><span class="pun">&gt;</span></span><span class="typ">Submit</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">button</span></span><span class="pun">&gt;</span></span></span></code></pre>

<p>
	في الشّيفرة أعلاه، نستعمل الماكرو <code>forms.input</code> لإنشاء حقل نصي لاسم المُستخدم، ونستخدمه مُجدّدا لإنشاء حقل لكلمة المرور الذي حدّدنا نوعه بالقيمة <code>password</code>، ثمّ بعد ذلك أنشأنا حقلا لمساحة النّص مع تعيين القيمة <code>message</code> كاسم للحقل، وفي آخر سطر أضفنا زرّا صغيرا لإرسال مُحتويات النّموذج.
</p>

<p>
	بعد إضافة الشّفرة السّابقة، ستكون مُحتويات الملفّ <code>index.html</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="str">'forms.html'</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> forms </span><span class="pun">%}</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="str">'base.html'</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> block title </span><span class="pun">%}</span><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">Application</span><span class="pln"> </span><span class="pun">{%</span><span class="pln"> endblock </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> block body </span><span class="pun">%}</span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"container"</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">h1</span></span><span class="str">&gt;</span></span><span class="typ">Please</span><span class="pln"> </span><span class="typ">Login</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">h1</span></span><span class="pun">&gt;</span></span><span class="pln">

    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">input</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">username</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Type</span></span><span class="str"> </span><span class="hljs-variable"><span class="hljs-keyword"><span class="str">in</span></span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">username</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">input</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Type</span></span><span class="str"> </span><span class="hljs-variable"><span class="hljs-keyword"><span class="str">in</span></span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">type</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">password</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">forms</span><span class="pun">.</span><span class="pln">textarea</span></span><span class="pun">(</span><span class="str">'</span><span class="hljs-variable"><span class="str">message</span></span><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">placeholder</span></span><span class="pun">=</span><span class="str">'</span><span class="hljs-variable"><span class="str">Write</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">your</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">message</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">here.</span></span><span class="str">'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">button</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"btn btn-primary"</span></span><span class="pun">&gt;</span></span><span class="typ">Submit</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">button</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">div</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endblock </span><span class="pun">%}</span></span></code></pre>

<p>
	والصّفحة ستكون مُشابهة للمثال في الصّورة التّالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23549" href="https://academy.hsoub.com/uploads/monthly_2017_06/5J3aj52.png.8989f1054c3c7c717439ab9fecf7b546.png" rel=""><img alt="5J3aj52.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23549" data-unique="y034x7uno" src="https://academy.hsoub.com/uploads/monthly_2017_06/5J3aj52.thumb.png.c6929d96e69ec855e21aa99727314d3b.png"></a>
</p>

<p>
	<strong>مُلاحظة:</strong> الغرض من هذه الأمثلة هو شرح مبدأ الاستيراد وكيفية عمله في مُحرّك القوالب Jinja. إن أردتَ إدارة نماذج HTML على نحو أفضل وأكثر أمانا، فمن الأفضل استخدام <a href="https://academy.hsoub.com/programming/python/flask/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-wtforms-%D9%84%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-html-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r411/" rel="">مكتبة WTForms</a>.
</p>

<h3 id="استيراد-مكون-معين-باستخدام-التعبير-from-import">
	استيراد مكوّن مُعيّن باستخدام التّعبير from import
</h3>

<p>
	بالإضافة إلى إمكانيّة استيراد وحدة واستعمال الدّوال المتواجدة فيها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs ruby"><span class="kwd">import</span><span class="pln"> </span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">module</span></span></span><span class="pln">
</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">module</span></span><span class="pun">.</span><span class="hljs-title"><span class="pln">macro</span></span><span class="pun">()</span></span></code></pre>

<p>
	يُمكنك كذلك استخدام التّعبير <code>from import</code> لاستيراد ماكرو واحد فقط كما في المثال التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs python"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'forms.html'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> input </span><span class="pun">%}</span></code></pre>

<p>
	هكذا ستتمكّن من استعمال الماكرو <code>input</code> عبر استدعائه، لكنّك لن تستطيع الوصول إلى الماكرو <code>textarea</code> حتى تستدعيه على نحو صريح.
</p>

<p>
	لاستدعاء أكثر من ماكرو واحد، افصل بينها بفاصلة كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs python"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'forms.html'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> textarea </span><span class="pun">%}</span></code></pre>

<p>
	يُمكنك كذلك استعمال الكلمة المفتاحية <code>as</code> لمنح اسم مُستعار لكلّ ماكرو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs python"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'forms.html'</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> input </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> textarea </span><span class="hljs-keyword"><span class="kwd">as</span></span><span class="pln"> t </span><span class="pun">%}</span></code></pre>

<p>
	بعد استيراد الماكرو باسم مُستعار، يُمكنك استخدام هذا الاسم المُستعار كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_993_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">i</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">t</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	بنهاية هذا الدّرس، يجب أن تكون قادرا على تصميم قوالب HTML بمرونة أكثر، بحيث تتمكّن من استغلال الجملة <code>import</code> لتفادي تكرار الشّيفرة والحصول على تجربة تطوير أفضل.
</p>
]]></description><guid isPermaLink="false">497</guid><pubDate>Thu, 08 Jun 2017 13:09:19 +0000</pubDate></item><item><title>&#x62F;&#x645;&#x62C; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; &#x628;&#x639;&#x636;&#x647;&#x627; &#x628;&#x628;&#x639;&#x636; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x627;&#x644;&#x62C;&#x645;&#x644;&#x629; include</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AF%D9%85%D8%AC-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-%D8%A8%D8%B9%D8%B6%D9%87%D8%A7-%D8%A8%D8%A8%D8%B9%D8%B6-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AC%D9%85%D9%84%D8%A9-include-r494/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.3d5b4879353763a2d271fbd2984d44ae.png" /></p>

<h2 id="دمج-القوالب-بعضها-ببعض-باستعمال-الجملة-include">
	مُقدّمة
</h2>

<p>
	تكرار الشّيفرة من أسوء المُمارسات التّي يُمكن لأي مُطوّر القيام بها، إذ تستهلك الكثير من الوقت الثّمين الّذي يُمكن صرفه في تطوير ميّزات أخرى وأمور أكثر أهميّة؛ سنتعرّف في هذا الدّرس على كيفيّة استغلال مُحرّك القوالب Jinja لتفادي تكرار الشّيفرة وتقسيم ملفّ HTML كبير إلى عدّة ملفّات صغيرة يُمكن إعادة استعمالها عبر الاعتماد على التعليمة <code>include</code> في Jinja.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23455" data-unique="o442w3asl" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.0546f9e91e8a42a48c5877c39eab5222.png"></p>

<h2 id="التعليمة-include-لتضمين-قالب-html-داخل-آخر">
	التعليمة <code>include</code> لتضمين قالب HTML داخل آخر
</h2>

<p>
	تُستعمل التعليمة <code>include</code> لتضمين مُحتويات ملفّ HTML في مكان ما في قالب HTML آخر.
</p>

<p>
	على سبيل المثال، لنقل بأنّ لدينا خمسة قوالب HTML في مجلّد <code>templates</code> الخاصّ بنا كما يلي:
</p>

<ul>
<li>
		ملفّ باسم <code>base.html</code>
	</li>
	<li>
		ملفّ باسم <code>header.html</code>
	</li>
	<li>
		ملفّ آخر باسم <code>content.html</code>
	</li>
	<li>
		ملفّ آخر باسم <code>footer.html</code>
	</li>
	<li>
		الملفّ الرّئيسي باسم <code>main.html</code>
	</li>
</ul>
<p>
	هكذا ستكون الصّورة العامّة للملفّات داخل المُجلّد <code>templates</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<span class="pun">└──</span><span class="pln"> templates
    </span><span class="pun">├──</span><span class="pln"> body</span><span class="pun">.</span><span class="pln">html
    </span><span class="pun">├──</span><span class="pln"> footer</span><span class="pun">.</span><span class="pln">html
    </span><span class="pun">├──</span><span class="pln"> header</span><span class="pun">.</span><span class="pln">html
    </span><span class="pun">└──</span><span class="pln"> main</span><span class="pun">.</span><span class="pln">html
    </span><span class="pun">└──</span><span class="pln"> base</span><span class="pun">.</span><span class="pln">html</span></pre>

<p>
	بالنّسبة للقالب <code>base.html</code> فهو معروف وطريقة استعماله واضحة، إذ يُعتبر القاعدة الأساسيّة لصفحات HTML التّي تعتمد عليه، ومُكوّناته ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<code class="hljs django"><span class="xml"><span class="hljs-doctype"><span class="dec">&lt;!DOCTYPE html&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">html</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">lang</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"en"</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">head</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">link</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">rel</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"stylesheet"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">meta</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">charset</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"UTF-8"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">title</span></span><span class="tag">&gt;</span></span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title %}</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> %}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">title</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">head</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">body</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body %}</span></span><span class="xml"><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> %}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">body</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">html</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	كما تُلاحظ هنا فإنّنا نقوم بوضع شِفرة HTML التّي تتكرّر في كلّ صفحة وفيها جزءان ديناميكيّان، الجزء الأول يُعنى بعنوان الصّفحة ويوجد داخل الوسم <code>&lt;title&gt;</code> وأمّا الجزء الثّاني فمسؤول عن الظّهور داخل جسم الصّفحة بالوسم <code>&lt;body&gt;</code>، وسنرى كيفيّة استغلال هذا القالب بعد لحظات.
</p>

<p>
	لاحظ كذلك بأنّنا أضفنا ملفّ CSS الخاص بإطار العمل Bootstrap في وسم <code>&lt;link&gt;</code> في الشّفرة أعلاه.
</p>

<p>
	أمّا عن قالب <code>header.html</code> فسيحمل شِفرة HTML التّي تكون عادة داخل الوسم <code>&lt;header&gt;</code> والتّي تكون مسؤولة عن الجزء العلوي من صفحة HTML كشريط التّصفّح وشعار التّطبيق وغير ذلك من المُكونات التّي تكون أعلى صفحات الويب. شيفرة هذا الملفّ ستكون عادة مُشابهة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">header</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"navbar navbar-default"</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"container-fluid"</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"nav navbar-nav"</span></span><span class="tag">&gt;</span></span><span class="pln">
                </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"navbar-brand"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"#"</span></span><span class="tag">&gt;</span></span><span class="pln"> Home
                    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"nav navbar-nav navbar-right"</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"/about/"</span></span><span class="tag">&gt;</span></span><span class="pln">
                    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">span</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"glyphicon glyphicon-info-sign"</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">span</span></span><span class="tag">&gt;</span></span><span class="pln"> About
                </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"/contact/"</span></span><span class="tag">&gt;</span></span><span class="pln">
                   </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">span</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"glyphicon glyphicon-envelope"</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">span</span></span><span class="tag">&gt;</span></span><span class="pln"> Contact
                </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
            </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
        </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">header</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	إن لم تفهم الشّفرة أعلاه فلا تقلق، إذ سيتّضح كلّ شيء بعد أن نجمع الملفّات بعضها مع بعض. لكن عليك أن تفهم فقط بأنّ الشّفرة بالأعلى عبارة عن شفرة HTML مع تنسيقات من إطار العمل Bootstrap تُمثّل شريط تصفّح به ثلاثة أزرار، الزّر Home للرّبط بالصّفحة الرّئيسية، والزّر About لصفحة “عن التّطبيق” والزّر Contact لصفحة التّواصل.
</p>

<p>
	أمّا ملفّ <code>footer.html</code> فسيحمل الشّفرة التّي تكون عادة أسفل صفحات الوِب مثل حقوق المُحتوى ومعلومات عن الشّركة صاحبة الموقع أو عن فريق التّطوير الّذي ساهم في بناء التّطبيق، بالإضافة إلى إمكانيّة احتوائه على معلومات التّواصل مع أصحاب التّطبيق أو معلومات أخرى، وقد تُلاحظ أسفل هذا الموقع (موقع أكاديميّة حسوب)، جزءا خاصّا بمُنتجات شركة حسوب وقد تُلاحظ ذلك في الصّفحات الأخرى التّابعة لمُنتجات حسوب، وهذا ما أقصده بالضّبط.
</p>

<p>
	كمثال على مُحتوى هذا الملفّ، سنستعمل الشِّفرة التّاليّة لعرض حقوق الموقع واسم المُطوّر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">footer</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"footer"</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"container"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">Built by Abdelhadi Dyouri</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"text-muted"</span></span><span class="tag">&gt;</span></span><span class="pln">All rights reserved.</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">p</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">footer</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	بالنّسبة للملفّ <code>content.html</code>، فسيكون المسؤول عمّا بداخل الوسم <code>&lt;div&gt;</code> ذي خاصيّة CSS المسمّاة <code>container</code> التّي يُوفّرها إطار العمل Bootstrap. سيشمل هذا الجزء المُكونات التي تُمثّل المُحتوى العام للموقع، فمثلا إن كان الموقع معنيّا بنشر المقالات، فالمُحتوى الّذي سيكون بداخل هذا الوسم هو لائحة المقالات وإن كانت الصّفحة خاصّة بعرض مقال واحد، فعنوان هذا المقال ومُحتواه وكاتبه والمعلومات العامّة حول المقال ستكون داخل هذا الوسم.<br>
	ما يُميّز هذا الجزء من صفحات HTML هو أنّه يكون مُتغيّرا عكس كلّ من رأس الصّفحة وأسفلها، إذ يبقى مثلا شريط التّصفّح هو نفسه في جميع صفحات التّطبيق وكذلك مُكوّنات أسفل الصّفحة كالحقوق والمعلومات حول التّطبيق، إذ يُمكن للمقالات في وسط الصّفحة أن تتبدّل وأن يتغيّر نوع المحتوى من مقال إلى صفحة لاستعراض المعلومات الشّخصيّة للكاتب وما إلى ذلك.
</p>

<p>
	على سبيل المثال، سنستعمل المثال الّذي سبق وأن شرحناه في درس الدّالتين <code>range</code> و<code>lipsum</code> لملْء مُحتوى هذا الملفّ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'container'</span></span><span class="tag">&gt;</span></span><span class="pln">
{% for i in range(8) %}
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'col-md-3'</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln"> </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'#'</span></span><span class="tag">&gt;</span></span><span class="pln"> </span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pln">(1, </span><span class="hljs-variable"><span class="pln">min</span></span><span class="pln">=3, </span><span class="hljs-variable"><span class="pln">max</span></span><span class="pln">=5) }}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="pln"> </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h2</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pln">(1, </span><span class="hljs-variable"><span class="pln">max</span></span><span class="pln">=50) }}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">button</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">'btn btn-default'</span></span><span class="tag">&gt;</span></span><span class="pln">Read more...</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">button</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span><span class="pln">
{% endfor %}
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">div</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	إن لم تقرأ الدّرس من قبل، فلا تقلق، المهم أن تفهم بأنّ الشّفرة أعلاه تُنتج ثمانيّة فقرات مع عنوان باستعمال نصّ <code>lorem ipsum</code>، ما يُتيح لنا الحصول على مُحتوى يُشبه المقالات دون كتابة شيفرة HTML كبيرة ومُكرّرة مكان استعمال دوال في Jinja للقيام بالأمر بكلّ بساطة.
</p>

<p>
	بالنّسبة للملفّ <code>main.html</code>، فهو الملفّ الرّئيسي الّذي سنستعمله لجمع هذه الملفّات لتظهر على شكل صفحة واحدة. الشّيء الّذي سنقوم به في الفقرة التّالية.
</p>

<h3 id="جمع-ملفات-html-لتظهر-في-صفحة-واحدة-باستخدام-التعليمة-include">
	جمع ملفّات HTML لتظهر في صفحة واحدة باستخدام التعليمة <code>include</code>
</h3>

<p>
	بعد أن أصبح لدينا كلّ من الجزء العلوي للموقع في ملفّ <code>header.html</code> ومُحتوى الموقع في الملفّ <code>content.html</code> والجزء السّفلي للصّفحة داخل ملفّ <code>footer.html</code>، حان الوقت لجمع كلّ هذه المُكونات في ملفّ واحد لتجتمع في صفحة واحدة.
</p>

<p>
	سنستخدم الملفّ <code>main.html</code> لجمع جميع هذه المُكوّنات وسنستعمل التعليمة <code>include</code> كما شرحنا مُسبقا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9924_8" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">extends</span></span><span class="pln"> </span><span class="str">'base.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> title </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">Application</span><span class="pln"> </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> body </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'header.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'content.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">include</span></span><span class="pln"> </span><span class="str">'footer.html'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln"> 

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	كما تُلاحظ، فقد استعملنا التعليمة <code>extends</code> للوراثة من الملفّ <code>base.html</code> الذي يُعتبر قاعدة الصّفحة، بعدها حدّدنا عنوانا للصّفحة عن طريق السّطر <code>{% block title %} My Application {% endblock %}</code>، بعدها حدّدنا جسم الصّفحة داخل الجزء <code>body</code> ومن ثمّ استعملنا التعليمة <code>include</code> لتضمين كلّ من الملفّات <code>header.html</code>، <code>content.html</code> و<code>footer.html</code> داخل الصّفحة، لكن لاحظ بأنّ التّرتيب مُهمّ وهو نفس التّرتيب المنطقي الذي يجب اتّباعه، بحيث يكون تضمين الجزء العلوي أولا ثمّ الجزء المسؤول عن المُحتوى ثمّ الجزء السّفلي للصّفحة.
</p>

<p>
	يُمكنك أن تتخيّل بأنّ الجملة <code>include</code> غير مُتواجدة ويتواجد في مكانها كلّ الشّيفرة المتواجدة داخل ملفّ HTML المُضمّن، فعوضا عن السّطر <code>{% include 'header.html' %}</code> ستكون شيفرة الملفّ <code>header.html</code> وهكذا…
</p>

<p>
	بعد إنهاء تطبيق ما سبق، ستُلاحظ نتيجة مُشابهة لما في الصّورة التّاليّة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23454" href="https://academy.hsoub.com/uploads/monthly_2017_05/01_include_files.png.1814ec9daefae1915b5af5962f5f2483.png" rel=""><img alt="01_include_files.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23454" data-unique="6uu1z309g" src="https://academy.hsoub.com/uploads/monthly_2017_05/01_include_files.thumb.png.49ddcd1bb794b0fb1e114375f455eaf9.png"></a><img alt="66402eaf_o.png" src="http://i.share.pho.to/66402eaf_o.png" title=""></p>

<h3 id="متى-تستعمل-التعليمة-include-ولماذا">
	متى تستعمل التعليمة <code>include</code> ولماذا
</h3>

<p>
	استعمال التعليمة <code>include</code> مُفيد لأنّه يُعطيك حرّية أكثر في العمل على أجزاء مُختلفة من صفحات الويب في تطبيقك، إذ يُمكنك تطوير الجزء السّفلي من الصّفحة دون الاضطرار إلى المرور بالشّفرة المسؤولة عن الأجزاء الأخرى، ما يُتيح لك تجربة تطوير أفضل، بالإضافة إلى أنّ تقسيم أجزاء الصّفحات إلى ملفّات HTML مُستقلّة أمر مُفيد إن كنت تعمل مع أحدهم على تطوير نفس التّطبيق أو حتّى فريق مُكوّن من أكثر من شخصين، إذ يُمكنك مثلا العمل على الجزء العلوي من الصّفحة وتترك صديقك يعمل على مُحتويات الصّفحة وصديق آخر يعمل على الجزء السّفلي بحيث لا يُعدّل الجميع نفس الملفّ في نفس الوقت.
</p>

<p>
	بالإضافة إلى أنّ التعليمة <code>include</code> تُساعد على تقسيم ملفّ HTML إلى عدّة ملفّات صغيرة لتسهيل عمليّة التّطوير، يُمكن كذلك أن تستفيد من هذه الملفّات عبر إعادة استعمالها في أكثر من ملفّ HTML لتفادي تكرار الشّيفرة واختصار الوقت.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كيفيّة تقسيم صفحة HTML إلى عدّة ملفّات وكيفيّة جمعها داخل ملفّ واحد باستعمال الجملة <code>include</code> لتوفير تجربة تطوير أفضل، في الدّرس القادم، سنلقي نظرة على مبدأ الاستيرادات في مُحرّك القوالب Jinja وكيفيّة الاستفادة منه.
</p>
]]></description><guid isPermaLink="false">494</guid><pubDate>Thu, 01 Jun 2017 21:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x651;&#x648;&#x627;&#x644; &#x627;&#x644;&#x645;&#x628;&#x646;&#x64A;&#x651;&#x629; &#x645;&#x64F;&#x633;&#x628;&#x642;&#x627; &#x641;&#x64A; &#x645;&#x64F;&#x62D;&#x631;&#x651;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja&#x60C; &#x627;&#x644;&#x62F;&#x651;&#x627;&#x644;&#x651;&#x629; dict &#x648;&#x627;&#x644;&#x635;&#x651;&#x646;&#x641; cycler</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AF%D9%91%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%A8%D9%86%D9%8A%D9%91%D8%A9-%D9%85%D9%8F%D8%B3%D8%A8%D9%82%D8%A7-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja%D8%8C-%D8%A7%D9%84%D8%AF%D9%91%D8%A7%D9%84%D9%91%D8%A9-dict-%D9%88%D8%A7%D9%84%D8%B5%D9%91%D9%86%D9%81-cycler-r490/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.b7f412c02fb8e8426bab963150ada63d.png" /></p>

<h2 id="تمهيد">
	تمهيد
</h2>

<p>
	إلى الآن، تعرّفنا على العديد من أساسيّات تطوير الويب باستعمال كلّ من إطار العمل Flask ومُحرّك القوالب Jinja، وفي الدّرس السّابق، تعرّفنا على ماهيّة الدّوال المُسبقة التّعريف في هذا الأخير، إذ تعرّفنا كبداية على كلّ من الدّالة <code>range()</code> والدّالة <code>lipsum</code>، وسنُكمل في هذا الدّرس ما بدأناه لنتعرّف على بقيّة الدّوال والأصناف المبنيّة مُسبقا في مُحرّك القوالب Jinja ليُساعدك ذلك على تطوير تطبيقات وِب أفضل.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23384" data-unique="co2v5qu26" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.cd5afae1fa6000d944406fbeae774004.png"></p>

<h2 id="الدالة-dict">
	الدّالة dict
</h2>

<p>
	في لغة بايثون، هناك نوع خاصّ من القيم يُسمّى القواميس Dictinaries، في كلّ قاموس نجد مفاتيح وقيّما لتُساعدنا على ترتيب البيانات وتسهيل البحث عن قيمة ما عبر مفتاحها، كما نستطيع الوصول إلى كلّ من القيم والمفاتيح باستعمال حلقة <code>for</code> بسيطة.
</p>

<p>
	في مُحرّك القوالب Jinja، القواميس مُشابهة لقواميس بايثون، إذ يُمكنك تعريف قاموس كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<span class="pun">{%</span><span class="pln"> set dictionary </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'1'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'2'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">}</span><span class="pln"> </span><span class="pun">%}</span></pre>

<p>
	في المثال أعلاه، كلّ من <code>1</code> و <code>2</code> عبارة عن مفاتيح، أمّا <code>One</code> و <code>Two</code> فهي قيم المفاتيح، بحيث <code>One</code> قيمة المفتاح <code>1</code> و <code>Two</code> قيمة المفتاح <code>2</code>.
</p>

<p>
	للحصول على القيم في القاموس، يُمكن استخدام اسم المُتغيّر الذي يحمل القاموس مع المفاتيح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">dictionary</span></span><span class="pun">[</span><span class="str">'1'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">dictionary</span></span><span class="pun">[</span><span class="str">'2'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs "><span class="typ">One</span><span class="pln"> 
</span><span class="typ">Two</span></code></pre>

<p>
	<strong>مُلاحظة:</strong> في المثال أعلاه، قُمنا باستخدام الكلمة المفتاحيّة <code>set</code> لتعريف مُتغيّر يحمل قاموسا كقيمة، لكن يُمكن كذلك أن تُمرّر مُتغيّرا يحمل قاموسا من ملفّات التّحكم – وهو الجزء الّذي يهتمّ به إطار العمل Flask - إلى قوالب HTML، لذا ففي هذه الحالة ستتمكّن من الوصول إلى القاموس مُباشرة من المُتغيّر دون تعريفه على نحو صريح باستعمال مُحرّك القوالب Jinja.
</p>

<p>
	يُمكنك في مُحرّك القوالب Jinja إنشاء قواميس بطريقة أفضل عبر الاستعانة بالدّالة <code>dict()</code>، إذ يُمكنك استعمال الدّالة لإنشاء قاموس تكون مفاتيحه هي أسماء المُعاملات وقيمة المُعامل هي نفسها قيمة المفتاح.
</p>

<p>
	التّالي مثال على كيفيّة استخدام الدّالة <code>dict()</code> لإنشاء قاموس بسيط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs scss"><span class="hljs-function"><span class="pln">dict</span><span class="pun">(</span><span class="pln">key</span><span class="pun">=</span><span class="hljs-string"><span class="str">'value'</span></span><span class="pun">,</span><span class="pln"> another_key</span><span class="pun">=</span><span class="hljs-string"><span class="str">'another value'</span></span><span class="pun">)</span></span></code></pre>

<p>
	المثال أعلاه سيُنتج قاموسا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs bash"><span class="pun">{</span><span class="hljs-string"><span class="str">'another_key'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'another value'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'key'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'value'</span></span><span class="pun">}</span></code></pre>

<p>
	تُستخدم القواميس عندما يكون لدينا نوع من القيم المُترابطة والتّي لها أصل واحد، فمثلا لنقل بأنّ القاموس يُمثّل بطاقة تعريف أحدهم، في القاموس سيتوجّب علينا تخزين الاسم الأوّل للشّخص، والاسم العائلي أو نسبُ نفس الشّخص.
</p>

<p>
	المثال التّالي توضيح على كيفيّة استخدام الدّالة <code>dict</code> لإنشاء قاموس يعمل على تخزين الاسم الكامل لشخص ما وعرض جملة ترحيبيّة مُخصّصة له:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs matlab"><span class="hljs-cell"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> dictionary </span><span class="pun">=</span><span class="pln"> dict</span><span class="pun">(</span><span class="pln">firstname</span><span class="pun">=</span><span class="hljs-string"><span class="str">'أحمد'</span></span><span class="pun">,</span><span class="pln"> lastname</span><span class="pun">=</span><span class="hljs-string"><span class="str">'علي'</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span></span><span class="pln">

</span><span class="pun">مرحبا</span><span class="pln"> </span><span class="pun">يا</span><span class="pln"> </span><span class="hljs-cell"><span class="pun">{{</span><span class="pln"> dictionary</span><span class="pun">[</span><span class="hljs-string"><span class="str">'firstname'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span></span><span class="pun">}</span><span class="pln"> </span><span class="hljs-cell"><span class="pun">{{</span><span class="pln"> dictionary</span><span class="pun">[</span><span class="hljs-string"><span class="str">'lastname'</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">}</span></span><span class="pun">}!</span></code></pre>

<p>
	النّتيجة ستكون الجملة التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs erlang-repl"><span class="pun">مرحبا</span><span class="pln"> </span><span class="pun">يا</span><span class="pln"> </span><span class="pun">أحمد</span><span class="pln"> </span><span class="pun">علي</span><span class="hljs-exclamation_mark"><span class="pun">!</span></span></code></pre>

<p>
	وبالطّبع فالنّتيجة ستتغيّر كلّما غيّرت أحد قيمتي المُعاملين <code>firstname</code> و<code>lastname</code> أثناء استدعاء الدّالة <code>dict</code>.
</p>

<p>
	من الأمور المُميّزة في الدّالة <code>dict</code> أنّها تُعطيك الحرّية في اختيار كيفيّة الوصول إلى قيمة كلّ مفتاح.
</p>

<p>
	سابقا، استعملنا الطّريقة التّقليديّة للوصول إلى قيم القاموس كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs bash"><span class="pln">dictionary</span><span class="pun">[</span><span class="hljs-string"><span class="str">'firstname'</span></span><span class="pun">]</span><span class="pln"> dictionary</span><span class="pun">[</span><span class="hljs-string"><span class="str">'lastname'</span></span><span class="pun">]</span></code></pre>

<p>
	لكن يُمكننا كذلك الوصول إلى القيم بطريقة أسرع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs avrasm"><span class="pln">dictionary</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">firstname</span></span><span class="pln">
dictionary</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">lastname</span></span></code></pre>

<p>
	بهذه الطّريقة يُمكنك اعتبار المفاتيح خصائص كما في خصائص الأصناف في لغة بايثون، ما يعني بأنّك تستطيع استخدام المُرشّحات والاختبارات التّي تسمح لك باختبار قيم الخصائص مُباشرة.
</p>

<p>
	بالتّالي فالمثال السّابق سيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pun">مرحبا</span><span class="pln"> </span><span class="pun">يا</span><span class="pln"> </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">dictionary</span><span class="pun">.</span><span class="pln">firstname</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">dictionary</span><span class="pun">.</span><span class="pln">lastname</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pun">!</span></span></code></pre>

<p>
	ستُلاحظ بأنّ النّتيجة هي نفسها وبأنّ هذا المثال الأخير أفضل من المثال السّابق لأنّك تستطيع اختصار بعض الوقت عند الوصول إلى قيم المفاتيح بهذه الطّريقة.
</p>

<h2 id="الصنف-cycler">
	الصّنف cycler
</h2>

<p>
	يُمكّنك الصّنف cycler من الدّوران حول مجموعة من العناصر بشكل لا نهائي، مع إمكانيّة إعادة الدّوران في وقت مُحدّد إن أردت ذلك.
</p>

<p>
	على سبيل المثال، لنقل بأنّك تُريد الدّوران حول قائمة من الأسماء بشكل لا نهائي بحيث تُعاد الدّورة في كلّ مرّة.<br>
	لنضع الشّيفرة التّالية كمثال لكيفيّة استعمال الصّنف <code>cycler</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs sql"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">names</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cycler</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Ahmed'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ali'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Hassan'</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	في هذا المثال، أنشأنا كائنا من الصّنف <code>cycler</code> وأسندناه إلى المُتغيّر <code>names</code>.
</p>

<p>
	يُمكننا الآن استخدام الكائن <code>names</code> للدّوران حول قائمة الأسماء التّي مرّرناها إلى الصّنف <code>cycler</code>.
</p>

<p>
	من المُهم أن نفهم بأنّ الكائن <code>names</code> سيحمل قيمة واحدة فقط في كلّ مرّة نستدعيه فيه باستخدام أحد توابع أو خصائص الصّنف <code>cycler</code>، إذ يُمكننا استخدام الخاصيّة <code>current</code> للحصول على القيمة الحاليّة، والتّابع <code>next()</code> للوصول إلى القيمة التّاليّة، بالإضافة إلى التّابع <code>reset()</code> لإعادة الدّوران من جديد والوصول إلى أول قيمة.
</p>

<p>
	القيمة التي سيحملها الكائن <code>names</code> عند استعمال أحد التّوابع ستكون أحد الأسماء في مجموعة الأسماء التّي حدّدناها من قبل فقط ولا يُمكن أن تكون قيمة أخرى.
</p>

<h3 id="الوصول-إلى-قيمة-الدوران-الحالية">
	الوصول إلى قيمة الدّوران الحاليّة
</h3>

<p>
	إن اعتبرنا المثال السّابق، فإنّنا نستطيع الوصول إلى قيمة الدّوران الحاليّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs sql"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">names</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cycler</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Ahmed'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ali'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Hassan'</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{{</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">names</span></span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">current</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	وبما أنّنا لم نقم بأي انتقال من قيمة إلى الّتي تليها عبر التّابع <code>next()</code>، فالقيمة البدئيّة ستكون أول عنصر من مجموعة العناصر المُمرّرة إلى الصّنف <code>cycler</code>، أي الاسم <code>Ahmed</code> في هذه الحالة.
</p>

<h3 id="الوصول-إلى-قيمة-الدوران-التالية">
	الوصول إلى قيمة الدّوران التّاليّة
</h3>

<p>
	للوصول إلى القيمة التّاليّة وعرضها، يُمكنك استخدام التّابع <code>next()</code> على الكائن <code>names</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	ستُلاحظ بأنّ النّتيجة هي نفسها النّتيجة التّي تظهر عند استخدام الخاصيّة <code>current</code> أي أنّ القيمة التّي ظهرت هي العنصر الأول من قائمة العناصر.
</p>

<p>
	هذا لأنّه يتوجّب علينا استخدام التّابع <code>next()</code> أكثر من مرّة ليظهر مفعوله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">names</span><span class="pun">.</span><span class="kwd">next</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span></span></code></pre>

<p>
	استخدمنا في المثال أعلاه التّابع <code>next()</code> خمس مرّات، والنّتيجة كما المُتوقّع ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs "><span class="typ">Ahmed</span><span class="pln"> 
</span><span class="typ">Ali</span><span class="pln"> 
</span><span class="typ">Hassan</span><span class="pln"> 
</span><span class="typ">Ahmed</span><span class="pln"> 
</span><span class="typ">Ali</span><span class="pln"> </span></code></pre>

<p>
	كما تُلاحظ، عندما وصلت القيمة إلى آخر عنصر (أي الاسم <code>Hassan</code>)، فقد عادت الدّورة إلى البداية من جديد لتستمرّ في الدّوران حول القيم، هذا يعني بأنّك تستطيع استخدام التّابع <code>next()</code> لعدد لا نهائي من المرّات مع أي مجموعة من العناصر.
</p>

<h3 id="استخدام-الصنف-cycler-مع-قائمة-بايثون">
	استخدام الصّنف cycler مع قائمة بايثون
</h3>

<p>
	بما أنّ الصّنف <code>cycler</code> يعمل مع قيمٍ عدّة، فمن الطّبيعي أن ترغب في استخدامه مع قائمة عاديّة تحتوي على مجموعة من العناصر.
</p>

<p>
	لكن إن مرّرت قائمة إلى الصّنف <code>cylcer</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">names</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cycler</span><span class="pun">([</span><span class="hljs-string"><span class="str">'Ahmed'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ali'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Hassan'</span></span><span class="pun">])</span></span></code></pre>

<p>
	فسيعتبر الصّنف هذه القائمة المُمرّرة مُجرّد قيمة واحدة، ولو استعملت مثلا التّابع <code>next()</code> على القائمة مرّتين فستحصل على النّتيجة التّالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="str">'Ahmed'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Ali'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hassan'</span><span class="pun">]</span><span class="pln"> 
</span><span class="pun">[</span><span class="str">'Ahmed'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Ali'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hassan'</span><span class="pun">]</span><span class="pln"> </span></code></pre>

<p>
	هذا يعني بأنّ الصّنف <code>cycler</code> لا يعتبر القائمة مجموعة من العناصر كما يجب.
</p>

<p>
	لحلّ هذه المُشكلة، استعمل الرّمز <code>*</code> قبل القائمة لتفكيكها وتمرير كلّ عنصر منها على شكل مُعامل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs sql"><span class="hljs-operator"><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">names</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cycler</span><span class="pun">(*[</span><span class="hljs-string"><span class="str">'Ahmed'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ali'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Hassan'</span></span><span class="pun">])</span></span></code></pre>

<p>
	هذه الطّريقة تعمل حتى لو كانت القائمة مُسندة إلى مُتغيّر ما كذلك، على سبيل المثال إن كانت لديك قائمة باسم <code>list</code> وأردت تمرير عناصرها إلى الصّنف <code>cycler</code> فيُمكنك ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5232_7" style="">
<code class="hljs erlang"><span class="hljs-function"><span class="hljs-title"><span class="pln">cycler</span></span><span class="hljs-params"><span class="pun">(*</span><span class="pln">list</span><span class="pun">)</span></span></span></code></pre>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	تعرّفنا في هذا الدّرس على كلّ من الدّالة <code>dict</code> والصّنف <code>cycler</code> لمُساعدتك على بناء صفحات HTML أفضل عند استعمال كلّ من إطار العمل Flask ومُحرّك القوالب Jinja، في الدّرس القادم سنتعرّف على جزء آخر لا يقلّ أهميّة عمّا درسناه في الدّروس السّابقة، ألا وهو كيفيّة التّعامل مع أكثر من ملفّ عبر تضمينها بعضها ببعض لتفادي تكرار الشّيفرة البرمجيّة.
</p>
]]></description><guid isPermaLink="false">490</guid><pubDate>Thu, 25 May 2017 05:45:10 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62F;&#x651;&#x648;&#x627;&#x644; &#x627;&#x644;&#x645;&#x628;&#x646;&#x64A;&#x651;&#x629; &#x645;&#x64F;&#x633;&#x628;&#x642;&#x627; &#x641;&#x64A; &#x645;&#x64F;&#x62D;&#x631;&#x651;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja&#x60C; &#x627;&#x644;&#x62F;&#x651;&#x627;&#x644;&#x651;&#x62A;&#x627;&#x646; range &#x648;lipsum</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AF%D9%91%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%A8%D9%86%D9%8A%D9%91%D8%A9-%D9%85%D9%8F%D8%B3%D8%A8%D9%82%D8%A7-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja%D8%8C-%D8%A7%D9%84%D8%AF%D9%91%D8%A7%D9%84%D9%91%D8%AA%D8%A7%D9%86-range-%D9%88lipsum-r488/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.faa7c79cc3770c87724712003075c14c.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	بعد أن تعرّفنا على المُرشّحات والاختبارات في مُحرّك القوالب Jinja، بقي أن نتعرّف على الدّوال التّي يُمكنك استعمالها لتسهيل عمليّة تطوير قوالب HTML، هذه الدّوال مُشابهة للدّوال التّي يُمكنك استخدامها في لغة بايثون، ما يعني بأنّك تستطيع استخدامها كما تُستخدم في لغة بايثون، أي باستدعائها وتمرير مُعاملات إليها إن كان ذلك مُمكنا.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23338" data-unique="vfc3c3n1k" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.3b5119aeaae3689b9b96ec084a22ce4f.png"></p>

<p>
	<br>
	في هذا الدّرس، سنتعرّف على كلّ من الدّالة <code>range</code> والدّالة <code>lipsum</code> اللّتان تُعتبران دالّتين مُهمّتين لكل مُصمّم قوالب ولمُطوّري الويب الّذين يستخدمون إطار العمل Flask خصّيصا.
</p>

<p>
	ولتطبيق الأمثلة المذكورة في هذا الدّرس، يُمكنك الاستعانة بملفّ <code>filters.html</code> الّذي أنشأناه سابقا في بداية هذه <a href="https://academy.hsoub.com/tags/flask_cms/" rel="">السّلسة</a> للتّحقق من نتائج أمثلة المُرشّحات.
</p>

<p>
	إن لم تتّبع <a href="https://academy.hsoub.com/tags/flask_cms/" rel="">سلسلة الدّروس</a> منذ البداية، فلا مُشكلة، إذ يُمكنك إنشاء تطبيق بسيط بإطار العمل Flask بحيث يحتوي على موجّه واحد على الأقل يُقدّم صفحة HTML لتستطيع التّعامل معها عبر مُحرّك القوالب Jinja الّذي يُعتبر الأداة الافتراضيّة لإدارة قوالب HTML في تطبيقات الويب المبنيّة بإطار العمل Flask.
</p>

<p>
	بعد تجهيز قالب لنختبر به الأمثلة، لننتقل الآن إلى التّعرف على الدّوال المبنيّة مُسبقا في مُحرّك القوالب Jinja.
</p>

<h2 id="الدالة-range">
	الدّالة range
</h2>

<p>
	الدّالة <code>range()</code> في Jinja تعمل بشكل مُشابه لطريقة عمل الدّالة التّي تحمل نفس الاسم في لغة Python. إذ تُساعدك على إنشاء قائمة أعداد حسب المُعاملات.
</p>

<p>
	افتراضيّا، الدّالة <code>range</code> تعمل إذا ما مرّرت إليها قيمة واحدة كمُعامل عددي، والنّتيجة تكون قائمة بالأعداد من 0 إلى العدد ما قبل العدد الذي مُرِّرَ كمُعامل.
</p>

<p>
	مثلا، استدعاء الدّالة <code>range</code> مع تمرير العدد 10 كمُعامل سيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<span class="pln">range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span></pre>

<p>
	نتيجة المثال ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">7</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">9</span></span><span class="pun">]</span></code></pre>

<p>
	لاحظ بأنّ النّتيجة عبارة عن قائمة تحتوي على 10 عناصر من الصّفر إلى تسعة دون تضمين العدد 10 الذي يُعتبر المُعامل المُستخدم.
</p>

<p>
	<strong>مُلاحظة:</strong> إن طبّقت المثال أعلاه في ملفّ HTML فلن تظهر النّتيجة حتّى تُطبّق المُرشّح <code>list</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">range</span></span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">list</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	لكن عموما تستطيع استخدام حلقة <code>for</code> مع نتيجة الدّالة مُباشرة دون استخدام المُرشّح <code>list</code>.
</p>

<h3 id="تحديد-القيمة-البدئية">
	تحديد القيمة البدئيّة
</h3>

<p>
	عندما نستعمل الدّالة <code>range</code> في ملفّات HTML مع تمرير مُعامل واحد فقط، فالقيمة البدئيّة تكون دائما العدد 0، لكن يُمكنك تغيير هذا الوضع بتمرير مُعامل قبل مُعامل القيمة القُصوى ليبدأ العدّ من هذه القيمة الجديدة إلى حين الوصول إلى العدد ما قبل القيمة القُصوى.
</p>

<p>
	كمثال على ذلك، لنعتبر بأنّنا نحتاج إلى قائمة تبدأ من العدد 5 وتنتهي بالعدد 15، في هذه الحالة سيتوجّب علينا استخدام الدّالة <code>range</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">range</span></span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">list</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	هكذا ستكون النّتيجة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">7</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">9</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">11</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">12</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">13</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">14</span></span><span class="pun">]</span></code></pre>

<p>
	كما تُلاحظ، فقد انتهت القائمة بالعدد 14 وليس بالعدد 15 كما قد تتوقّع، لذا لو أردت تضمين العدد 15 في القائمة فسيتوجّب عليك استخدام العدد 16 في المقام الأول كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs erlang"><span class="hljs-function"><span class="hljs-title"><span class="pln">range</span></span><span class="hljs-params"><span class="pun">(</span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">16</span></span><span class="pun">)</span></span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">7</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">9</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">11</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">12</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">13</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">14</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">15</span></span><span class="pun">]</span></code></pre>

<h3 id="تحديد-قيمة-الزيادة">
	تحديد قيمة الزّيادة
</h3>

<p>
	افتراضيّا، قيمة الزّيادة هي العدد 1، إذ يكون كلّ عنصر أكبر من العدد الذّي يسبقه في القائمة بواحد، وإن أردت أن تُغيّر قيمة الزّيادة فيُمكنك تمريرها كمُعامل ثالث.
</p>

<p>
	على سبيل المثال، لو أردنا الحصول على العشرات التّي تحتوي على رقمين فقط (20, 50 …) فسيُمكننا أن نقوم بتوليد قائمة عناصرها تبدأ من العدد 10 إلى العدد 100 بزيادة قيمتها العدد 10، ويُمكننا القيام بالأمر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs erlang"><span class="hljs-function"><span class="hljs-title"><span class="pln">range</span></span><span class="hljs-params"><span class="pun">(</span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">)</span></span></span></code></pre>

<p>
	النّتيجة ستكون جميع العشرات من 10 إلى 90 في قائمة كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">20</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">30</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">40</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">50</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">60</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">70</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">80</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">90</span></span><span class="pun">]</span><span class="pln"> </span></code></pre>

<p>
	يُمكن لقيمة الزّيادة أن تكون سلبيّة كذلك، ما يسمح لك بالحصول على قائمة عكسيّة أو عدّ تنازلي.
</p>

<p>
	فمثلا، يُمكننا الحصول على قائمة الأعداد من 10 إلى 1 كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs erlang"><span class="hljs-function"><span class="hljs-title"><span class="pln">range</span></span><span class="hljs-params"><span class="pun">(</span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">)</span></span></span></code></pre>

<p>
	هنا نضع العدد 10 كقيمة بدئيّة والعدد 0 كقيمة قُصوى لأنّ آخر عدد قبل الصّفر هو العدد 1، وفي قيمة الزّيادة نضع العدد السّلبي <code>-1</code>.
</p>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs json"><span class="pun">[</span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">9</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">7</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">]</span><span class="pln"> </span></code></pre>

<p>
	يُمكنك تغيير قيمة الزّيادة إلى أي عدد سلبي آخر حسب ظروف الاستعمال.
</p>

<h3 id="أمثلة-على-استخدام-الدالة-range-في-تطبيقات-إطار-العمل-flask">
	أمثلة على استخدام الدّالة range في تطبيقات إطار العمل Flask
</h3>

<p>
	بعد أن تعرّفنا على الهدف من الدّالة <code>range</code> وكيفيّة استعمالها في مُختلف الحالات مع عدّة مُعاملات، لننتقل الآن إلى أمثلة واقعيّة لكيفيّة استخدام هذه الدّالة في تطوير تطبيقات الويب.
</p>

<h4 id="المثال-الأول-تكرار-نص-ما-عدة-مرات">
	المثال الأول، تكرار نصّ ما عدّة مرّات
</h4>

<p>
	في تطبيقات الويب، قد ترغب بتكرار نصّ ما عدّة مرّات لتوضيح فكرة أو للحصول على صورة عامّة للصّفحة مع مُحتوى وهمي.
</p>

<p>
	يُمكنك استخدام الدّالة <code>range()</code> لتكرار نصّ ما أو مقطع HTML عددا من المرّات حسب العدد المُمرّر كمُعامل، فمثلا، يُمكننا تكرار المقطع “مرحبا بالعالم!” 10 مرّات باستعمال الشّيفرة التّالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> number </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span><span class="pun">مرحبا</span><span class="pln"> </span><span class="pun">بالعالم!</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	لاحظ بأنّنا قد تعاملنا مع الدّالة <code>range</code> كقائمة عاديّة دون الحاجة إلى استعمال المُرشّح <code>list</code> على نحو صريح.
</p>

<h4 id="المثال-الثاني-توليد-أرقام-الصفحات">
	المثال الثّاني، توليد أرقام الصّفحات
</h4>

<p>
	لنقل بأنّنا نمتلك العديد من السّجلات في قاعدة بياناتنا ونرغب بعرضها على شكل صَفحات، بالإضافة إلى أنّنا نريد توفير طريقة بسيطة لنُمكّن المُستخدم من التّنقل عبر الصّفحات بِحُرّيَة. يُمكننا في هذه الحالة أن نُنشئ شريطا لأرقام الصّفحات ونربط كلّ رقم برابط الصّفحة التّابعة له.
</p>

<p>
	التّالي مثال بسيط على كيفيّة إنشاء شريط تصفّح يُغطّي أرقام الصّفحات من 1 إلى 9:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> number </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">span</span></span><span class="str">&gt;</span></span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> number </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">span</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs "><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span></code></pre>

<p>
	في المثال لم نقم سوى بعرض كل رقم داخل وسم <code>&lt;span&gt;</code> وإن أردت تطوير هذا المثال أكثر، فسيلزمك استخدام الدّالة <code>url_for</code> التي يوفّرها إطار العمل Flask لربط كلّ رقم بالصّفحة الخاصّة به.
</p>

<h2 id="الدالة-lipsum">
	الدّالة lipsum
</h2>

<p>
	إن كانت لك خلفيّة في التّصميم فلا بدّ أن تكون قد سمعت عن نصّ <code>lorem ipsum</code>، إن كان الأمر كذلك، فالدّالة <code>lipsum()</code> ستُساعدك على توليد مقاطع عشوائيّة من هذا النّص لتستعملها في ملفّات HTML الخاصّة بك.
</p>

<p>
	إن لم تسمع من قبل عن <code>lorem ipsum</code>، فهو ببساطة نصّ لاتيني يُستعمل في التّصاميم الطّباعيّة كمثال على نصّ صحيح، وذلك لكي تتوضّح الصّورة لدى المُصمّم ومن يرى التّصميم، وقد أصبح يُستعمل كثيرا في تصاميم الويب لتأديّة نفس الواجب، بحيث يُستعمل على شكل فقرات وعناوين في ملفّات HTML لتوضيح التّصميم والحصول على فكرة عن الصّورة العامّة للتّصميم عندما تكون النّصوص مُتوفّرة، فمثلا إن كنت تُصمّم صفحة ويب لعرض مقالات ما، فستنقصك المقالات لتتوضّح صورة التّصميم بالنّسبة إليك، لذا فاللجوء إلى توليد هذا النّص العشوائي أسرع طريقة للحصول على تصميم يحتوي على مقالات وهميّة.
</p>

<p>
	طريقة استعمال الدّالة هي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	افتراضيّا، تولّد الدّالة <code>lipsum</code> خمسة فقرات، كلّ فقرة تحتوي على ما بين 20 إلى 100 كلمة، ويُمكنك تغيير هذه الإعدادات عبر تمرير مُعاملات إلى الدّالة.
</p>

<p>
	لتغيير عدد الفقرات المُولّدة، يُمكنك تمرير العدد الذي ترغبه كمُعامل. لذا فإن كنت ترغب بالحصول على فقرتين فقط، فستحصل على هذه النّتيجة كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	الحدّ الأدنى لعدد الكلمات في كلّ فقرة هو 20 كلمة، إن كنت ترغب بتعديل هذا فمرّر العدد الأدنى كقيمة للمُعامل <code>min</code>.<br>
	التّالي مثال على كيفيّة جعل الدّالة <code>lipsum</code> تولّد فقرة واحدة تحتوي على 60 كلمة أو أكثر دون النّزول عن هذا الحدّ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">lipsum</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> min</span></span><span class="pun">=</span><span class="hljs-string"><span class="lit">60</span><span class="pun">)</span></span></code></pre>

<p>
	الحدّ الأقصى لعدد الكلمات المُولّدة يكون 100 كلمة بشكل افتراضي، لكن تغييره يُمكنك تمرير العدد الّذي تودّ أن يكون العدد الأقصى إلى المُعامل <code>max</code>.
</p>

<p>
	على سبيل المثال، الشّيفرة التّاليّة ستقوم بتوليد فقرتين عدد كلمات كلّ واحدة منهما بين 50 إلى 80 كلمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">min</span></span><span class="pun">=</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">max</span></span><span class="pun">=</span><span class="lit">80</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<h2 id="مثال-يجمع-كلا-من-الدالة-range-والدالة-lipsum">
	مثال يجمع كلّا من الدّالة range والدّالة lipsum
</h2>

<p>
	بعد أن تعرّفنا على كلّ من الدّالة <code>range</code> والدّالة <code>lipsum</code>، حان الوقت لاستعمالهما في مثال واحد لتتّضح لك فكرة استعمالهما وتحصل على أفكار أخرى لكيفيّة استغلال ما تعلّمته في هذا الدّرس.
</p>

<p>
	في هذا المثال، سنقوم بعرض ثمانيّة فقرات من نصّ <code>lorem ipsum</code> مع عنوان يعمل على شكل رابط بالإضافة إلى زرّ لتمكين الزّائر من قراءة المزيد. وسنستعمل إطار العمل Bootstrap للحصول على تصميم جميل.
</p>

<p>
	شيفرة المثال ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_240_7" style="">
<code class="hljs handlebars"><span class="xml"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">div</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">'col-md-3'</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">h2</span></span><span class="str">&gt;</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">'#'</span></span><span class="pun">&gt;</span></span><span class="pln"> </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">min</span></span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">max</span></span><span class="pun">=</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="str">/</span><span class="hljs-title"><span class="str">a</span></span><span class="str">&gt;</span></span><span class="str"> </span><span class="hljs-tag"><span class="str">&lt;/</span><span class="hljs-title"><span class="pln">h2</span></span><span class="pun">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">lipsum</span></span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">max</span></span><span class="pun">=</span><span class="lit">50</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">button</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="kwd">class</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">'btn btn-default'</span></span><span class="pun">&gt;</span></span><span class="typ">Read</span><span class="pln"> more</span><span class="pun">...</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">button</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">div</span></span><span class="pun">&gt;</span></span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endfor </span><span class="pun">%}</span></span></code></pre>

<p>
	نقوم أولا باستعمال حلقة <code>for</code> مع الدّالة <code>range</code> مع تمرير العدد 8 كمُعامل، لذا فأي شيفرة داخل حلقة <code>for</code> هذه ستتكرّر ثماني مرّات.
</p>

<p>
	داخل حلقة <code>for</code>، نستعمل وسم <code>&lt;div&gt;</code> وخاصيّة CSS<br><code>col-md-3</code> التّي يُوفّرها لنا إطار العمل Bootstrap لتقسيم صفحة الويب لأجزاء مُتساويّة.
</p>

<p>
	داخل وسم <code>&lt;div&gt;</code> نستعمل الدّالة <code>lipsum</code> لتوليد نصّ عشوائي صغير ليظهر على شكل عنوان للمقال الوهمي، بعدها نستعمل الدّالة مُجدّدا لتوليد فقرة واحدة عدد كلماتها لا يتعدّى 50 كلمة، ثمّ بعد ذلك نعرض زرّا لقراءة المزيد.
</p>

<p>
	بعد تطبيق هذا المثال، سنحصل على نتيجة مُشابهة للصّورة التّاليّة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23337" href="https://academy.hsoub.com/uploads/monthly_2017_05/1n4sHZ2.png.43ee5d512d8691aa29c8ec6c77d59bd5.png" rel=""><img alt="1n4sHZ2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23337" data-unique="3hl3nnd5d" src="https://academy.hsoub.com/uploads/monthly_2017_05/1n4sHZ2.thumb.png.48a2fd57d7cbc05b4b4e06e8de4cd6ef.png"></a>
</p>

<p>
	 
</p>

<h2 id="ختاما">
	ختاماً
</h2>

<p>
	تعرّفنا في هذا الدّرس على جزء آخر من أساسيّات مُحرّك القوالب Jinja، يُمكنك الآن استخدام كلّ من الدّالة <code>range</code> والدّالة <code>lipsum</code> لتطوير تطبيقات أفضل واختصار الكثير من الوقت عند العمل مع إطار العمل Flask، إضافة إلى أنّك ستستطيع استخدامها مع تطبيق إدارة المُحتوى “كلمة” والذي سنُكمل تطويره بعد إنهاء أساسيّات مُحرّك القوالب Jinja.
</p>
]]></description><guid isPermaLink="false">488</guid><pubDate>Tue, 23 May 2017 06:48:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631; Jinja &#x62E;&#x627;&#x635; &#x644;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644;&#x647; &#x641;&#x64A; &#x62A;&#x637;&#x648;&#x64A;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-jinja-%D8%AE%D8%A7%D8%B5-%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D9%87-%D9%81%D9%8A-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-r486/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.5ac2582096a2943cfa89dcbd8ab19ecc.png" /></p>

<h2 id="مقدمة">
	مُقدّمة
</h2>

<p>
	بعد أن تعرّفنا على <a href="https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-r478/" rel="">ماهية ميّزة الاختبارات في مُحرّك القوالب Jinja</a>، وتعرّفنا على <a href="https://academy.hsoub.com/programming/python/flask/%D8%A8%D8%B9%D8%B6-%D9%85%D9%86-%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%AA%D9%88%D9%81%D9%91%D8%B1%D8%A9-%D9%81%D9%8A-%D9%85%D9%8F%D8%AD%D8%B1%D9%91%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-r482/" rel="">بعض من أهمّ الاختبارات المبنيّة مُسبقا في Jinja</a> والتّي يُمكنك استعمالها مُباشرة لتطوير قوالبHTML الخاصّة بك، قد لا تجد ما يسدّ حاجتك في الاختبارات التّي درسناها، وكما فعلنا مع <a href="https://academy.hsoub.com/programming/python/flask/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-jinja-%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r451/" rel="">المُرشّحات</a>، يُمكننا سدّ هذه الحاجة بإنشاء اختبارات خاصّة بنا لاختبار القيم والتّحقق ممّا إذا كانت تتّبع نمطا مُعيّنا أو لا.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23281" data-unique="5l6nbcz9r" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.6ad515acdd8f83fad5f951a7f0548168.png"></p>

<h2 id="مبدأ-اختبارات-jinja-المخصصة-في-إطار-العمل-flask">
	مبدأ اختبارات Jinja المُخصّصة في إطار العمل Flask
</h2>

<p>
	قبل الانتقال إلى أمثلة تطبيقيّة حول كيفيّة إنشاء اختبارات خاصّة بك لاستعمالها في قوالب Jinja مع إطار العمل Flask، سنتعرّف أولا على الشّكل المبدئي للاختبار.
</p>

<p>
	كما استعملنا المُزخرف <code>template_filter</code> لإنشاء مُرشّحات خاصّة بنا، فإنّنا نستعمل مُزخرفا آخر لإنشاء اختبار مُخصّص، إذ نستعمل المُزخرف <code>template_test</code> مع كائن التّطبيق <code>app</code> لتمكين جميع القوالب من استخدام الاختبار.
</p>

<p>
	شيفرة اختبار بسيط هي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<span class="lit">@app</span><span class="pun">.</span><span class="pln">template_test</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'test_name'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> test_name_function</span><span class="pun">(</span><span class="pln">value</span><span class="pun">):</span><span class="pln"> 
    </span><span class="com"># Test value</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">True</span></pre>

<p>
	الشّيفرة شبيهة بشيفرة إنشاء مُرشّح مُخصّص، الفرق أنّنا نستعمل المُزخِرف <code>template_test</code> ونُمرّر اسم الاختبار إلى المُعامل <code>name</code>، ثمّ نمنح للدّالة المُزَخْرَفَةِ اسما مُعبّرا، الدّالة تستقبل قيمة افتراضيّة (القيمة المُختبَرَة) تتواجد داخل المُعامل <code>value</code>، داخل الدّالة ستقوم بإجراءات لاختبار القيمة <code>value</code> مكان التّعليق <code>Test value</code> ثمّ تُرجع إمّا القيمة المنطقيّة <code>True</code> أو القيمة المنطقيّة <code>False</code> حسب ما إذا اجتازت القيمة الاختبار أو لا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			إذا لم تُمرّر اسم الاختبار إلى المُعامل <code>name</code> في المُزخرف <code>template_test</code> فسيُعيّن اسم الدّالة إلى الاختبار افتراضيّا، ما يعني بأنّه إن كان اسم الدّالة <code>test_name()</code> فاسم الاختبار سيكون هو نفسه <code>test_name</code> في حالة لم تُمرّر قيمة إلى المُعامل <code>name</code> عند استخدام المُزخرف <code>template_test</code>.
		</p>
	</div>
</blockquote>

<p>
	طريقة استعمال الاختبار الذي تقوم بإنشائه هي نفسُها طريقة استعمال الاختبارات المبنيّة مُسبقا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs vhdl"><span class="hljs-keyword"><span class="pln">variable</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> test_name</span></code></pre>

<p>
	لاحظ بأنّ الاختبار يجب أن يُرجع قيمة منطقيّة، ولتبسيط الأمور، فالمثال يُرجع دائما القيمة المنطقيّة <code>True</code>.
</p>

<h2 id="مثال-على-اختبار-للتحقق-من-أن-طول-قيمة-ما-لا-يتجاوز-حدا-معينا">
	مثال على اختبار للتّحقق من أنّ طول قيمة ما لا يتجاوز حدا مُعيّنا
</h2>

<p>
	في هذا المثال سنقوم بإنشاء اختبار للتّحقق ممّا إذا كانت سلسلة نصيّة مُعيّنة أكبر من 30 محرفا، الأمر الذي سيضمن لنا تنسيقا أفضل للصّفحات، فمثلا، لنقل بأنّك ترغب بأن تكون عناوين المقالات في تطبيقك قصيرة، ولنقل بأنّك لا ترغب في عرض أي عنوان تزيد عدد أحرفه عن الثّلاثين حرفا لسبب أو لآخر.
</p>

<p>
	المثال التّالي يُوضّح كيفيّة إنشاء اختبار Jinja مُخصّص للتّحقّق من أنّ قيمة مُعيّنة أكبر من 30 محرفا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs python"><span class="hljs-decorator"><span class="lit">@app</span><span class="pun">.</span><span class="pln">template_test</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'long'</span><span class="pun">)</span></span><span class="pln">
</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">is_long_test</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    is_long </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-number"><span class="lit">30</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> is_long </span><span class="hljs-comment"><span class="com"># True if value is more than 30 characters long</span></span></code></pre>

<p>
	نقوم أولا باستخدام المُزخرف <code>app.template_test</code> مع تمرير الاسم <code>long</code> إلى المعامل <code>name</code> وبالتالي سنتمكّن من استعمال الاختبار بالاسم <code>long</code>، في الدّالة المُزخرفة <code>is_long_test</code> نقوم بإنشاء مُتغيّر <code>is_long</code> يحمل إحدى القيمتين <code>True</code> أو <code>False</code> حسب ما إذا كان عدد أحرف السّلسلة النّصيّة <code>value</code> المُمرّرة افتراضيّا إلى الاختبار أكبر من 30 أو لا، للتّحقق ممّا إذا كانت كذلك، نستعمل المُعامل <code>&gt;</code> (أكبر من) للمُقارنة بين طول القيمة <code>value</code> الذي نحصل عليه باستخدام الدّالة <code>len</code> والقيمة 30، في الأخير نُرجع قيمة المُتغيّر <code>is_long</code>.
</p>

<p>
	بعد إنشاء الاختبار في الملفّ <code>project/__init__.py</code> ستتمكّن من اختباره كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="str">'</span><span class="hljs-variable"><span class="str">Building</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">A</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Web</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Application</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Using</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">The</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Flask</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Framework</span></span><span class="str">'</span><span class="pln"> </span><span class="hljs-variable"><span class="kwd">is</span></span><span class="pln"> </span><span class="hljs-variable"><span class="kwd">long</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">br</span></span><span class="str">&gt;</span></span><span class="pln">
</span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="str">'</span><span class="hljs-variable"><span class="str">An</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Introduction</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">To</span></span><span class="str"> </span><span class="hljs-variable"><span class="str">Flask</span></span><span class="str">'</span><span class="pln"> </span><span class="hljs-variable"><span class="kwd">is</span></span><span class="pln"> </span><span class="hljs-variable"><span class="kwd">long</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs mathematica"><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">False</span></span></code></pre>

<p>
	في المثال اختبرنا قيمتين، الأولى عدد عناصرها أكبر من 30 محرفا، والقيمة الثّانية عبارة عن عنوان قصير لا يتعدّى الطّول الأقصى، لذا فمن الطّبيعي أن تكون نتيجة الاختبار الأول القيمة <code>True</code> لأنّ العنوان طويل بالفعل، ونتيجة اختبار القيمة الثّانية هي القيمة <code>False</code> لأنّ العنوان أقصر من الثّلاثين حرفا.
</p>

<p>
	يُمكنك كذلك ترك تحديد أكبر قيمة للمُطوّر عبر جعلها مُعاملا كما هو مُوضّح في المثال التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs python"><span class="hljs-decorator"><span class="lit">@app</span><span class="pun">.</span><span class="pln">template_test</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'longer_than'</span><span class="pun">)</span></span><span class="pln">
</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">is_long_test</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> number_of_characters</span><span class="pun">=</span><span class="hljs-number"><span class="lit">30</span></span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    is_long </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> number_of_characters
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> is_long</span></code></pre>

<p>
	في هذا المثال أنشأنا اختبارا باسم <code>longer_than</code>، الدّالة المسؤولة عن الاختبار تقبل مُعاملا واحدا بالإضافة إلى القيمة <code>value</code> التّي تُمرّر افتراضيّا والتّي تُعتبر القيمة التّي تُختبر، بالنّسبة للمُعامل فقد سمّيناه <code>number_of_characters</code> لأنّه يُمثّل عدد المحارف الذي سنعتبره الحد الأقصى لسلسلة نصيّة، افتراضيّا قيمة المُعامل <code>number_of_characters</code> هي 30، ما يعني بأنّ الاختبار سيعمل بنفس طريقة عمل الاختبار <code>long</code> في المثال السّابق إذا لم تُوفّر قيمة للمُعامل.
</p>

<p>
	داخل الدّالة، الأمر مُشابه لطريقة عمل الاختبار <code>long</code>، لكن عوضا عن مُقارنة طول قيمة المُعامل <code>value</code> مع العدد 30، أصبحنا نُقارن الطّول مع قيمة المُعامل <code>number_of_characters</code> الذي نحصل عليه من مُستخدم الاختبار.
</p>

<p>
	هكذا سيكون لدينا اختبار يسمح لنا بالتّحقق ممّا إذا كانت سلسلة نصّيّة ما أطول من عدد مُعيّن أو لا، عوضا عن التّحقق ممّا إن كانت أطول من العدد 30 فقط.
</p>

<p>
	المثال التّالي توضيح لكيفيّة استخدام الاختبار <code>longer_than</code> الذي أنشأناه للتوّ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'An Introduction To Flask'</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> title </span><span class="kwd">is</span><span class="pln"> longer_than </span><span class="lit">40</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span><span class="str">'Title is too long'</span><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">

    </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> title </span><span class="pun">}}</span></span><span class="xml"><span class="pln">

</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	في هذا المثال، نُعرّف مُتغيّرا <code>title</code> ونمنحه سلسلة نصيّة قصيرة، بعدها نختبر هذا المُتغيّر باستعمال الجملة الشّرطيّة <code>if</code> والاختبار <code>longer_than</code>، نتأكّد في الاختبار من أنّ السّلسلة النّصيّة المتواجدة بالمُتغيّر <code>title</code> أطول من 40 محرفا، إن كانت كذلك فإنّنا نعرض الرّسالة <code>'Title is too long'</code>، وإن لم تكن كذلك فإنّنا نعرضها على صفحة HTML بشكل طبيعي.
</p>

<p>
	بما أنّ العنوان غير طويل، فالنّتيجة ستكون عرض العنوان في الصّفحة وليس العكس:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs vbnet"><span class="typ">An</span><span class="pln"> </span><span class="typ">Introduction</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">To</span></span><span class="pln"> </span><span class="typ">Flask</span></code></pre>

<p>
	لاختبار العكس استبدل سطر تعريف المُتغيّر <code>title</code> بما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs bash"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Building A Web Application Using The Flask Framework'</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	في هذه الحالة، العنوان أطول من 40 محرفا، لذا فالنّتيجة ستكون الجملة <code>'Title is too long'</code>.
</p>

<h2 id="مثال-على-اختبار-للتحقق-مما-إذا-كانت-سلسلة-نصية-ما-تنتهي-بمقطع-معين">
	مثال على اختبار للتّحقق ممّا إذا كانت سلسلة نصيّة ما تنتهي بمقطع مُعيّن
</h2>

<p>
	في لغة بايثون، يُمكننا التّحقق من أنّ سلسلة نصيّة تنتهي بمقطع ما باستعمال التّابع <code>endswith</code> مع تمرير المقطع كمُعامل.
</p>

<p>
	مثال على كيفيّة استخدام التّابع <code>endswith</code> داخل مُفسّر لغة بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs python"><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="hljs-string"><span class="str">'An Introduction To Flask'</span></span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Flask'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pln">
</span><span class="hljs-prompt"><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span></span><span class="hljs-string"><span class="str">'An Introduction To Flask'</span></span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Python'</span></span><span class="pun">)</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">False</span></span></code></pre>

<p>
	المُهمّة هي إنشاء اختبار Jinja للحصول على نفس النّتيجة، بحيث سيكون لدينا اختبار باسم <code>endswith</code> ويقبل مُعاملا واحدا، ألا وهو المقطع الذي سنتحقّق ممّا إذا كان مُتواجدا بنهاية السّلسلة المُختَبَرَةِ أو لا.
</p>

<p>
	ما يلي مثال على كيفيّة إنشاء الاختبار <code>endswith</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs python"><span class="hljs-decorator"><span class="lit">@app</span><span class="pun">.</span><span class="pln">template_test</span><span class="pun">(</span><span class="pln">name</span><span class="pun">=</span><span class="str">'endswith'</span><span class="pun">)</span></span><span class="pln">
</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">endswith_test</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">end</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> value</span><span class="pun">.</span><span class="pln">endswith</span><span class="pun">(</span><span class="kwd">end</span><span class="pun">)</span></code></pre>

<p>
	الاختبار بسيط جدّا، إذ كل ما نقوم به هو استعمال التّابع <code>endswith</code> على القيمة <code>value</code> مع تمرير قيمة المُعامل <code>end</code> التّي تُعتبر المقطع الذي نرغب بالتّحقق من أنّ السّلسلة تنتهي به، وبما أنّ نتيجة استعمال التّابع ستكون إمّا القيمة <code>True</code> أو القيمة <code>False</code>، فالاختبار سيعمل دون مشاكل، لأنّ شرط اختبار أن تُرجع إحدى القيمتين.
</p>

<p>
	المثال التّالي توضيح لكيفيّة استعمال الاختبار <code>endswith</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs applescript"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Building A Web Application Using Flask'</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> title </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> endswith</span><span class="pun">(</span><span class="str">'Flask'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

    </span><span class="str">'Title </span><span class="hljs-keyword"><span class="str">ends with</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">the</span></span><span class="str"> </span><span class="hljs-property"><span class="str">word</span></span><span class="str"> Flask'</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

    </span><span class="str">'Title </span><span class="hljs-keyword"><span class="str">does</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">not</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">end</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">with</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">the</span></span><span class="str"> </span><span class="hljs-property"><span class="str">word</span></span><span class="str"> Flask'</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span></code></pre>

<p>
	في المثال، نقوم بالتّعريف الاعتيادي للمُتغيّر <code>title</code>، مع تعيين عنوان ينتهي بالكلمة <code>Flask</code>، بعدها نستعمل الاختبار للتّحقق ممّا إذا كان المُتغيّر <code>title</code> ينتهي بالمقطع <code>Flask</code> أو لا، فإن كان كذلك فإنّنا نعرض الرّسالة <code>'Title ends with the word Flask'</code> وإن لم يكن كذلك فالرّسالة تُصبح <code>'Title does not end with the word Flask'</code>.
</p>

<p>
	وبما أنّ العنوان ينتهي بالمقطع <code>Flask</code> فالنّتيجة هي الحالة الأولى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5083_7" style="">
<code class="hljs applescript"><span class="str">'Title </span><span class="hljs-keyword"><span class="str">ends with</span></span><span class="str"> </span><span class="hljs-keyword"><span class="str">the</span></span><span class="str"> </span><span class="hljs-property"><span class="str">word</span></span><span class="str"> Flask'</span></code></pre>

<p>
	لاختبار الحالة الثّانية، غيّر سطر تعريف المُتغيّر <code>title</code> إلى جملة لا تنتهي بالمقطع <code>Flask</code>.
</p>

<h2 id="خاتمة">
	خاتمة
</h2>

<p>
	بنهاية هذا الدّرس، يجب أن تكون قادرا على كتابة واستخدام اختباراتك الخاصّة عند العمل مع كل من مُحرّك القوالب Jinja وإطار العمل Flask، في الدّروس القادمة، سنُكمل التّعرف على أساسيات مُحرّك القوالب لتتمكّن من تطوير تطبيقات Flask أفضل.
</p>
]]></description><guid isPermaLink="false">486</guid><pubDate>Fri, 19 May 2017 12:37:11 +0000</pubDate></item></channel></rss>
