<?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/3/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Flask</description><language>ar</language><item><title>&#x628;&#x639;&#x636; &#x645;&#x646; &#x623;&#x647;&#x645; &#x627;&#x644;&#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x64F;&#x62A;&#x648;&#x641;&#x651;&#x631;&#x629; &#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%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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.916498e6d5bfe1c9d82d54f6f7d082b2.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23189" data-unique="ybq8jx34a" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.736249f2956a608620c413a4164eaa33.png" alt="main.png"></p>

<h3 id="الاختبار-iterable">
	الاختبار iterable
</h3>

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

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

<p>
	المثال التّالي توضيح لكيفيّة استعمال الاختبار <code>Iterable</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<span class="pun">{%</span><span class="pln"> set variable </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ABCD'</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"> variable </span><span class="kwd">is</span><span class="pln"> iterable </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"> item </span><span class="kwd">in</span><span class="pln"> variable </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"> item </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><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">لا</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"> endif </span><span class="pun">%}</span></pre>

<p>
	المثال بسيط وواضح، إذ نقوم بتعريف المُتغيّر <code>variable</code> ونتحقّق من أنّه من النّوع <code>Iterable</code> عن طريق كل من الجملة الشّرطيّة <code>if</code> والاختبار <code>iterable</code>، إذا كانت قيمة المُتغيّر قابلة للدّوران عليها، فإنّنا نقوم باستعمال الحلقة <code>for</code> للوصول إلى كل عنصر وعرضه على شكل عنصر من قائمة HTML، أمّا إن لم تجتز قيمة المُتغيّر الاختبار فإنّنا نعرض الجملة “لا يُمكنك الدّوران حول قيمة المُتغيّر”.
</p>

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

<p>
	لنتأكّد من أنّ المثال يعمل في كلتا الحالتين، غيّر السّطر الأول إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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">variable</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	في هذه الحالة، قيمة المُتغيّر هي العدد الصّحيح 100، والأعداد الصّحيحة نوع لا يُمكن أن تدور حوله (إلّا إذا ما حوّلته إلى سلسلة نصيّة)، لذا فالنّتيجة هذه المرّة ستكون الجملة “لا يُمكنك الدّوران حول قيمة المُتغيّر ”.
</p>

<h3 id="الاختبار-lower">
	الاختبار lower
</h3>

<p>
	عند التّعامل مع الأحرف اللاتينيّة، قد ترغب بالتّحقق من أنّ قيمة مُتغيّر عبارة عن أحرف صغيرة (Lowercase)، وهذا بالضّبط ما يُمكنك فعله بالاختبار <code>lower</code>.
</p>

<p>
	المثال التّالي يُوضّح طريقة عمل الاختبار <code>lower</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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-keyword"><span class="pln">words</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">'ORM'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'walk'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'run'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>'</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-built_in"><span class="pln">word</span></span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">in</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">words</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-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">word</span></span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">lower</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="pln">word</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-keyword"><span class="kwd">else</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="pln">word</span></span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="hljs-operator"><span class="pln">an</span></span><span class="pln"> acronym</span><span class="pun">.</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
    </span><span class="str">&lt;br&gt;</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endfor </span><span class="pun">%}</span></code></pre>

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

<p>
	نتيجة المثال أعلاه ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<code class="hljs applescript"><span class="pln">ORM </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> an acronym</span><span class="pun">.</span><span class="pln">
walk 
</span><span class="hljs-command"><span class="pln">run</span></span><span class="pln"> 
<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> an acronym</span><span class="pun">.</span></code></pre>

<h3 id="الاختبار-upper">
	الاختبار upper
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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-keyword"><span class="pln">words</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">'ORM'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'walk'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'run'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>'</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-built_in"><span class="pln">word</span></span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">in</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">words</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-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">word</span></span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">upper</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="pln">word</span></span><span class="pln"> </span><span class="pun">}}</span><span class="pln">
        </span><span class="str">&lt;br&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></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<code class="hljs "><span class="pln">ORM 
<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr></span></code></pre>

<h3 id="الاختبار-undefined">
	الاختبار undefined
</h3>

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

<h3 id="الاختبار-none">
	الاختبار none
</h3>

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

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

<p>
	المثال التّالي يُوضّح استعمال الاختبار <code>none</code> مع جملة شرطيّة لعرض رسالة تنبيه في حالة كانت قيمة العنصر فارغة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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"> list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="kwd">None</span><span class="pun">,</span><span class="pln"> </span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">None</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></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">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"> item </span><span class="kwd">is</span><span class="pln"> none </span><span class="pun">%}</span></span><span class="xml"><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="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-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"> item </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-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>
	في المثال أعلاه، مزجنا بين السّلاسل النّصيّة والقيمة <code>None</code> في عناصر القائمة <code>list</code>، بعدها نقوم بالدّوران حول القائمة بحلقة <code>for</code>، ثمّ بعد ذلك نتحقّق ممّا إذا العنصر الحالي عبارة عن قيمة فارغة، فإن كان الأمر كذلك فإنّنا نعرض الرّسالة “قيمة العنصر فارغة”، أمّا إن لم يكن العنصر فارغا فإنّنا نعرضه.
</p>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<code class="hljs "><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="typ">One</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="typ">Two</span><span class="pln"> </span></code></pre>

<h3 id="الاختبار-number">
	الاختبار number
</h3>

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

<p>
	المثال التّالي توضيح على كيفيّة استخدام الاختبار <code>number</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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"> list </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="str">'Flask'</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">3.2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.001</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">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"> item </span><span class="kwd">is</span><span class="pln"> number </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="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="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-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"> item </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">ليس</span><span class="pln"> </span><span class="pun">بعدد</span><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-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>
	في هذا المثال، نقوم بتعريف قائمة تحتوي على أعداد وسلاسل نصيّة، ندور حول القائمة باستعمال حلقة <code>for</code> ثمّ نستعمل الاختبار <code>number</code> للتّحقّق ممّا إذا كان العنصر عددا أو لا، فإن كان عددا فإنّنا نعرض رسالة تُفيد بأنّ العنصر عبارة عن عدد بالفعل، أمّا إن لم يكن العنصر كذلك فإنّنا نعرض رسالة مفادها بأنّ القيمة ليست بعدد.
</p>

<p>
	نتيجة المثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<code class="hljs "><span class="lit">1</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="typ">Flask</span><span class="pln"> </span><span class="pun">ليس</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="pun">عن</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="pun">عن</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln">
</span><span class="lit">3.2</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="lit">0.001</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></code></pre>

<p>
	لاحظ في النّتيجة بأنّ الأعداد العشريّة تجتاز الاختبار كذلك.
</p>

<h3 id="الاختبار-string">
	الاختبار string
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_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"> list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Flask'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2017</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">None</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">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"> item </span><span class="kwd">is</span><span class="pln"> number </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="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="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-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">elif</span></span><span class="pln"> item </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><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> item </span><span class="pun">}}</span></span><span class="xml"><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="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-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"> item </span><span class="pun">}}</span></span><span class="xml"><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="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-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>
	في المثال أعلاه، نقوم بإنشاء قائمة ثمّ ندور عليها كالعادة، نختبر ما إذا كان كل عنصر عبارة عن عدد بالاختبار <code>number</code> لعرض رسالة تُفيد بذلك، إذا لم تكن القيمة عددا فإنّنا نستعمل الاختبار <code>string</code> لنرى إذا ما كانت القيمة سلسلة نصيّة لنعرض رسالة مفادها أنّ القيمة سلسلة نصيّة بالفعل، إذا لم تكن القيمة لا عددا ولا سلسلة نصيّة فإنّنا نعرض الجملة “ليس بعدد وليس سلسلة نصيّة ”.
</p>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5736_7" style="">
<code class="hljs mathematica"><span class="typ">Flask</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="hljs-number"><span class="lit">2017</span></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="hljs-keyword"><span class="kwd">None</span></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></code></pre>

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

<p>
	هكذا نكون قد تعرّفنا على ماهيّة الاختبارات في مُحرّك القوالب Jinja، وألقينا نظرة إلى بعض من أهمّ الاختبارات المبنيّة مُسبقا وعلى كيفيّة استخدامها في تطبيقات Flask أو أي مشروع بايثون آخر يعتمد على Jinja، سننتقل في الدّرس القادم إلى كيفيّة إنشاء اختبارات خاصّة بنا لاستعمالها في حالة لم تجد اختبارا يُلبي حاجتك في قائمة الاختبارات المبنيّة مُسبقا.
</p>
]]></description><guid isPermaLink="false">482</guid><pubDate>Thu, 11 May 2017 16:07:44 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631;&#x627;&#x62A; &#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%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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.1f43b0652f8cf41f797b7619368f1b21.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23190" data-unique="6m6c8nay4" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.12c440be68ad3a85d071afb2adea5574.png" alt="main.png"></p>

<h2 id="ما-معنى-اختبارات-jinja">
	ما معنى اختبارات Jinja
</h2>

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

<p>
	طريقة إجراء الاختبارات هي باستعمال الكلمة المفتاحيّة <code>is</code> عوضا عن الرّمز <code>|</code> الذي يُستعمل لتطبيق مُرشّح مُعيّن.
</p>

<p>
	على سبيل المثال، يُمكنك التّحقق ممّا إذا كان مُتغيّر مُعرّفا أو لا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<span class="pln">name </span><span class="kwd">is</span><span class="pln"> defined</span></pre>

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

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<code class="hljs cs"><span class="hljs-number"><span class="lit">9</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> divisibleby</span><span class="pun">(</span><span class="hljs-number"><span class="lit">3</span></span><span class="pun">)</span></code></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<code class="hljs cs"><span class="hljs-number"><span class="lit">9</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> divisibleby </span><span class="hljs-number"><span class="lit">3</span></span></code></pre>

<p>
	نتيجة الاختبار ستكون إمّا القيمة المنطقيّة <code>True</code> أو القيمة المنطقيّة <code>False</code>، ما يعني بأنّك تستطيع الاستفادة من نتيجة الاختبار باستعمالها مع الجمل الشّرطية <code>if</code> و <code>else</code> و <code>elif</code>.
</p>

<p>
	لتفهم هذا الدّرس أكثر، يُمكنك استعمال ملفّ <code>filters.html</code> الذي أنشأناه سابقا لتطبيق الأمثلة وتجربة أفكارك إذا ما شئت، إذ يُمكنك تفعيل البيئة الوهميّة وتعريف مُتغيّرات البيئة ومن ثمّ تشغيل الخادوم المحلي لتطبيق “كلمة” عبر كتابة الأمر <code>flask run</code> في سطر الأوامر، وبعدها كتابة المثال التّالي في ملفّ <code>filters.html</code> وزيارة العنوان <a href="http://127.0.0.1:5000/filters" rel="external nofollow">http://127.0.0.1:5000/filters</a> لتُلاحظ نتيجة تطبيق الاختبار <code>divisibleby</code> مع أعداد مُختلفة.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="lit">10</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="pln">divisibleby</span></span><span class="pln"> </span><span class="lit">2</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="lit">4</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="pln">divisibleby</span></span><span class="pln"> </span><span class="lit">3</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="lit">9</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="pln">divisibleby</span></span><span class="pln"> </span><span class="lit">2</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="lit">60</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="pln">divisibleby</span></span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span></span></code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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><span class="pln"> 
</span><span class="hljs-keyword"><span class="kwd">False</span></span><span class="pln"> 
</span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pln"> </span></code></pre>

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

<h2 id="ما-الغرض-من-استعمال-الاختبارات">
	ما الغرض من استعمال الاختبارات؟
</h2>

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

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

<h2 id="قائمة-ببعض-من-أهم-اختبارات-محرك-القوالب-jinja">
	قائمة ببعض من أهم اختبارات مُحرّك القوالب Jinja
</h2>

<p>
	الآن وقد تعرّفنا على ماهيّة الاختبارات في مُحرّك القوالب Jinja، حان الوقت للتّعرف على أهمّ الاختبارات المبنيّة مُسبقا في Jinja والتّي يُمكنك استخدامها مُباشرة.
</p>

<h3 id="الاختبار-defined">
	الاختبار <code>defined</code>
</h3>

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

<p>
	يُمكنك استخدام المثال التّالي لتفهم أكثر الغرض من الاختبار <code>defined</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> variable </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">defined</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </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"> variable </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">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><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><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></code></pre>

<p>
	المثال أعلاه يتحقّق ممّا إذا كان المُتغيّر <code>variable</code> مُعرّفا أو لا، إذا كان مُعرّفا فالنّتيجة ستكون الجملة “قيمة المُتغيّر: ” بالإضافة إلى قيمة المُتغيّر، أمّا إذا لم يكن المُتغيّر مُعرّفا فالنّتيجة ستكون الجملة “المُتغيّر غير مُعرّف”.
</p>

<p>
	إذا قُمت بتجربة المثال في ملفّ <code>filters.html</code> فستحصل على النّتيجة الثّانيّة، ولتغيير الوضع يُمكنك تعريف المُتغيّر فوق جملة <code>if</code> الشّرطية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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">variable</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'مرحبا بالعالم!'</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	بعد تعريف المُتغيّر ستجد بأنّ النّتيجة أصبحت الجملة “قيمة المُتغيّر: مرحبا بالعالم! ” عوضا عمّا سبق.
</p>

<h3 id="الاختبار-callable">
	الاختبار <code>callable</code>
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> macro say_hello</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="pun">مرحبا</span><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"> endmacro </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"> say_hello </span><span class="kwd">is</span><span class="pln"> callable </span><span class="pun">%}</span></span><span class="xml"><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="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-variable"><span class="pun">{{</span><span class="pln"> say_hello</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">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><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><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>callable</code> على الماكرو، والنّتيجة هي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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="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="hljs-exclamation_mark"><span class="pun">!</span></span><span class="pln"> </span></code></pre>

<p>
	ما يعني بأنّ الماكرو قابل للاستدعاء، ولو لم يكن كذلك لكانت النّتيجة هي الجملة “لا يُمكن استدعاء الكائن”.
</p>

<p>
	يُمكنك اختبار الحالة الأخرى (عدم قابليّة استدعاء الكائن) عبر حذف الماكرو وتعريف المُتغيّر <code>say_hello</code> مكان الماكرو باستعمال السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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"> say_hello </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'مرحبا بالعالم!'</span></span><span class="pln"> </span><span class="pun">%}</span></code></pre>

<p>
	وبما أنّ مُتغيّرا عاديّا لا يُمكن استدعاؤه، فالنّتيجة ستكون الجملة “لا يُمكن استدعاء الكائن ”، وذلك لأنّ الاختبار <code>callable</code> يُرجع القيمة المنطقيّة <code>Flase</code> عند استعماله مع متغيّرات بايثون عاديّة أو خصائص الأصناف لأنّها غير قابلة للاستدعاء.
</p>

<h3 id="الاختباران-even-و-odd">
	الاختباران even و odd
</h3>

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

<p>
	أمّا الاختبار <code>odd</code> فيقوم بالعكس، إذ يُستعمل للتّحقق من أنّ عددا ما فردي أو لا.
</p>

<p>
	المثال التّالي توضيح لكيفيّة استخدام كل من <code>even</code> و <code>odd</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_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"> numbers </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><span class="pln"> </span><span class="lit">6</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">for</span></span><span class="pln"> number </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> numbers </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"> number </span><span class="kwd">is</span><span class="pln"> even </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"> number </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">زوجي</span><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-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">elif</span></span><span class="pln"> number </span><span class="kwd">is</span><span class="pln"> odd </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"> number </span><span class="pun">}}</span></span><span class="xml"><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">فردي</span><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-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>
	في المثال أعلاه، نُعرّف أولا قائمة أعداد ثمّ ندور حولها باستخدام حلقة <code>for</code>، في كل دورة نتحقّق ممّا إذا كان العدد زوجيّا لعرض رسالة تُفيد بأنّ العدد زوجي، وإن لم يكن العدد زوجيّا نتحقّق مّما إذا كان عددا فرديا لنعرض رسالة مضمونها أنّ العدد فردي.
</p>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3461_7" style="">
<code class="hljs "><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="pun">فردي</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="pun">زوجي</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="pun">فردي</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="pun">زوجي</span><span class="pln"> 
</span><span class="pun">العدد</span><span class="pln"> </span><span class="lit">5</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="lit">6</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">زوجي</span><span class="pln"> </span></code></pre>

<h3 id="ختاما">
	ختاما
</h3>

<p>
	تعرّفنا في هذا الدّرس على ماهيّة ميّزة الاختبارات في مُحرّك القوالب Jinja، وتعرّفنا على الغرض منها وكيفيّة استعمالها وعلى بعض الاختبارات المبنيّة مُسبقا، في الدّرس القادم، سنُكمل ما بدأناه بالتّعرف على المزيد من الاختبارات المتواجدة بمُحرّك القوالب Jinja والتّي ستُساعدك على تطوير تطبيقات ويب أفضل كما ستُفيدك في فهم وتطوير تطبيق “كلمة”.
</p>
]]></description><guid isPermaLink="false">478</guid><pubDate>Fri, 05 May 2017 21:03:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A; Jinja &#x62E;&#x627;&#x635;&#x629; &#x628;&#x643; &#x644;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645;&#x647;&#x627; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.74afd42feab098ebb27abf54ff4800f0.png" /></p>

<h2>
	مُقدّمة
</h2>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23191" data-unique="jyeodd9lr" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.4181ad5b7225aff46f828795b1c49bb0.png" alt="main2.png"></p>

<h2>
	إنشاء مُرشّحات خاصّة بك
</h2>

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

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

<p>
	بمعنى آخر، إن أنشأت مُرشّحا في المُخطّط الخاصّة بالمُستخدمين فلن تستطيع استخدامه سوى على قوالب HTML المتواجدة بمُجلّد <code>templates</code> في المسار <code>project/users</code>. والمُرشّحات التّي تُنشأ في المخطّط الخاصّ بالمقالات لن تستطيع استخدامها سوى مع القوالب الخاصّة بالمقالات، أمّا إن أردت إنشاء مُرشّحات للوصول إليها بشكل عام في كل التّطبيق بحيث تتمكّن جميع قوالب HTML من الوصول إلى المُرشّح واستخدامه فسيتوجّب عليك إنشاؤه باستعمال الكائن <code>app</code> الذي يتواجد في ملفّ <code>__init__.py</code> داخل مُجلّد المشروع <code>project</code> أي المسار <code>project/__init__.py</code> .
</p>

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

<h2>
	كيف يعمل المُرشّح
</h2>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
@app.template_filter('filter_name')
def filter_name_function(value): 
        return value
</code></pre>

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

<p>
	لاستخدام المُرشّح سيتوجّب عليك استخدام اسمه الذي خصّصته ما بين قوسين (أي الاسم <code>filter_name</code> في المثال أعلاه)، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{{ value | filter_name() }}
</code></pre>

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

<p>
	لتفهم أهميّة السّطر <code>return</code>، جرّب تغييره إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
@app.template_filter('filter_name')
def filter_name_function(value): 
        return 'Hello World!'
</code></pre>

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

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

<h2>
	أمثلة على إنشاء مُرشّحات وكيفيّة استعمالها
</h2>

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

<h3>
	كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الأول: مُرشّح ترجمة الكلمات
</h3>

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

<p>
	سيكون المُرشّح كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
@app.template_filter('translate')
def translate_filter(value): 
    english_to_arabic = {'Hello': u'مرحبا',
                         'Flask': u'فلاسك',
                         'Python': u'بايثون',
                         'Javascript': u'جافاسكربت',
                         'Academy': u'أكاديميّة'
                         }
    arabic_word = english_to_arabic[value]
    return arabic_word
</code></pre>

<p>
	ستُلاحظ أولا بأنّنا سمّينا المُرشّح بالاسم <code>translate</code> وهذا هو الاسم الذي سنستعمله إذا ما أردنا تطبيق المُرشّح في قوالب HTML، أمّا الدّالة فاسمها <code>translate_filter</code> وكما قلت سابقا، فاسم الدّالة لا يهم، لكن من المُفضّل أن يشرح الاسم هدف الدّالة. بعدها أنشأنا القاموس <code>english_to_arabic</code> ليحتوي على بضعة كلمات إنجليزيّة ونظيراتها باللغة العربيّة كمثال بسيط، وبالطّبع، ففي مثال واقعي، سيتوجّب عليك الحصول على الكلمات وترجماتها من قاعدة بيانات وليس من قاموس عادي. في السّطر ما قبل الأخير، نُعرّف المُتغيّر <code>arabic_word</code> لتحمل الكلمة العربيّة التي نحصل عليها من القاموس باستعمال القيمة <code>value</code> التّي تُمرّر إلى المُرشّح كمفتاح. أمّا في السّطر الأخير فإنّنا نقوم بإرجاع مُحتوى المُتغيّر <code>arabic_word</code>.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{{ 'Python' | translate }}
</code></pre>

<p>
	النّتيجة ستكون الكلمة "بايثون” لأنّها الكلمة التي تُعتبر قيمة للمفتاح <code>Python</code> في القاموس <code>english_to_arabic</code>.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{% set words = ['Flask', 'Python', 'Hello', 'Javascript', 'Academy'] %}
{% for word in words %}

    &lt;p&gt; {{ word }}: {{ word | translate }} &lt;/p&gt;

{% endfor %}


</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
Flask: فلاسك
Python: بايثون
Hello: مرحبا
Javascript: جافاسكربت
Academy: أكاديميّة
</code></pre>

<h3>
	كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الثّاني
</h3>

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

<p>
	إليك شيفرة المُرشّح:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
@app.template_filter('list_len')
def list_length_filter(value): 
    joined_list = "".join(value)
    length = len(joined_list)
    return length
</code></pre>

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

<p>
	المثال التّالي يُوضّح كيفيّة المُرشّح <code>list_len</code> الذي أنشأناه مع قائمة باسم <code>numbers</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{% set numbers = ['One', 'Two', 'Three'] %}


{{ numbers | list_len }}
</code></pre>

<p>
	النّتيجة ستكون العدد 11 وهو عدد أحرف الكلمات <code>One</code>، <code>Two</code> و <code>Three</code> مُجتمعة.
</p>

<p>
	مثال آخر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{% set words = ['Flask', 'Python', 'Hello', 'Javascript', 'Academy'] %}


{{ words | list_len }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
33
</code></pre>

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

<p>
	المثال التّالي يُوضّح كيفيّة الحصول على نفس النّتيجة باستعمال كل من <code>join</code> و <code>length</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
{{ words | join("") | length }}
</code></pre>

<h3>
	كيفيّة إنشاء مُرشّح Jinja خاص بك، المثال الثّالث
</h3>

<p>
	في هذا المثال، سنقوم بإنشاء مُرشّح لعرض صورة على المُتصفّح مُباشرة من رابطها، هذا يعني بأنّنا لن نحتاج إلى تمرير الرّابط كقيمة إلى الخاصيّة <code>src</code> في الوسم <code>&lt;img /&gt;</code>.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
image_link | image() | safe()
</code></pre>

<p>
	سيتوجّب علينا استخدام المُرشّح <code>safe</code> لأنّ نتيجة المُرشّح <code>image</code> ستكون عبارة عن شيفرة HTML، ولتمكين المُتصفّح من ترجمة هذه الشّيفرة، لا بد من استخدام المُرشّح <code>safe</code>.
</p>

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

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
image_link | image(width=200) | safe
</code></pre>

<p>
	بالإضافة إلى التّحكم بحجم الصّورة، سنُضيف كذلك إمكانيّة التّحكم بقيمة خاصيّة <code>border-radius</code> في لغة CSS لتحديد مدى استدارة حواف الصّورة.
</p>

<p>
	مع هذه الإضافة، المثال التّالي سيُنتج صورة بحجم 100 px وقيمة 5 px للخاصيّة <code>border-radius</code> أي أنّها ستكون مُستديرة الحواف قليلا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
image_link | image(width=200, radius=5)
</code></pre>

<p>
	بعد أن تعرّفنا على فكرة المُرشّح، لننتقل الآن إلى إنشائه.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
@app.template_filter('image')
def image_filter(value, width=500, radius=0):

    css_style = "'width: {}px; border-radius: {}px'".format(width, radius)
    html_code = '''
                &lt;img src={} style={} /&gt;
                '''.format(value, css_style)

    return html_code
</code></pre>

<p>
	هناك العديد من الأمور التّي قد لا تُفهم في هذا المُرشّح، لذا لا بد من شرح مُفصّل.
</p>

<p>
	أولا، نقوم بإنشاء مُرشّح باسم <code>image</code>، الدّالة المسؤولة تأخذ ثلاثة مُعاملات، القيمة الأولى تُعطى للمُعامل الأول، وهي عبارة عن القيمة التّي يأخذها المُرشّح أثناء استدعائه (أي ما يسبق الرّمز <code>|</code>) والتّي ستكون رابط أو مسار الصّورة المرغوب عرضها، المُعامل <code>width</code> عبارة عن المُعامل الذي يُحدّد حجم الصّورة، إذا لم يتوفّر حجم مُحدّد أثناء استدعاء المُرشّح فالحجم الافتراضي هو 500. بالنّسبة للمُعامل <code>radius</code> فسيكون المُعامل الذي يُحدّد مدى استدارة حواف الصّورة، والقيمة الافتراضية هي 0 أي أنّ الصورة ستظهر بشكل عادي دون استدارة للحواف إذا لم تتوفّر قيمة أكبر من 0 للمُعامل <code>radius</code> أثناء استخدام المُرشّح على رابط الصّورة لعرضها.
</p>

<p>
	نُعرّف المُتغيّر <code>css_style</code> داخل الدّالة ليحمل شيفرة لغة CSS لتعديل الصّورة حسب قيم كل من الحجم و مدى استدارة الحواف التّي نحصل عليها من المُتغيّرين <code>width</code> و <code>radius</code>. ستُلاحظ بأنّنا نستخدم التّابع <code>format</code> لدمج قيم المُتغيّرين داخل السّلسلة النّصيّة، بهذه الطّريقة ستكون القيمة الافتراضيّة للمُتغيّر <code>css_style</code> ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
'width: 500px; border-radius: 0px'
</code></pre>

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

<p>
	في شيفرة HTML، نقوم باستخدام الوسم <code>&lt;img&gt;</code> لعرض الصورة عبر تمرير رابط أو مسار الصّورة إلى الخاصيّة <code>src</code>، كما نقوم بتمرير شيفرة CSS التّي تتواجد داخل المُتغيّر <code>css_style</code> إلى الخاصيّة <code>style</code> لتنسيق الصّورة حسب الحجم ومدى استدارة الحواف بلغة CSS.
</p>

<p>
	في الأخير نقوم بإرجاع شيفرة HTML المُتواجدة داخل المُتغيّر <code>html_code</code> والتّي ستكون مسؤولة عن عرض الصّورة.
</p>

<h3>
	اختبار مُرشّح عرض الصّور
</h3>

<p>
	بعد الانتهاء من إنشاء المُرشّح <code>image</code> لعرض الصّور، يُمكنك اختباره كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
image_link | image(width=100) | safe
</code></pre>

<p>
	مع التّأكد من أنّ المُتغيّر <code>image_link</code> عبارة عن رابط مُباشر للصورة.
</p>

<p>
	يُمكنك مثلا تجربة المُرشّح مع صورة رمزيّة لأحد دروس إطار العمل Flask السّابقة عبر تجربة السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
'https://academy.hsoub.com/uploads/monthly_2016_05/flask-introduction.png.b896f4a662940d3b348b5b95f5eac86a.png' | image(width=100) | safe
</code></pre>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code>
&lt;center&gt;
&lt;h1&gt; إنشاء مُرشّحات Jinja خاصّة بك &lt;/h1&gt;
&lt;br&gt;

{{ 'https://academy.hsoub.com/uploads/monthly_2016_05/flask-introduction.png.b896f4a662940d3b348b5b95f5eac86a.png' | image(width=300, radius=20) | safe }}

&lt;/center&gt;
</code></pre>

<p>
	نتيجة المثال أعلاه ستكون مُشابهة لما يلي:
</p>

<p style="text-align: center;">
	<img alt="IbTVwUU.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22504" data-unique="8j42l1bdf" src="https://academy.hsoub.com/uploads/monthly_2017_04/IbTVwUU.png.74e963a16cf561cf7ab56f3f2172b5b8.png"></p>

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

<p>
	تعرّفنا في هذا الدّرس والدّروس السّابقة على كيفيّة استخدام مُرشّحات Jinja وكيفيّة إنشاء مُرشّحات خاصّة بك، لذا ستتمكّن الآن من استعمال ما تعلّمته لتطوير تطبيقات أكثر تعقيدا لتُلبي احتياجاتك وتُطبّق أفكارك بسهولة وطرق أحسن من ذي قبل. في الدّرس المُقبل، سنُنهي سلسلة الدّروس المُخصّصة لمُحرّك القوالب Jinja عبر التّعرف على مبدأ الاختبارات ومن ثمّ ننتقل إلى إكمال تطوير تطبيق "كلمة” في بقيّة الدّروس.
</p>
]]></description><guid isPermaLink="false">451</guid><pubDate>Sat, 15 Apr 2017 21:07:00 +0000</pubDate></item><item><title>&#x623;&#x647;&#x645; &#x627;&#x644;&#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62A;&#x648;&#x641;&#x631;&#x629; &#x628;&#x634;&#x643;&#x644; &#x642;&#x64A;&#x627;&#x633;&#x64A; &#x641;&#x64A; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja&#x60C; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x644;&#x62B;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D9%88%D9%81%D8%B1%D8%A9-%D8%A8%D8%B4%D9%83%D9%84-%D9%82%D9%8A%D8%A7%D8%B3%D9%8A-%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%D8%8C-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-r449/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.dd4633f6b6f9bb0e54a47b274571f1b7.png" /></p>

<h3>
	مُقدّمة
</h3>

<p>
	تعرّفنا في <a href="https://academy.hsoub.com/programming/python/flask/%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D9%88%D9%81%D8%B1%D8%A9-%D8%A8%D8%B4%D9%83%D9%84-%D9%82%D9%8A%D8%A7%D8%B3%D9%8A-%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r447/" rel="">الدّرس السّابق</a> على بعض من مُرشّحات مُحرّك القوالب Jinja، مثل المُرشّح length لحساب عدد عناصر مجموعة ما، والمُرشّح list لتحويل القيم إلى قائمة، والمُرشّح replace لتعويض قيمة من نص ما بقيمة أخرى، وكذلك المُرشّح reverse لعكس قيمة نصيّة أو مجموعة من القيم، وانتهينا بالتّعرف على المُرشّح safe لإعلام Jinja بأنّ القيمة عبارة عن شيفرة HTML آمنة، في هذا الدّرس سنُكمل ما بدأناه بالتّعرف على المزيد من المُرشّحات المهمّة لننتقل بعد ذلك إلى كيفيّة إنشاء مُرشّح خاص بك مع مجموعة من الأمثلة في درس مُقبل.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23192" data-unique="p1q1xvk72" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.e7927c0b9a5b2390d908a30fb78f0587.png" alt="main2.png"></p>

<h3>
	المُرشّح <code>sort</code> لترتيب قيمة قابلة للدّوران عليها
</h3>

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

<p>
	التّرتيب يكون من الأصغر إلى الأكبر بالنّسبة للأعداد، وبشكل أبجدي عند التّعامل مع السّلاسل النّصيّة.
</p>

<p>
	المثال التّالي يُوضّح كيفيّة ترتيب الأعداد من أصغر عدد إلى أكبر عدد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<span class="pun">{{</span><span class="pln"> </span><span class="str">"3241"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sort</span><span class="pun">}}</span></pre>

<p>
	ستُلاحظ بأنّ النتيجة عبارة عن قائمة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
['1', '2', '3', '4'] 
</pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
{{ "adbc" | sort}}
</pre>

<p>
	النّتيجة ستكون عبارة عن قائمة أيضا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['a', 'b', 'c', 'd'] 
</code></pre>

<p>
	وبما أنّ قائمة عاديّة عبارة عن Iterable كذلك، فيُمكنك استخدام المُرشّح <code>sort</code> مع القوائم بنفس الطّريقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ ['c', 'b', 'd', 'a'] | sort() }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['a', 'b', 'c', 'd']   
</code></pre>

<p>
	يُمكنك كذلك ترتيب كلمات كاملة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ ['Ali', 'Do', 'Flask', 'Ball'] | sort() }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['Ali', 'Ball', 'Do', 'Flask'] 
</code></pre>

<p>
	 
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ '41532dabec' | sort() }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['1', '2', '3', '4', '5', 'a', 'b', 'c', 'd', 'e']
</code></pre>

<p>
	 
</p>

<p>
	بعد بضعة تجارب، لاحظت بأنّ التّرتيب ممكن كذلك مع الكلمات العربيّة، ويُمكنك تجربة المثال التّالي لتتأكّد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ ['أب', 'جبل', 'ثلاثة', 'ترجم'] | sort() }}
</code></pre>

<p>
	النّتيجة ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['أب', 'ترجم', 'ثلاثة', 'جبل']
</code></pre>

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

<h3>
	المُرشّح <code>sum</code> للحصول على جمع أعداد من مجموعة من القيم
</h3>

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

<p>
	لنضرب مثالا لقائمة مُشتريات، كل عنصر يُمثّل سعر بضاعة ما، وسيتوجّب عليك عرض القيمة الإجماليّة لقائمة المُشتريات وذلك بجمع الأسعار. لنضع القائمة التّالية كمثال لأسعار ثلاثة سلع:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
[12, 14, 2]
</code></pre>

<p>
	للوصول إلى السّعر الإجمالي، سيتوجّب عليك جمع كل من 12 مع 14 ثمّ إضافة 2 للنّتيجة. وهذا بالضّبط ما يقوم به المُرشّح <code>sum</code>.
</p>

<p>
	إليك المثال التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{% set prices = [12, 14, 2]  %}

{{ prices | sum() }}

</code></pre>

<p>
	النّتيجة ستكون العدد 28 وهي نتيجة العمليّة الحسابيّة <code>12 + 14 + 2</code>.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
item.price
</code></pre>

<p>
	لذا فطريقة استعمال المُرشّح <code>sum</code> في هذه الحالة مُختلفة قليلا، إذ سيتوجّب عليك تمرير اسم الخاصيّة إلى المُعامل <code>attribute</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ items | sum(attribute='price') }}
</code></pre>

<p>
	المثال التّالي سيقوم بالدّوران حول عناصر المتغيّر <code>items</code> والوصول إلى سعر كل عنصر عبر الخاصيّة <code>price</code> ومن ثمّ جمعها للحصول على السّعر الإجمالي.
</p>

<p>
	 
</p>

<p>
	 
</p>

<h3>
	المُرشّح truncate لعرض جزء صغير من نص طويل
</h3>

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

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

<p>
	المثال التّالي يُوضّح كيفيّة استخدام المُرشّح مع نص طويل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "مقال طويل يحتاج إلى تقصيره وعرض جزء صغير منه فقط ليكون تنسيق الصّفحة التّي تعرض عناوين المقالات أحسن" | truncate(length=50) }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
مقال طويل يحتاج إلى تقصيره وعرض جزء صغير منه ... 
</code></pre>

<p>
	يُمكنك تغيير طول النّص النّاتج بتغيير قيمة المُعامل <code>length</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "مقال طويل يحتاج إلى تقصيره وعرض جزء صغير منه فقط ليكون تنسيق الصّفحة التّي تعرض عناوين المقالات أحسن" | truncate(length=25) }}
</code></pre>

<p>
	هنا غيّرنا قيمة المُعامل <code>length</code> وجعلناها <code>25</code> عوضا عن <code>50</code>، لذا فالنّتيجة ستكون هذه المرّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
مقال طويل يحتاج إلى ... 
</code></pre>

<h3>
	المُرشّح urlize لتحويل الروابط النّصيّة إلى روابط قابلة للضّغط عليها
</h3>

<p>
	 
</p>

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

<p>
	 
</p>

<p>
	لتفهم أكثر، جرّب المثال التّالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "https://academy.hsoub.com/" }}
</code></pre>

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

<p>
	الآن، حاول استعمال المُرشّح <code>urlize</code> مع النّص السّابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "https://academy.hsoub.com/" | urlize() }}
</code></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
&lt;a href="https://academy.hsoub.com/"&gt;https://academy.hsoub.com/&lt;/a&gt;
</code></pre>

<p>
	ويُمكنك كذلك تجاهل الجزء <code>http://</code> أو <code>https://</code> ووضع رابط عادي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "academy.hsoub.com" | urlize() }}
</code></pre>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ "https://academy.hsoub.com/tags/flask%20101/" | urlize(21) }}
</code></pre>

<p>
	النّتيجة ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
https://academy.hsoub... 
</code></pre>

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

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

<p>
	إليك المثال التّالي لتتوضّح الفكرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>

{{ " اضغط على الرّابط التّالي للوصول إلى سلسلة دروس إطار العمل فلاسك للمُبتدئين: https://academy.hsoub.com/tags/flask%20101/ أو تابع دروس بايثون عبر النّقر على الرّابط التّالي: https://academy.hsoub.com/programming/python/ " | urlize() }}
</code></pre>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
اضغط على الرّابط التّالي للوصول إلى سلسلة دروس إطار العمل فلاسك للمُبتدئين: https://academy.hsoub.com/tags... أو تابع دروس بايثون عبر النّقر على الرّابط التّالي: https://academy.hsoub.com/prog...
</code></pre>

<h3>
	المُرشّح wordcount لحساب عدد كلمات نص معيّن
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ 'واحد اثنان ثلاثة' | wordcount() }}
</code></pre>

<p>
	النّتيجة ستكون 3 لأنّ النّص أعلاه يحتوي على ثلاثة كلمات.
</p>

<h3>
	المُرشّح wordwrap لنسيق النّصوص الطّويلة.
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ text | wordwrap() }}
</code></pre>

<p>
	لكن رغم تطبيق المُرشّح على النّص فالنّتيجة لن تظهر إلّا عند تصفّحك لمصدر الصّفحة، وذلك لأنّ المُرشّح لا يُقسّم الأسطر باستعمال الوسم <code>&lt;br&gt;</code> افتراضيّا، بل يجب عليك أن تقوم بتحديد نوع التّقسيم الذي تُريده أولا عبر تمرير الفاصل إلى المُعامل <code>wrapstring</code>.
</p>

<p>
	لذا للفصل بين الأسطر باستعمال الوسم <code>&lt;br&gt;</code> سيتوجّب علينا أن نُمرّره أولا إلى المُعامل <code>wrapstring</code> ثمّ تطبيق المُرشّح <code>safe</code> لإعلام Jinja بأنّ شيفرة HTML بداخل النّص آمنة (مُجدّدا، تأكّد أولا من أنّ النّص آمن بالفعل قبل تطبيق هذا المُرشّح).
</p>

<p>
	 
</p>

<p>
	لذا فالمثال أعلاه سيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ text  |  wordwrap(wrapstring='&lt;br&gt;') | safe() }}
</code></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{{ text  |  wordwrap(width=20, wrapstring='&lt;br&gt;') | safe() }}
</code></pre>

<p>
	 
</p>

<p>
	 
</p>

<h3>
	المُرشّح select لعرض نتيجة حسب اختبار ما
</h3>

<p>
	الاختبارات Tests في مُحرّك القوالب Jinja طريقة أخرى لمُعالجة القيم، وسنتطرّق إليها بشكل مُفصّل لاحقا، ما يجب أن تعرفه الآن هو أنّ المُرشّح <code>select</code> يُمكّنك من تطبيق اختبار على مجموعة من القيم لتُعرَض العناصر التّي تجتاز الاختبار وتُتجاهل العناصر الأخرى.
</p>

<p>
	سنُلقي نظرة على عدّة أمثلة لتفهم الأمر.
</p>

<p>
	أولا، سنُطبّق الاختبار <code>odd</code> على قائمة أعداد لاختيار الأعداد الفرديّة منها.
</p>

<h3>
	المثال الأول:
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{% set numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9] %}
{{ numbers | select("odd") | list() }}
</code></pre>

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

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
[1, 3, 5, 7, 9]
</code></pre>

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

<h3>
	المثال الثّاني:
</h3>

<p>
	في المثال الثّاني سنستعمل الاختبار <code>string</code> الذي يتحقّق ما إذا كانت القيمة سلسلة نصيّة أو لا.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
{% set numbers = [1, 'Flask', 3, 42, 'Python', 'Hello World!', 2312, 2017, 'Jinja'] %}

{{ numbers | select("string") | list() }}
</code></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2337_7">
<code>
['Flask', 'Python', 'Hello World!', 'Jinja'] 
</code></pre>

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

<p>
	 
</p>

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

<p>
	تعرّفنا في الدّروس السّابقة وهذا الدّرس على كيفيّة التّعامل مع مُحرّك القوالب Jinja الذي يكون مُرفقا مع إطار العمل فلاسك، خاصّة كيفيّة العمل مع خاصيّة المُرشّحات والاستفادة منها، هذا الدّرس هو آخر درس يتحدّث عن المُرشّحات المبنيّة مُسبقا في Jinja ما يعني بأنّنا سنضطر إلى إنشاء مُرشّحات خاصّة بنا لتأدية أغراض أخرى غير التّي بُنيت لها المُرشّحات المبنيّة مُسبقا، لذا فالدّرس القادم سيكون عبارة عن مدخل إلى كيفيّة إنشاء مُرشّحات خاصّة بك مع مُساعدة من إطار العمل Flask للحصول على تجربة تطوير أفضل وتفادي تكرار شيفرات HTML.
</p>
]]></description><guid isPermaLink="false">449</guid><pubDate>Mon, 10 Apr 2017 21:05:00 +0000</pubDate></item><item><title>&#x623;&#x647;&#x645; &#x627;&#x644;&#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62A;&#x648;&#x641;&#x631;&#x629; &#x628;&#x634;&#x643;&#x644; &#x642;&#x64A;&#x627;&#x633;&#x64A; &#x641;&#x64A; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D9%88%D9%81%D8%B1%D8%A9-%D8%A8%D8%B4%D9%83%D9%84-%D9%82%D9%8A%D8%A7%D8%B3%D9%8A-%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r447/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.b7cce0ac5210312033a96c33b3c074b2.png" /></p>

<h3>
	<a id="_2" rel=""></a>مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23193" data-unique="p1n2wb338" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.dcfb91eca6e4d0257b6e66632a2a4ae6.png" alt="main2.png"></p>

<h3>
	<a id="_length_______7" rel=""></a>المُرشّح length لقياس عدد عناصر مجموعة من القيم
</h3>

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

<p>
	في مُحرّك القوالب Jinja، يُمكنك استخدام المُرشّح <code>length</code> للحصول على نفس النّتيجة.
</p>

<p>
	يُمكنك استخدام هذا المُرشّح كما يلي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_7">
<span class="pun">{{</span><span class="pln"> list </span><span class="pun">|</span><span class="pln"> length </span><span class="pun">}}</span></pre>

<p>
	مع استبدال المُتغيّر <code>list</code> بالمُتغيّر الذي يحمل القائمة التي ترغب بحساب عدد عناصرها.
</p>

<p>
	المثال التّالي عبارة عن توضيح لكيفيّة استعمال المُرشّح <code>length</code> للحصول على عدد عناصر القائمة <code>comments</code> لمنح المُستخدم فكرة عن عدد التّعليقات المُتوفّرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_9">
<span class="pun">{%</span><span class="pln"> set comments </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Comment 1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Comment 2'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Comment 3'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Comment 4'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Comment 5'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="typ">Comments</span><span class="pun">({{</span><span class="pln"> comments </span><span class="pun">|</span><span class="pln"> length </span><span class="pun">}}):</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> comment </span><span class="kwd">in</span><span class="pln"> comments  </span><span class="pun">%}</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"> comment </span><span class="pun">}}</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></pre>

<p>
	إن جرّبت المثال في ملفّ <code>filters.html</code> فستُلاحظ نتيجة مُشابهة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_11">
<span class="typ">Comments</span><span class="pun">(</span><span class="lit">5</span><span class="pun">):</span><span class="pln"> 
</span><span class="typ">Comment</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
</span><span class="typ">Comment</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> 
</span><span class="typ">Comment</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> 
</span><span class="typ">Comment</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> 
</span><span class="typ">Comment</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span></pre>

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

<p>
	<strong>مُلاحظة:</strong> يُمكنك كذلك استخدام المُرشّح <code>count</code> للحصول على نفس النّتيجة.
</p>

<h3>
	<a id="_list_62" rel=""></a>المُرشّح list
</h3>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_13">
<span class="pun">{{</span><span class="pln"> </span><span class="str">'Hello'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> list</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></pre>

<p>
	ستكون النّتيجة كما يلي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_15">
<span class="pun">[</span><span class="str">'H'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'e'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'l'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'l'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'o'</span><span class="pun">]</span><span class="pln"> </span></pre>

<h3>
	<a id="_random_78" rel=""></a>المُرشّح <code>random</code>
</h3>

<p>
	المُرشّح <code>random</code> يختار عنصرا عشوائيّا من مجموعة قيم وتكون نتيجته مُختلفة في كل مرّة بدون ترتيب مُعيّن.
</p>

<p>
	يُمكنك استخدام هذا المُرشّح كما يلي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_17">
<span class="pun">{{</span><span class="pln"> </span><span class="pun">[</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span></pre>

<p>
	إذا جرّبت المثال أعلاه في الملفّ <code>filters.html</code> وتوجّهت إلى العنوان <a href="http://127.0.0.1:5000/filters" rel="external nofollow">http://127.0.0.1:5000/filters</a> فستحصل على أحد عناصر القائمة أعلاه بشكل غير مُرتّب وغير مُتوقّع وكلّما أعدت تحميل الصّفحة ستتغيّر القيمة إلى قيمة أخرى وقد تحصل أحيانا على نفس القيمة أكثر من مرّة.
</p>

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

<p>
	يُمكنك كذلك أن تعرض مقولة بشكل عشوائي في كل مرّة يُعاد فيها تحميل الصّفحة، والمثال التّالي يُوضّح هذه الفكرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_19">
<span class="pun">{%</span><span class="pln"> set quotes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Quote 1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Quote 2'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Quote 3'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Quote 4'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Quote 5'</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="str">"quote"</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{{</span><span class="pln"> quotes </span><span class="pun">|</span><span class="pln"> random</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="pun">&gt;</span></pre>

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

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

<h3>
	<a id="_replace______103" rel=""></a>المُرشّح <code>replace</code> لتغيير قيمة إلى قيمة أخرى
</h3>

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

<p>
	المثال التّالي يُوضّح كيفيّة عمل هذا المُرشّح:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_21">
<span class="pun">{{</span><span class="pln"> </span><span class="str">'Hello World'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> replace</span><span class="pun">(</span><span class="str">'Hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hi'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span></pre>

<p>
	إذا قمت بتجربة المثال أعلاه فالنّتيجة ستكون <code>Hi World</code> بدل <code>Hello World</code>.
</p>

<p>
	يُمكنك كذلك استعمال المُرشّح <code>replace</code> مع مجموعة من القيم عوضا عن سلسلة نصيّة واحدة.
</p>

<p>
	المثال التّالي يُوضّح كيفيّة استخدام المُرشّح <code>replace</code> مع قائمة تحتوي على ثلاثة عناصر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_23">
<span class="pun">{%</span><span class="pln"> set list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{{</span><span class="pln"> list </span><span class="pun">|</span><span class="pln"> replace</span><span class="pun">(</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span></pre>

<p>
	كما تُلاحظ، فقد استعملنا المُرشّح <code>replace</code> لاستبدال القيمة <code>One</code> بالقيمة <code>1</code>، لذا فإنّ النّتيجة ستكون كالآتي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_25">
<span class="pun">[</span><span class="str">'1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</span><span class="pun">]</span><span class="pln"> </span></pre>

<h3>
	<a id="_reverse____129" rel=""></a>المُرشّح <code>reverse</code> لعكس قيمة ما
</h3>

<p>
	يُمكن أن تحتاج في بعض الأحيان إلى طريقة سريعة لعكس سلسلة نصّية. يُمكنك القيام بالأمر ببساطة باستعمال المُرشّح <code>reverse</code> كما في المثال التّالي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_27">
<span class="pun">{{</span><span class="pln"> </span><span class="str">"Hello World!"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> reverse</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span></pre>

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

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_29">
<span class="pun">!</span><span class="pln">dlroW olleH </span></pre>

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

<p>
	لتتوضّح الصّورة، جرّب المثال التّالي في ملفّ <code>filters.html</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_31">
<span class="pun">{%</span><span class="pln"> set list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{{</span><span class="pln"> list </span><span class="pun">|</span><span class="pln"> reverse</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span></pre>

<p>
	ستُلاحظ نتيجة مُشابهة لما يلي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_33">
<span class="pun">&lt;</span><span class="pln">list_reverseiterator object at </span><span class="lit">0x7fc0b6262518</span><span class="pun">&gt;</span><span class="pln"> </span></pre>

<p>
	لكن بعد استخدام المُرشّح <code>list</code> على النّتيجة كما هو مُوضّح في السّطر التّالي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_35">
<span class="pun">{{</span><span class="pln"> list </span><span class="pun">|</span><span class="pln"> reverse</span><span class="pun">()</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> list</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span><span class="pln"> </span></pre>

<p>
	فستحصل على النّتيجة التّاليّة:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_55">
<span class="pun">[</span><span class="str">'Three'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'One'</span><span class="pun">]</span><span class="pln"> </span></pre>

<p>
	وهي قائمة عناصرها مُرتّبة ترتيبا عكسيّا للقائمة <code>list</code> التّي عرّفناها من قبل:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_53">
<span class="pun">[</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</span><span class="pun">]</span></pre>

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

<p>
	إليك مثالا على كيفيّة استخدام الحلقة <code>for</code> مُباشرة مع نتيجة المُرشّح <code>reverse</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_51">
<span class="pun">{%</span><span class="pln"> set list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'One'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Two'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Three'</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"> item </span><span class="kwd">in</span><span class="pln"> list </span><span class="pun">|</span><span class="pln"> reverse</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">li</span><span class="pun">&gt;{{</span><span class="pln"> item </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_8703_49">
<span class="pun">-</span><span class="pln"> </span><span class="typ">Three</span><span class="pln">
</span><span class="pun">-</span><span class="pln"> </span><span class="typ">Two</span><span class="pln">
</span><span class="pun">-</span><span class="pln"> </span><span class="typ">One</span></pre>

<h3>
	<a id="_safe_195" rel=""></a>المُرشّح <code>safe</code>
</h3>

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

<p>
	لتوضيح الأمر، جرّب ما يلي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_47">
<span class="pun">{{</span><span class="pln"> </span><span class="str">"&lt;h1&gt;Hello World!&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">}}</span></pre>

<p>
	ستُلاحظ في المُتصفّح ما يلي بخط عادي:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_45">
<span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln"> </span></pre>

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

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

<p>
	لذا فالمثال التّالي سيُظهر الجملة <code>Hello World!</code> بخط كبير داخل الوسم <code>&lt;h1&gt;</code>:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_43">
<span class="pun">{{</span><span class="pln"> </span><span class="str">"&lt;h1&gt;Hello World!&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> safe </span><span class="pun">}}</span></pre>

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

<p>
	المثال التّالي يُوضّح كيفيّة استعمال المُرشّح <code>safe</code> لعرض قائمة تحتوي على شيفرات HTML:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_41">
<span class="pun">{%</span><span class="pln"> set list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'&lt;span div=list-item&gt;One&lt;/span&gt;'</span><span class="pun">,</span><span class="pln">
               </span><span class="str">'&lt;span div=list-item&gt;Two&lt;/span&gt;'</span><span class="pun">,</span><span class="pln">
               </span><span class="str">'&lt;span div=list-item&gt;Three&lt;/span&gt;'</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"> item </span><span class="kwd">in</span><span class="pln"> list </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"> item </span><span class="pun">|</span><span class="pln"> safe </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>
	كما تُلاحظ، فإنّ القائمة <code>list</code> تحتوي على عدّة عناصر، كل عنصر يحتوي على شيفرة HTML.
</p>

<p>
	لو قمنا بالدّوران حول القائمة وعرضنا كل عنصر دون استعمال المُرشّح <code>safe</code>، فستكون النّتيجة في المُتصفّح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_39">
<span class="pln"> </span><span class="pun">&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">One</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
 </span><span class="pun">&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">Two</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
 </span><span class="pun">&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">Three</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span></pre>

<p>
	وهذه ليست النّتيجة التّي نُريدها، بل نُريد أن تُترجم الشّيفرة إلى لغة HTML يفهمها المُتصفّح.
</p>

<p>
	أمّا عند استعمال المُرشّح <code>safe</code>، فشيفرة HTML ستُترجم ليفهمها المُتصفّح وسيكون مصدر الصّفحة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8703_37">
<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">li</span><span class="pun">&gt;&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">One</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">Two</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">span div</span><span class="pun">=</span><span class="pln">list</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="typ">Three</span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">    
</span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span></pre>

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

<h3>
	<a id="_265" rel=""></a>خاتمة
</h3>

<p>
	تعرّفنا في هذا الدّرس على المزيد من المُرشّحات التّي يُوفرّها مُحرّك القوالب Jinja لتتمكّن من تطوير قوالب HTML بشكل أسرع وبأقل تكرار ممكن للشّيفرة. لكنّنا لم ننته بعد، إذ لا تزال في جعبة مُحرّك القوالب Jinja المزيد من المُرشّحات المُفيدة والتّي سنتعرّف عليها في الدّرس المُقبل.
</p>
]]></description><guid isPermaLink="false">447</guid><pubDate>Wed, 05 Apr 2017 21:02:00 +0000</pubDate></item><item><title>&#x623;&#x647;&#x645; &#x627;&#x644;&#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62A;&#x648;&#x641;&#x631;&#x629; &#x628;&#x634;&#x643;&#x644; &#x642;&#x64A;&#x627;&#x633;&#x64A; &#x641;&#x64A; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A3%D9%87%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D9%88%D9%81%D8%B1%D8%A9-%D8%A8%D8%B4%D9%83%D9%84-%D9%82%D9%8A%D8%A7%D8%B3%D9%8A-%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-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r445/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.a5df93e94eb4684403adca0e157a9641.png" /></p>

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

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23194" data-unique="f7ww7pk2k" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.5d2b38ba9dbec02cb3c9175de5127f2a.png" alt="main2.png"></p>

<h3 id="المرشح-default-لتوفير-قيمة-افتراضية">
	المُرشّح <code>default</code> لتوفير قيمة افتراضيّة
</h3>

<p>
	في بعض الأحيان، يُمكن أن يكون متغيّرٌ غير مُتوفّرٍ في القالب، لكن يُمكنك توفير قيمة افتراضيّة لتظهر في هذه الحالة.
</p>

<p>
	كمثال على ذلك، لنفترض بأنّك تعرض عنوان مقال باستخدام السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> </span><span class="hljs-expression">{{ <span class="hljs-variable">title</span> }}</span><span class="xml"> <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span></span></code></pre>

<p>
	في حالة لم يكن المُتغيّر <code>title</code> مُعرّفا فقد يُشوّه ذلك مظهر الصّفحة أو من المُمكن أن تحدث أخطاء غير مُتوقّعة، يُمكننا عوضا عن ذلك عرض النّص <code>Title Not Found</code> باستخدام السّطر التّالي عوضا عن السّطر السّابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> </span><span class="hljs-expression">{{ <span class="hljs-variable">title</span> | <span class="hljs-variable">default</span>(<span class="hljs-string">"Title Not Found"</span>) }}</span><span class="xml"> <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span></span></code></pre>

<p>
	يُمكننا الآن التّأكّد من أنّ الجملة <code>Title Not Found</code> تظهر فقط في حالة لم يكن المُتغيّر <code>title</code> مُعرّفا، وذلك عبر تعريفه قبل استدعائه باستخدام السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash">{% <span class="hljs-keyword">set</span> title = <span class="hljs-string">"A title for a post"</span> %}</code></pre>

<p>
	تأكّد فقط من تعريف المُتغيّر في سطر يسبق السّطر الذي تستدعي فيه قيمته.
</p>

<p>
	عند تعريف المُتغيّر ستظهر قيمته بشكل عادي، أمّا إن لم يكن مُعرّفا فالجملة “Title Not Found” ستظهر عوضا عن ذلك.
</p>

<h3 id="المرشح-capitalize-لتحويل-الحرف-الأول-من-كلمة-إلى-حرف-كبير">
	المُرشّح <code>capitalize</code> لتحويل الحرف الأول من كلمة إلى حرف كبير
</h3>

<p>
	في بعض اللغات اللاتينيّة، من المُهمّ أن تجعل الحرف الأول من بعض الأسماء حرفا كبيرا، فمثلا كتابة اسم على شكل <code>Ali</code> طريقة تعبير أفضل من كتابته على شكل <code>ali</code>.<br>
	ولتحويل كل قيمة مُعيّنة إلى هذه الحالة يُمكننا استعمال المُرشّح <code>capitalize</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> </span><span class="hljs-expression">{{ <span class="hljs-string">"academy"</span> | <span class="hljs-variable">capitalize</span>() }}</span><span class="xml"> <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span></span></code></pre>

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

<h3 id="المرشح-title-لتحويل-قيمة-نصية-إلى-طريقة-كتابة-العناوين">
	المُرشّح <code>title</code> لتحويل قيمة نصيّة إلى طريقة كتابة العناوين
</h3>

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

<p>
	فعوضا عن كتابة عنوان بالطّريقة المُواليّة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs fsharp">how <span class="hljs-keyword">to</span> <span class="hljs-keyword">use</span> the flask framework <span class="hljs-keyword">to</span> develop web applications</code></pre>

<p>
	فإنّ الطّريقة الصّحيحة هي بكتابته كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs vhdl">How <span class="hljs-keyword">To</span> <span class="hljs-keyword">Use</span> The Flask Framework <span class="hljs-keyword">To</span> Develop Web Applications </code></pre>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> </span><span class="hljs-expression">{{ <span class="hljs-string">"how to use the flask framework to develop web applications"</span> | <span class="hljs-variable">title</span>() }}</span><span class="xml"> <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span></span></code></pre>

<p>
	بالإضافة إلى كل من <code>upper</code>، <code>capitalize</code> و <code>title</code> فالمُرشّح <code>lower</code> يقوم بتحويل أي سلسلة نصّيّة إلى أحرف صغيرة.
</p>

<h3 id="المرشح-first-لعرض-أول-عنصر-من-مجموعة-عناصر">
	المُرشّح <code>first</code> لعرض أول عنصر من مجموعة عناصر
</h3>

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

<p>
	المثال التّالي يُوضّح كيفيّة استخدام المُرشّح <code>first</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript">{% <span class="hljs-keyword">set</span> <span class="hljs-type">list</span> = [<span class="hljs-string">"One"</span>, <span class="hljs-string">"Two"</span>, <span class="hljs-string">"Three"</span>] %}

&lt;h1&gt; {{ <span class="hljs-type">list</span> | <span class="hljs-keyword">first</span>() }} &lt;/h1&gt;</code></pre>

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

<p>
	إذا عدت إلى الصّفحة الخاصّة بالمُرشّحات الآن، فستُلاحظ بأنّ ما بداخل الوسم <code>&lt;h1&gt;</code> هو القيمة <code>One</code> فقط، وذلك لأنّها أول قيمة في مجموعة القيم المُتواجدة داخل القائمة <code>list</code>.
</p>

<h3 id="المرشح-float-لتحويل-الأعداد-إلى-أعداد-عشرية">
	المُرشّح float لتحويل الأعداد إلى أعداد عشريّة
</h3>

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

<p>
	يُمكنك استخدامه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml">
</span><span class="hljs-expression">{{ 10 | <span class="hljs-variable">float</span>() }}</span><span class="xml">
</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-string">"10"</span> | <span class="hljs-variable">float</span>() }}</span></code></pre>

<p>
	إذا لم يكن بالمقدور تحويل القيمة إلى عدد عشري فستظهر القيمة 0.0 عوضا عن ذلك.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-string">"Hello Word"</span> | <span class="hljs-variable">float</span>() }}</span></code></pre>

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

<p>
	يُمكنك تغيير القيمة الافتراضيّة 0.0 إلى أي قيمة أخرى عبر تمرير القيمة الافتراضيّة الجديدة إلى المُعامل <code>default</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-string">"Hello Word"</span> | <span class="hljs-variable">float</span>(<span class="hljs-variable">default</span>=<span class="hljs-string">"Error: value cannot be converted into a floating point number"</span>) }}</span></code></pre>

<p>
	بعد هذا التّغيير، ستجد بأنّ نتيجة تحويل قيمة لا يُمكن تحويلها إلى عدد عشري هي الجملة “Error: value cannot be converted into a floating point number” ويُمكنك تغيير هذه الرّسالة كيفما تشاء.
</p>

<h3 id="المرشح-int-لتحويل-القيم-إلى-أعداد-صحيحة">
	المُرشّح int لتحويل القيم إلى أعداد صحيحة
</h3>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ 10<span class="hljs-variable">.</span>0 | <span class="hljs-variable">int</span>() }}</span></code></pre>

<p>
	وكما الحال مع المُرشّح<code>float</code>، فإنّ المُرشّح <code>int</code> يُحوّل أي قيمة غير قابلة إلى التّحويل إلى عدد صحيح إلى القيمة 0، ويُمكنك تعديل هذه القيمة الافتراضيّة عبر تمرير القيمة الجديدة إلى المُعامل <code>default</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-string">"Hello Word"</span> | <span class="hljs-variable">int</span>(<span class="hljs-variable">default</span>=<span class="hljs-string">"Error: value cannot be converted into an integer number"</span>) }}</span></code></pre>

<h3 id="المرشح-join-لضم-عناصر-مجموعة-من-القيم-وجمعها-لتكون-قيمة-واحدة">
	المُرشّح join لضمّ عناصر مجموعة من القيم وجمعها لتكون قيمة واحدة
</h3>

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

<p>
	في مُحرّك القوالب Jinja، يُمكننا استخدام المُرشّح <code>join</code> للوصول إلى نفس النّتيجة.
</p>

<p>
	يُمكنك استخدام المُرشّح <code>join</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ [1, 2, 3] | <span class="hljs-variable">join</span>()  }}</span></code></pre>

<p>
	ستُلاحظ بأنّ النّتيجة في المُتصفّح هي <code>123</code>.
</p>

<p>
	إليك مثالا آخر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ [<span class="hljs-string">"One"</span>, <span class="hljs-string">"Two"</span>, <span class="hljs-string">"Three"</span>] | <span class="hljs-variable">join</span>()  }}</span></code></pre>

<p>
	هذه المرّة ستكون النّتيجة القيمة <code>OneTwoThree</code>.
</p>

<p>
	يُمكنك كذلك الفصل بين العناصر بفاصل عبر تمريره إلى المُرشّح كمُعامل.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cs">{{ [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] | <span class="hljs-keyword">join</span>(<span class="hljs-string">'|'</span>)  }}</code></pre>

<p>
	في هذا المثال، ستُلاحظ بأنّ النّتيجة هي <code>1|2|3</code> عوضا عن <code>123</code> لأنّنا وضعنا فاصلا بين عناصر القائمة.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ [<span class="hljs-string">"One"</span>, <span class="hljs-string">"Two"</span>, <span class="hljs-string">"Three"</span>] | <span class="hljs-variable">join</span>(<span class="hljs-string">"-"</span>)  }}</span></code></pre>

<p>
	هذه المرّة ستُلاحظ بأنّ النّتيجة هي <code>One-Two-Three</code>.
</p>

<h3 id="المرشح-last">
	المُرشّح <code>last</code>
</h3>

<p>
	المُرشّح <code>last</code> يعمل بطريقة مُعاكسة للمُرشّح <code>first</code>، إذ أنّ هذا الأخير يعرض أول قيمة من مجموعة قيم، والمُرشّح <code>last</code> يعرض آخر قيمة من المجموعة.
</p>

<p>
	المثال التّالي يُوضّح كيفيّة استعمال المُرشّح <code>last</code> لعرض آخر قيمة من القائمة <code>names</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs sql">{% <span class="hljs-operator"><span class="hljs-keyword">set</span> <span class="hljs-keyword">names</span> = [<span class="hljs-string">'Kamal'</span>, <span class="hljs-string">'Ali'</span>, <span class="hljs-string">'Ahmed'</span>, <span class="hljs-string">'Khaled'</span>] %}


&lt;h1&gt; {{ <span class="hljs-keyword">names</span> | <span class="hljs-keyword">last</span>()  }} &lt;/h1&gt;</span></code></pre>

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

<p>
	المثال التّالي يجمع كلّا من المُرشّح <code>first</code> والمُرشّح <code>last</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs sql">{% <span class="hljs-operator"><span class="hljs-keyword">set</span> <span class="hljs-keyword">names</span> = [<span class="hljs-string">'Kamal'</span>, <span class="hljs-string">'Ali'</span>, <span class="hljs-string">'Ahmed'</span>, <span class="hljs-string">'Khaled'</span>] %}

&lt;h1&gt; <span class="hljs-keyword">First</span>: {{ <span class="hljs-keyword">names</span> | <span class="hljs-keyword">first</span>()  }} &lt;/h1&gt;
&lt;h1&gt; <span class="hljs-keyword">Last</span>: {{ <span class="hljs-keyword">names</span> | <span class="hljs-keyword">last</span>()  }} &lt;/h1&gt;</span></code></pre>

<p>
	النّتيجة ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs http"><span class="hljs-attribute">First</span>: <span class="hljs-string">Kamal</span>
<span class="hljs-attribute">Last</span>: <span class="hljs-string">Khaled</span></code></pre>

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

<p>
	تعرّفنا في هذا الدّرس على جزء من أهم مُرشّحات Jinja التّي يُمكنك أن تعتمد عليها في تطوير تطبيقات فلاسك الخاصّة بك، وسنستعمل بعضا منها في تطوير تطبيق “كلمة” في ما يلي من الدّروس، مُرشّحات Jinja كثيرة ولا يُمكن أن نذكرها جميعها في درس واحد، لذا فسنُكمل تغطيّة بقيّة المُرشّحات المُهمّة في دروس مُقبلة لنمرّ بعدها إلى جانب آخر من تطوير الويب أثناء تطويرنا لتطبيق كبير في هذه السّلسلة، لذا ترقّب بقيّة الدّروس.
</p>
]]></description><guid isPermaLink="false">445</guid><pubDate>Sat, 01 Apr 2017 21:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x651;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x625;&#x637;&#x627;&#x631; Flask &#x648;&#x645;&#x643;&#x62A;&#x628;&#x629; WTForms : &#x627;&#x644;&#x62A;&#x651;&#x62D;&#x642;&#x642; &#x645;&#x646; &#x645;&#x64F;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x64F;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x645;&#x64F;&#x635;&#x627;&#x62F;&#x650;&#x642;&#x64A; WTForms</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D9%91%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-flask-%D9%88%D9%85%D9%83%D8%AA%D8%A8%D8%A9-wtforms-%D8%A7%D9%84%D8%AA%D9%91%D8%AD%D9%82%D9%82-%D9%85%D9%86-%D9%85%D9%8F%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D9%8F%D8%B5%D8%A7%D8%AF%D9%90%D9%82%D9%8A-wtforms-r444/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.d179058835ae7557fe7638276c8e5677.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22354" data-unique="afaa90gs5" src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.677b43ab1af8d4aa2e1bb027fe898b36.png"></p>

<p>
	المُصادقون Validators ميّزة من ميّزات مكتبة WTForms تُتيح لنا إمكانيّة التّحقق من مُدخلات المُستخدم والمُصادقة عليها حسب قانون مُعيّن (طول النّص، مجال عدد مُعيّن، صيغة بريد إلكتروني …)، وهناك أنواع مختلفة من المُصادقين، وقد تعرّفنا من قبل على المُصادق <code>DataRequired</code> الذي يتحقّق من أنّ المُدخل غير فارغ، ونُضيفه إلى كل حقل مطلوب ملؤه من قبل المُستخدم، ويرجع رسالة خطأ إذا ما لم تتم المُصادقة على المُدخل (في حالة المُصادق <code>DataRequired</code> فإنّ الرّسالة تُعرض إذا أرسل المُستخدم بيانات فارغة عبر النموذج).
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> TextField

<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> DataRequired

username = TextField(<span class="hljs-string">'Username'</span>, validators=[DataRequired()]) </code></pre>

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

<h3 id="مصادق-البريد-الإلكتروني-email">
	مُصادق البريد الإلكتروني Email
</h3>

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

<p>
	للتحقق من أنّ المُدخل على شكل بريد إلكتروني، فإنّ مكتبة WTForms تُوفّر لنا مُصادقا (Validator) باسم Email لتمريره كعنصر من القائمة التّي تُمرّر إلى المُعامل <code>validators</code> عند إنشاء حقل مُعيّن.
</p>

<p>
	لاستعمال المُصادق، نقوم أولا باستيراده من حزمة <code>wtforms.validators</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title">from</span> flask_wtf <span class="hljs-import"><span class="hljs-keyword">import</span> FlaskForm</span>
<span class="hljs-title">from</span> wtforms <span class="hljs-import"><span class="hljs-keyword">import</span> TextField</span>
<span class="hljs-title">from</span> wtforms.validators <span class="hljs-import"><span class="hljs-keyword">import</span> DataRequired, Email </span>
<span class="hljs-class">


<span class="hljs-keyword">class</span> <span class="hljs-type">SubscribeForm</span><span class="hljs-container">(<span class="hljs-type">FlaskForm</span>)</span>:
    email = <span class="hljs-type">TextField</span><span class="hljs-container">(
      '<span class="hljs-type">Email</span>', 
      <span class="hljs-title">validators</span>=[
      <span class="hljs-type">Email</span>()</span>,
      <span class="hljs-type">DataRequired</span><span class="hljs-container">()</span>]
       )</span></code></pre>

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

<h3 id="المصادق-equalto">
	المُصادق EqualTo
</h3>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title">from</span> flask_wtf <span class="hljs-import"><span class="hljs-keyword">import</span> FlaskForm</span>
<span class="hljs-title">from</span> wtforms <span class="hljs-import"><span class="hljs-keyword">import</span> TextField, PasswordField</span>
<span class="hljs-title">from</span> wtforms.validators <span class="hljs-import"><span class="hljs-keyword">import</span> DataRequired, Email, EqualTo</span>
<span class="hljs-class">
<span class="hljs-keyword">class</span> <span class="hljs-type">RegisterForm</span><span class="hljs-container">(<span class="hljs-type">FlaskForm</span>)</span>:
    email = <span class="hljs-type">TextField</span><span class="hljs-container">(
      '<span class="hljs-type">Email</span>', 
      <span class="hljs-title">validators</span>=[
      <span class="hljs-type">Email</span>()</span>,
      <span class="hljs-type">DataRequired</span><span class="hljs-container">()</span>]
       )
    password = <span class="hljs-type">PasswordField</span><span class="hljs-container">('<span class="hljs-type">Password</span>', 
      <span class="hljs-title">validators</span>=[<span class="hljs-type">DataRequired</span>()</span>])
    confirm  = <span class="hljs-type">PasswordField</span><span class="hljs-container">('<span class="hljs-type">Confirm</span> <span class="hljs-title">your</span> <span class="hljs-type">Password</span>',
      <span class="hljs-title">validators</span>=[<span class="hljs-type">DataRequired</span>()</span>, <span class="hljs-type">EqualTo</span><span class="hljs-container">('<span class="hljs-title">password'</span>)</span>])</span></code></pre>

<p>
	لاحظ بأنّنا نقوم بتمرير الحقل إلى المُصادق بتمرير اسم المُتغيّر الذي يمثّل الحقل (أي <code>password</code> في هذه الحالة) على شكل سلسلة نصيّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs scss"><span class="hljs-function">EqualTo(<span class="hljs-string">'password'</span>)</span></code></pre>

<p>
	هكذا نُعلم المُصادق بأنّ قيمة هذا الحقل يجب أن تُساوي قيمة الحقل <code>password</code>.
</p>

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

<h3 id="المصادق-ipaddress">
	المُصادق IPAddress
</h3>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> IPAddress</code></pre>

<p>
	يُستعمل المُعامل المُصادق على حقل نص قصير عادي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash">ip_address = TextField(<span class="hljs-string">'IP address'</span>, 
    validators=[DataRequired(), IPAddress()])</code></pre>

<p>
	هكذا لن تسمح مكتبة WTForms بمرور البيانات إلى حين توفير عنوان IP صالح.
</p>

<p>
	عند استعمالك للمُصادق دون تمرير أي مُعامل، فسيتأكّد من أنّ المُدخل مُتوافق مع النّسخة الرّابعة لعناوين IP فقط وإن أردت أن تُقبل عناوين IPv6 كذلك فيُمكنك ذلك عبر تمرير القيمة True إلى المُعامل <code>ipv6</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs mathematica">ip_address = TextField(<span class="hljs-string">'Ip address'</span>, 
    validators=[DataRequired(), IPAddress(ipv6=<span class="hljs-keyword">True</span>)])</code></pre>

<h3 id="المصادق-length">
	المُصادق Length
</h3>

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

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

<p>
	يُمكنك استعمال المُصادق بعد استيراده كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs glsl">Length(<span class="hljs-built_in">min</span>=MIN_VALUE, <span class="hljs-built_in">max</span>=MAX_VALUE)</code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs rsl">username = TextField(<span class="hljs-string">'Username'</span>, 
    validators=[DataRequired(),
        Length(<span class="hljs-built_in">min</span>=<span class="hljs-number">3</span>, <span class="hljs-built_in">max</span>=<span class="hljs-number">25</span>)]
    )</code></pre>

<p>
	هكذا لن تُقبل أية قيمة إن كان طولها أقصر أو أطول ممّا حدّدناه.
</p>

<p>
	وكما قُلت سابقا، تستطيع توفير قيمة واحدة فقط، والتّالي مثال على كيفيّة التّحقق من أنّ المُدخل لا يتجاوز 25 حرفا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs rsl">username = TextField(<span class="hljs-string">'Username'</span>, 
    validators=[DataRequired(),
        Length(<span class="hljs-built_in">max</span>=<span class="hljs-number">25</span>)]
    )</code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs rsl">username = TextField(<span class="hljs-string">'Username'</span>, 
    validators=[DataRequired(),
        Length(<span class="hljs-built_in">min</span>=<span class="hljs-number">3</span>)]
    )</code></pre>

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

<h3 id="المصادق-numberrange">
	المُصادق NumberRange
</h3>

<p>
	المُصادق <code>Length</code> يعمل مع السّلاسل النّصيّة فقط، ما يعني بأنّك تستطيع تطبيقه على حقل كلمة المرور، حقل النّصوص المُتعدّدة الأسطر Text Area أو أي حقل آخر يقبل قيما نصيّة، أمّا بالنّسبة لحقل الأعداد الصّحيحة <code>IntegerField</code> فهناك مُصادق آخر لتحديد مجال القيم العدديّة (قبول الأعداد الأكبر من 1 والأصغر من 255 على سبيل المثال).
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword">from</span> flask_wtf <span class="hljs-keyword">import</span> FlaskForm
<span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> IntegerField
<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> NumberRange

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AgeForm</span><span class="hljs-params">(FlaskForm)</span>:</span>
    age = IntegerField(<span class="hljs-string">'Age'</span>, validators=[NumberRange(min=<span class="hljs-number">12</span>, max=<span class="hljs-number">120</span>)])
</code></pre>

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

<p>
	ومثلما هو عليه الحال مع المُصادق <code>Length</code>، فإنّك تستطيع ترك أحد المُعاملين ووضع حد واحد لقيم الحقل، كأن تسمح فقط بالأعداد الموجبة بتحديد العدد 0 كقيمة دنيا، أو أن تتحقّق من أنّ قيمة الحقل لا تتجاوز العدد 1000 بتحديده كقيمة للمُعامل <code>max</code>.
</p>

<p>
	ما يلي مثال عن كيفيّة التّحقق من أنّ قيم الحقل أعداد موجبة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs fix"><span class="hljs-attribute">NumberRange(min</span>=<span class="hljs-string">0)</span></code></pre>

<p>
	هكذا يُمكن إدخال أي عدد موجب دون حد لأقصى قيمة.
</p>

<p>
	وللتّحقق من أنّ المُدخل لا يتجاوز العدد 100:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs fix"><span class="hljs-attribute">NumberRange(max</span>=<span class="hljs-string">100)</span></code></pre>

<p>
	سيسمح المُصادق الآن بمرور أي عدد ما دام لم يتجاوز المئة، ما يعني بأنّ الأعداد السّالبة مسموح بها كذلك.
</p>

<h3 id="المصادق-optional">
	المُصادق Optional
</h3>

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

<p>
	ما يلي مثال على كيفيّة استخدام المُصادق <code>Optional</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title">from</span> flask_wtf <span class="hljs-import"><span class="hljs-keyword">import</span> FlaskForm</span>
<span class="hljs-title">from</span> wtforms <span class="hljs-import"><span class="hljs-keyword">import</span> TextField</span>
<span class="hljs-title">from</span> wtforms.validators <span class="hljs-import"><span class="hljs-keyword">import</span> Optional</span>
<span class="hljs-class">
<span class="hljs-keyword">class</span> <span class="hljs-type">RegisterForm</span><span class="hljs-container">(<span class="hljs-type">FlaskForm</span>)</span>:
    phone = <span class="hljs-type">TextField</span><span class="hljs-container">('<span class="hljs-type">Phone</span> <span class="hljs-type">Number</span>', <span class="hljs-title">validators</span>=[<span class="hljs-type">Optional</span>()</span>])</span></code></pre>

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

<h3 id="المصادق-anyof">
	المُصادق AnyOf
</h3>

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

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

<p>
	لاستخدام المُصادق نقوم أولا باستيراده من حزمة <code>wtforms.validators</code> ثمّ نُطبّقه على الحقل الذي نُريده.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword">from</span> flask_wtf <span class="hljs-keyword">import</span> FlaskForm
<span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> TextField
<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> AnyOf

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NameForm</span><span class="hljs-params">(FlaskForm)</span>:</span>
    name = TextField(<span class="hljs-string">'Name'</span>, validators=[AnyOf([<span class="hljs-string">'Ahmed'</span>, <span class="hljs-string">'Khalid'</span>, <span class="hljs-string">'Kamal'</span>])])</code></pre>

<p>
	بتطبيقنا لهذا المُصادق في المثال أعلاه، فسنتمكّن من التّحقق من أنّ قيمة المُدخل لن تخرج عن مجموعة القيم ‘Ahmed’ و’Khalid’ و’Kamal’، وهكذا سنتأكّد من أنّ قاعدة البيانات لا تحتوي سوى على هذه القيم وبالتّالي فإجراء عمليّات على البيانات الضّخمة مثل إحصائها أو ربطها ببيانات أخرى لن تؤدي إلى أية نتائج سلبيّة.
</p>

<h3 id="المصادق-noneof">
	المُصادق NoneOf
</h3>

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

<p>
	ولاستثناء مجموعة من القيم فإنّنا نستخدم المُصادق <code>NoneOf</code>، وبما أنّ فكرته مُشابهة لفكرة المُصادق <code>AnyOf</code> فطريقة العمل هي نفسها، بحيث تُمرّر القيم التّي لا يجب أن توافق المُدخل إلى المُصادق كقائمة عند استدعائه، والتّالي مثال على كيفيّة استخدامه لاستثناء القيم ‘Ahmed’ و’Khalid’ و’Kamal’ من مُدخلات الحقل name:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword">from</span> flask_wtf <span class="hljs-keyword">import</span> FlaskForm
<span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> TextField
<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> NoneOf

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NameForm</span><span class="hljs-params">(FlaskForm)</span>:</span>
    name = TextField(<span class="hljs-string">'Country'</span>, validators=[NoneOf([<span class="hljs-string">'Ahmed'</span>, <span class="hljs-string">'Khalid'</span>, <span class="hljs-string">'Kamal'</span>])])</code></pre>

<p>
	بتطبيقك للمُصادِق ستتمكّن من التّحقق من أنّ المُدخل لا يوافق كلّا من الأسماء ‘Ahmed’ و’Khalid’ و’Kamal’ لذا فأي اسم آخر لا يندرج ضمنها سيُقبل وسيصل إلى الخادوم.
</p>

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

<p>
	بنهاية هذا الدّرس سنكون قد أتممنا سلسلة الدّروس المُخصّصة لكيفيّة استخدام مكتبة WTForms للتّحقق من مُدخلات المُستخدم، وبما أنّك قد أتممت السّلسلة، فستتمكّن الآن من توفير حماية أكثر لتطبيقك وستُطوّر تطبيقاتك بطريقة أفضل من ذي قبل، وإن كنت تُريد الاستمرار مع إطار العمل Flask لبناء تطبيقات أكبر وأعقد فتستطيع مُتابعة سلسلة إنشاء تطبيق لإدارة المُحتوى باستخدام إطار العمل Flask وإضافاته المُختلفة.
</p>
]]></description><guid isPermaLink="false">444</guid><pubDate>Tue, 28 Mar 2017 21:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x645;&#x62D;&#x631;&#x643; &#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; Jinja &#x627;&#x644;&#x62F;&#x648;&#x627;&#x644; &#x648;&#x627;&#x644;&#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A;</title><link>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%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-r440/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.9ac625c59985f1d56c90e8ead9590312.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23195" data-unique="uetaot3ba" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.cb878841020c850393bcba648b88b1a6.png" alt="main2.png"></p>

<h3 id="الدوال-في-jinja">
	الدّوال في Jinja
</h3>

<p>
	يُمكننا تعريف دوال لتحمل شيفرة معيّنة مع معاملات على Jinja لإعادة استعمالها وتحقيق مبدأ DRY أو Don’t Repeat Yourself وترجمته إلى اللغة العربيّة هي “لا تكرّر نفسك” ويعني بأنّه لا يجب عليك تكرار كتابة نفس الشّيفرة، وكلّما وجدت نفسك تُكرّرها توقّف وفكّر في إيجاد حل لتجنّب هذا التّكرار، إما بوضعها في دالّة أو شيء من هذا القبيل لتسهل عليك إعادة استعمالها.<br>
	في Jinja مبدأ الدّوال موجود في ما يُسمى بالماكرو macro ويُمكن تعريف واحدة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs asciidoc">{% macro name(param1, param2) %}

<span class="hljs-bullet">.
</span><span class="hljs-bullet">.
</span><span class="hljs-bullet">.

</span>{% endmacro %}
</code></pre>

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

<p>
	يُمكننا استدعاء الماكرو في مكان آخر من القالب كما نعرض قيمة مُتغيّر معيّن:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">name</span>('<span class="hljs-variable">pram</span>1_<span class="hljs-variable">value</span>', '<span class="hljs-variable">pram</span>2_<span class="hljs-variable">value</span>' }}</span></code></pre>

<p>
	يُمكننا كذلك تعريف الماكرو دون أية مُعاملات. ومن الشّائع أن توضع في ملف باسم <code>_helpers.html</code> في مجلّد <code>templates</code> الرّئيسي، وبعدها لاستخدامه يجب استيراده في أعلى الملف كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python">{% <span class="hljs-keyword">from</span> <span class="hljs-string">"_helpers.html"</span> <span class="hljs-keyword">import</span> macro_name %}
</code></pre>

<p>
	مع استبدال <code>macro_name</code> باسم الماكرو، تأكّد فقط بأنّك تستدعيه في أعلى الملفّ عوضا عن أي مكان آخر.
</p>

<p>
	بعد الاستدعاء ستتمكّن من استخدامه كالمُعتاد.
</p>

<h3 id="مثال-على-ماكرو">
	مثال على ماكرو
</h3>

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

<p>
	في هذا المثال سنقوم بإنشاء ماكرو لتحويل قائمة بايثون إلى قائمة HTML.<br>
	فمثلا لو كانت لدينا القائمة التّالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs php"><span class="hljs-keyword">list</span> = [<span class="hljs-string">'Abdelhadi'</span>, <span class="hljs-string">'Ayman'</span>, <span class="hljs-string">'Ibrahim'</span>]
</code></pre>

<p>
	فسنستطيع تحويلها إلى التّالي بسطر واحد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-title">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span>Abdelhadi<span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span>Ayman<span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span>Ibrahim<span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">ul</span>&gt;</span></code></pre>

<p>
	أولا سنُنشئ الماكرو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_tag">{% macro py_to_html(list) %}</span><span class="xml">
<span class="hljs-tag">&lt;<span class="hljs-title">ul</span>&gt;</span>
    </span><span class="hljs-template_tag">{% <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> list %}</span><span class="xml">
    <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span></span><span class="hljs-variable">{{ item }}</span><span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
    </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endfor</span> %}</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-title">ul</span>&gt;</span>
</span><span class="hljs-template_tag">{% endmacro %}</span></code></pre>

<p>
	ثمّ نستدعيه كما يلي (على فرض أنّ <code>list</code> عبارة عن قائمة بايثون عاديّة):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">py</span>_<span class="hljs-variable">to</span>_<span class="hljs-variable">html</span>(<span class="hljs-variable">list</span>) }}</span></code></pre>

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

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

<p>
	يُمكنك كذلك إنشاء ماكرو بدون أيّة مُعاملات، فمثلا الماكرو التّالي سيقوم بعرض الجملة “مرحبا بالعالم” في كل مرّة يتمّ استدعاؤه فيه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs mathematica"><span class="hljs-list">{% macro hello_world() %}</span>
     مرحبا بالعالم
<span class="hljs-list">{% endmacro %}</span></code></pre>

<p>
	وطريقة استدعائه في قالب HTML ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">hello</span>_<span class="hljs-variable">world</span>() }}</span></code></pre>

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

<h3 id="المرشحات-filters-في-jinja2">
	المُرشّحات (filters) في Jinja2
</h3>

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

<p>
	يُطبّق المُرشّح في مُحرّك القوالب Jinja على مُتغيّر لتغيير قيمته من حالة إلى أخرى.
</p>

<p>
	التّالي مثال على كيفيّة عرض قيمة المُتغيّر <code>name</code> في مُحرّك القوالب Jinja:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">name</span> }}</span></code></pre>

<p>
	إذا ما طبّقنا على هذا المتغيّر مُرشّحا فسيتوجّب علينا أن نقسم بين المُتغيّر والمُرشّح بعلامة <code>|</code>.<br>
	المثال التّالي يُوضّح كيفيّة تطبيق مُرشّح وهمي سنُسمّيه <code>filter</code> على المُتغيّر <code>name</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">name</span> | <span class="hljs-variable">filter</span> }}</span></code></pre>

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

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">name</span> | <span class="hljs-variable">filter</span>(<span class="hljs-variable">argument</span>1, <span class="hljs-variable">argument</span>2, <span class="hljs-variable">argument</span>3) }}</span></code></pre>

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

<p>
	يُمكن كذلك استخدام أكثر من مُرشّح عبر تقسيمها بالرمز <code>|</code> كما في المثال التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">name</span> | <span class="hljs-variable">filter</span>1() | <span class="hljs-variable">filter</span>2() | <span class="hljs-variable">filter</span>3() }}</span></code></pre>

<p>
	كل مُرشّح يجري عمليّة على القيمة التّي تسبقه، لذا فطريقة عمل المثال أعلاه هو كالتّالي:
</p>

<ul>
<li>
		<p>
			يأخذ المُرشّح <code>filter1</code> قيمة المُتغيّر <code>name</code> ويُرجع نتيجة تُعتبر مُجرّد قيمة أخرى.
		</p>
	</li>
	<li>
		<p>
			تمرّ النّتيجة السّابقة على المُرشّح <code>filter2</code> لنحصل على قيمة جديدة تُعتبر نتيجة لعمل المُرشّح <code>filter2</code> على ما أرجعه المرشّح <code>filter1</code>.
		</p>
	</li>
	<li>
		<p>
			يأخذ المُرشّح <code>filter3</code> القيمة التّي نحصل عليها في النّتيجة السّابقة ويُجري عليها عمليّة ثمّ يُرجع قيمة جديدة.
		</p>
	</li>
</ul>
<p>
	وبما أنّ آخر قيمة حصلنا عليها هي ما أنتجه المُرشّح <code>filter3</code> على ما سبقه من قيمة، فما سيظهر للمُستخدم الذي يزور صفحة HTML التّي حدث بها ما حدث هو القيمة الأخيرة.
</p>

<h3 id="ما-فائدة-المرشحات">
	ما فائدة المُرشّحات؟
</h3>

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

<p>
	بالإضافة إلى أنّك تستطيع إنشاء مُرشّحات خاصّة بك لتستعملها مع إطار العمل Flask وقوالب Jinja إن أردت ذلك، فمثلا يُمكنك أن تكتب مُرشّحا لتحويل تاريخ مُعيّن من الصّيغة العاديّة (1-1-2017) إلى صيغة (قبل كذا يوم/ قبل كذا شهر/ منذ X أشهر …).
</p>

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

<h3 id="مثال-على-استخدام-مرشح-لتحويل-نص-إلى-أحرف-كبيرة">
	مثال على استخدام مُرشّح لتحويل نصّ إلى أحرف كبيرة
</h3>

<p>
	كمثال على كيفيّة استخدام مُرشّح مُتوفّر مُسبقا بحيث يُمكنك استخدامه في أي قالب HTML في مشروع Flask الخاصّ بك، سننظرُ إلى كيفيّة استخدام المُرشّح <code>upper</code> الذي يعمل بنفس طريقة عمل التّابع <code>upper()</code> في لغة بايثون، والذي يُمكنك استخدامه لتحويل نصّ عادي إلى أحرف كبيرة Uppercase.
</p>

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

<p>
	سيكون المُوجّه كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-decorator">@app.route('/filters')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">filters</span><span class="hljs-params">()</span>:</span>
        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'filters.html'</span>)</code></pre>

<p>
	المُوجّه بسيط جدّا، والعمل الحقيقي سيكون داخل الملفّ <code>filters.html</code> الذي قدّمناه كجواب في الموجّه.
</p>

<p>
	أنشئ الملفّ <code>filters.html</code> داخل المُجلّد <code>templates</code> المُتواجد في مُجلّد المشروع <code>project</code>.
</p>

<p>
	داخل الملفّ <code>filters.html</code>، أضف ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_tag">{% <span class="hljs-keyword">extends</span> 'base.html' %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> title %}</span><span class="xml"> كلمة  – المُرشّحات  </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">


</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> content %}</span><span class="xml">

<span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> </span><span class="hljs-variable">{{ "Hello World!" | upper() }}</span><span class="xml">  <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span>

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span></code></pre>

<p>
	لاحظ الجزء <code>{{ "Hello World!" | upper() }}</code>، إن تابعت ما سبق جيّدا، فستفهم بأنّنا قُمنا في هذا الجزء بتطبيق المُرشّح <code>upper</code> على السّلسلة النّصيّة <code>Hello World</code> ، وبالطّبع، فإنّك تستطيع أن تُعوّض السّلسلة النّصيّة بمُتغيّر يحمل نفس القيمة أو قيمة أخرى.<br>
	إن زرت العنوان <a href="http://127.0.0.1:5000/filters" rel="external nofollow">http://127.0.0.1:5000/filters</a> فستُلاحظ النّص <code>HELLO WORLD!</code>، ما يعني بأنّ المُرشّح <code>upper</code> قد أدّى مهمّته.
</p>

<h3 id="استعمال-المرشحات-مع-نص-متعدد-الأسطر">
	استعمال المُرشّحات مع نصّ مُتعدّد الأسطر
</h3>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-string">"Hello World!"</span> | <span class="hljs-variable">upper</span>() }}</span></code></pre>

<p>
	لكن ماذا لو أردنا استعمال المُرشّح في جزء أكبر من الشّيفرة؟ كاستعمال المُرشّح <code>upper</code> مع فقرة كاملة أو نص متعدّد الفقرات.<br>
	يُمكننا استخدام المُرشّح كما نستعمل الجملة الشّرطية <code>if</code> أو حلقة <code>for</code> في Jinja، وذلك عبر إحاطة ما نُريد تطبيق المُرشّح عليه بكل من <code>{% filter upper %}</code> و <code>{% endfilter %}</code>، مع تغيير <code>upper</code> بالمُرشّح الذي تُريد استعماله.
</p>

<p>
	المثال التّالي يُمثّل كيفيّة استعمال المُرشّح <code>upper</code> مع نصّ مُتعدّد الأسطر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_tag">{% <span class="hljs-keyword">filter</span> upper() %}</span><span class="xml">
    Hello World!
</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endfilter</span> %}</span></code></pre>

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

<p>
	تعرّفنا في هذا الدّرس كيفيّة استعمال خاصيّة الماكرو في مُحرّك القوالب Jinja لتفادي تكرار شيفرة عدّة مرّات، كما تعرّفنا على ماهيّة مُرشّحات Jinja وكيفيّة استعمالها والهدف منها، في الدّرس التّالي، سنلقي نظرة على بعض من أهمّ المُرشّحات التّي تأتي مبنيّة مُسبقا في مُحرّك القوالب Jinja والتّي يُمكنك استعمالها مُباشرة مع تطبيقات فلاسك الخاصّة بك.
</p>
]]></description><guid isPermaLink="false">440</guid><pubDate>Sat, 25 Mar 2017 21:03:00 +0000</pubDate></item><item><title>&#x62A;&#x642;&#x62F;&#x64A;&#x645; &#x642;&#x648;&#x627;&#x644;&#x628; HTML &#x644;&#x62F;&#x649; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x645;&#x64F;&#x62E;&#x637;&#x651;&#x637;&#x627;&#x62A; Blueprint &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D9%82%D8%AF%D9%8A%D9%85-%D9%82%D9%88%D8%A7%D9%84%D8%A8-html-%D9%84%D8%AF%D9%89-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%8F%D8%AE%D8%B7%D9%91%D8%B7%D8%A7%D8%AA-blueprint-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r438/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.4dad338cea1c2e5852276547c7f5df57.png" /></p>

<p>
	 
</p>

<h2>
	مُقدّمة:
</h2>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23196" data-unique="kr3evu2kq" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.55e4a7a66275811aad43b28808f47aed.png" alt="main2.png"></p>

<h3>
	إنشاء صفحات HTML
</h3>

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

<p>
	مسارات المُجلّدات التّي أنشأناها سابقا هي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cmake"><span class="hljs-keyword">project</span>/templates/
<span class="hljs-keyword">project</span>/posts/templates/
<span class="hljs-keyword">project</span>/users/templates/</code></pre>

<p>
	المسار الأول عبارة عن مجلّد رئيسي للقوالب، يُمكنك أن تعتبره مُشتركا مع القوالب الأخرى، فمثلا يُمكن لكل من ملفّات المقالات والمُستخدمين أن يرثوا من ملفّ <code>base.html</code> كما سنوضّح بعد قليل، كما أنّ أي موجّه يُعرّف داخل الملفّ الرّئيسي <code>project/__init__.py</code> له الحق في تقديم الملفّات المُتواجدة في مجلّد القوالب الرّئيسي مُباشرة.
</p>

<p>
	أي أنّك تستطيع تعديل الموجّه الرّئيسي ليُقدّم القالب <code>index.html</code> المتواجد داخل مجلّد <code>project/templates</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"># project/__init__.py</span>
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template

<span class="hljs-comment">#...</span>
<span class="hljs-comment">#...</span>

<span class="hljs-decorator">@app.route('/') # 127.0.0.1:5000/</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>:</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>) <span class="hljs-comment"># render project/templates/index.html</span></code></pre>

<p>
	لا تنس بأنّنا استردنا أولا الدّالة <code>render_template</code> ثمّ استدعيناها في المُوجّه لتقديم الملفّ <code>index.html</code>.
</p>

<p>
	بنفس الطّريقة سنقوم بتقديم كلّ من ملفّي <code>posts.html</code> الخاصّ بالمقالات و <code>users.html</code> الخاص بالمُستخدمين.
</p>

<p>
	حدّث المُوجّه في مُخطّط المقالات ليُصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"># project/posts/views.py</span>


<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, render_template

<span class="hljs-decorator">@posts.route('/') # 127.0.0.1:5000/posts</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>:</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'posts.html'</span>) <span class="hljs-comment"># render project/posts/templates/posts.html</span>
</code></pre>

<p>
	وهكذا سيكون الموجّه الجديد في المُخطّطات الخاصّة بالمُستخدمين:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"># project/users/views.py</span>


<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, render_template

<span class="hljs-decorator">@users.route('/') # 127.0.0.1:5000/users</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span><span class="hljs-params">()</span>:</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'users.html'</span>) <span class="hljs-comment"># render project/users/templates/users.html</span>
</code></pre>

<p>
	هكذا إن طلب الزّائر أي صفحة من الصّفحات الثّلاث فسيُقدّمُ ملفّ HTML المُناسب.
</p>

<h2 id="استخدام-إطار-bootsrap-لتنسيق-الصفحات">
	استخدام إطار Bootsrap لتنسيق الصّفحات
</h2>

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

<p>
	سنستخدم في هذا المشروع إطار bootsrap 3 الذي يُمكنك تحميله من <a href="http://getbootstrap.com/" rel="external nofollow">الموقع الرّسمي</a> وفك الضّغط عن ملفّ <code>zip</code> داخل مجلّد <code>project/static</code>، سأعتمد كذلك على مشروع Bootsrap-rtl لتعريب وتوجيه التّنسيق من اليمين إلى اليسار وسأضعه في مجلّد <code>project/static/css</code> كما سأضع مكتبة jquery داخل مجلّد <code>project/static/css/bootstrap</code> لذا تأكّد من أنّك قد جهّزت كلّ شيء قبل أن تبدأ في استدعاء الملفّات السّاكنة.
</p>

<p>
	بعد تجهيز مُجلّد <code>static</code> ستكون المُجلّدات والملفّات بداخله كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm">project/static/
├── bootstrap
│   ├── css
│   │   └── bootstrap<span class="hljs-preprocessor">.min</span><span class="hljs-preprocessor">.css</span>
│   └── js
│       ├── bootstrap<span class="hljs-preprocessor">.min</span><span class="hljs-preprocessor">.js</span>
│       └── jquery<span class="hljs-preprocessor">.js</span>
└── css
    ├── bootstrap-rtl<span class="hljs-preprocessor">.min</span><span class="hljs-preprocessor">.css</span>
    └── style<span class="hljs-preprocessor">.css</span></code></pre>

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

<p>
	إذا أردت إضافة ملفّات Javascript أخرى، فيُمكنك إمّا أن تضعها داخل مُجلّد <code>js</code> المُتواجد داخل المُجلّد <code>bootstrap</code> أو أن تُنشئ مُجلّدا جديدا باسم <code>js</code> داخل مُجلّد الملفّات السّاكنة <code>static</code>.
</p>

<h2 id="الوراثة-في-قوالب-jinja2">
	الوراثة في قوالب Jinja2
</h2>

<p>
	لنقل بأنّنا نُريد عرض جملة واحدة في كل ملف من ملفات HTML الثلاثة. يُمكن أن أقوم بما يلي في كل ملفّ:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs xml"><span class="hljs-doctype">&lt;!DOCTYPE html&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">html</span> <span class="hljs-attribute">lang</span>=<span class="hljs-value">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">meta</span> <span class="hljs-attribute">charset</span>=<span class="hljs-value">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">title</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">body</span>&gt;</span>

    Hello

<span class="hljs-tag">&lt;/<span class="hljs-title">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">html</span>&gt;</span></code></pre>

<p>
	مع تعويض <code>Hello</code> بالجملة التّي ارغب في عرضها عند طلب كل موجّه.<br>
	هذه الطّريقة تعمل بشكل جيّد، لكن ألا تُلاحظ بأنّنا سنُكرّر نفس الأسطر في كلّ ملف؟<br>
	عوضا عن تكرار الأسطر في كلّ ملف يُمكننا استعمال مبدأ الوراثة في مجرّك القوالب Jinja.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml">{#  project/templates/base.html #}

<span class="hljs-doctype">&lt;!DOCTYPE html&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">html</span> <span class="hljs-attribute">lang</span>=<span class="hljs-value">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">meta</span> <span class="hljs-attribute">charset</span>=<span class="hljs-value">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">title</span>&gt;</span>{% block title %} {% endblock %}<span class="hljs-tag">&lt;/<span class="hljs-title">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"static"</span>, <span class="hljs-variable">filename</span>=<span class="hljs-string">"bootstrap/js/jquery.js"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"static"</span>, <span class="hljs-variable">filename</span>=<span class="hljs-string">"bootstrap/js/bootstrap.min.js"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">link</span> <span class="hljs-attribute">rel</span>=<span class="hljs-value">"stylesheet"</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"static"</span>, <span class="hljs-variable">filename</span>=<span class="hljs-string">"bootstrap/css/bootstrap.min.css"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">link</span> <span class="hljs-attribute">rel</span>=<span class="hljs-value">"stylesheet"</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"static"</span>, <span class="hljs-variable">filename</span>=<span class="hljs-string">"css/style.css"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-title">link</span> <span class="hljs-attribute">rel</span>=<span class="hljs-value">"stylesheet"</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"static"</span>, <span class="hljs-variable">filename</span>=<span class="hljs-string">"css/bootstrap-rtl.min.css"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">body</span>&gt;</span>

     {% block content %} {% endblock %}


<span class="hljs-tag">&lt;/<span class="hljs-title">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">html</span>&gt;</span></span></code></pre>

<p>
	احفظ الملف وأغلقه.<br>
	لاحظ بأنّنا قمنا باستدعاء جميع الملفّات التّي سنحتاج إليها للتّنسيق وإضافة ميّزات أخرى بلغة Javascript، وقُمنا كذلك بوضع كتلة Block باسم <code>title</code> لتعويضها بالعنوان في كل ملفّ، أمّا كتلة <code>content</code> فهي التّي ستُعوّضُ بالمحتوى (كلمة <code>Hello</code> في مثالنا السّابق).
</p>

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

<p>
	بعد تجهيز الملفّ <code>base.html</code> الذي سيُشكّل قاعدة للملفّات الأخرى، سنُنشئ الآن ثلاثة ملفّات HTML رئيسيّة، وهي كما يلي:
</p>

<ul>
<li>
		<p>
			ملفّ HTML للصّفحة الرّئيسية (مساره <code>project/templates/index.html</code> ).
		</p>
	</li>
	<li>
		<p>
			ملفّ HTML للصّفحة الرّئيسية للمُستخدمين (مساره <code>project/users/templates/users.html</code>).
		</p>
	</li>
	<li>
		<p>
			ملفّ المقالات الرّئيسي (مساره <code>project/posts/templates/posts.html</code>).
		</p>
	</li>
</ul>
<p>
	لملء الملفّات، ضع الشّيفرة التّاليّة في كلّ ملفّ يُمكنك الاستعانة بالمسار المُشار إليه في التّعليق أعلى الشّيفرة للوصول إلى الملفّ بشكل أسرع.
</p>

<p>
	ملفّ الصّفحة الرّئيسية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_comment">{# project/templates/index.html #}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">extends</span> 'base.html' %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> title %}</span><span class="xml"> كلمة  –  الصّفحة الرّئيسية </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> content %}</span><span class="xml">

<span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> مرحبا بك في تطبيق كلمة <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span>
</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">
</span></code></pre>

<p>
	ملفّ الصّفحة الرّئيسية للمُستخدمين:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_comment">{# project/users/templates/users.html #}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">extends</span> 'base.html' %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> title %}</span><span class="xml"> كلمة  – المُستخدمون </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> content %}</span><span class="xml">

<span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> الصّفحة الرّئيسية للمُستخدمين  <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span>

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">
</span></code></pre>

<p>
	ملفّ الصّفحة الرّئيسية للمقالات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_comment">{# project/posts/templates/posts.html #}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">extends</span> 'base.html' %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> title %}</span><span class="xml"> كلمة  – المقالات  </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> content %}</span><span class="xml">

<span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> الصّفحة الرّئيسية للمقالات <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span>

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">
</span></code></pre>

<p>
	كما ترى عوضا عن تكرار الكثير من شيفرات <code>HTML</code> قمنا ببساطة بإنشاء ملفّ واحد والوراثة منه باستخدام الجملة <code>extends 'base.html'</code> وفي كلّ مكان نضع المحتوى المناسب، وبهذه الطّريقة سنمتلك طريقة ديناميكية لتحديد عنوان ومحتوى كلّ موجّه مرتبط بقالب معيّن، بالإضافة إلى أنّ الملفّات السّاكنة مثل ملفّاتcss و js ستكون مُتاحة في جميع الملفّات التّي ترث من الملّف الرّئيسي <code>base.html</code>.
</p>

<p>
	<strong>مُلاحظة:</strong> في بعض المشاريع المكتوبة بلغة بايثون وإطار العمل فلاسك، يُمكن أن يُسمّى الملفّ المُشترك باسم <code>layout.html</code> عوضا عن <code>base.html</code>، لكنّ المبدأ هو نفسه.
</p>

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

<h2 id="الربط-بين-الموجهات-باستخدام-الدالة-urlfor">
	الرّبط بين المُوجّهات باستخدام الدّالة <code>url_for</code>
</h2>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash">url_<span class="hljs-keyword">for</span>(<span class="hljs-string">'index'</span>) <span class="hljs-comment"># /</span>
url_<span class="hljs-keyword">for</span>(<span class="hljs-string">'posts.index'</span>) <span class="hljs-comment"># /posts</span>
url_<span class="hljs-keyword">for</span>(<span class="hljs-string">'users.index'</span>) <span class="hljs-comment"># /users</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash">url_<span class="hljs-keyword">for</span>(<span class="hljs-string">'posts.post_by_id'</span>, post_id = <span class="hljs-number">1</span>)</code></pre>

<p>
	للرّبط بين الموجّهات الثّلاثة التّي سبق وأن أنشأناها سنُضيف ما يلي مُباشرة بعد وسم <code>h1</code> في كل ملفّ من ملفّات HTML حسب المسار في بداية الشّيفرة.
</p>

<p>
	الرّوابط في الصّفحة الرّئيسية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml">{# project/templates/index.html #}

<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"posts.index"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span> اضغط هنا للوصول إلى صفحة المقالات <span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">br</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"users.index"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>اضغط هنا للوصول إلى صفحة المُستخدمين<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span></span></code></pre>

<p>
	رابط العودة إلى الصّفحة الرّئيسية في صفحة المقالات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml">{# project/posts/templates/posts.html #}

<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"index"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>اضغط هنا للعودة إلى الصّفحة الرّئيسيّة<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span>
</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml">{# project/users/templates/users.html #}

<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{ <span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"index"</span>) }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>اضغط هنا للعودة إلى الصّفحة الرّئيسيّة<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span>
</span></code></pre>

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

<h3 id="الربط-بين-الموجهات-مع-تمرير-معاملات-للدالة-التابعة-لكل-موجه">
	الرّبط بين المُوجّهات مع تمرير مُعاملات للدالّة التّابعة لكل موجّه.
</h3>

<p>
	لفهم مبدأ المعاملات أكثر، سنقوم بإضافة موجّه للوصول إلى مقال برقم مُعرّفه في ملفّ <code>project/posts/views.py</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"># project/posts/views.py</span>

<span class="hljs-comment">#..</span>
<span class="hljs-comment">#..</span>


<span class="hljs-decorator">@posts.route('/&lt;int:id&gt;')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post_by_id</span><span class="hljs-params">(id)</span>:</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'post.html'</span>, id = id)
</code></pre>

<p>
	لاحظ بأنّنا خصّصنا المعامل <code>id</code> من نوع <code>int</code> أي عدد صحيح، فإن لم تكن قيمة المُعامل عند الوصول إلى الرّابط عددا صحيحا فإنّ ذلك سيُسبّب خطأ من نوع 404. بمعنى أدق، الرّابط /posts/1 صحيح، أمّا /posts/abc فسيرجع الخطأ ذو الرّقم 404. سنتعرّف على كيفيّة التّعامل مع هذه الأخطاء في درس قادم.
</p>

<p>
	سنضع ما يلي في ملفّ <code>post.html</code> الذي قدّمناه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_tag">{% <span class="hljs-keyword">extends</span> 'base.html' %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> title %}</span><span class="xml"> كلمة  – المقال ذو المُعرّف </span><span class="hljs-variable">{{ id }}</span><span class="xml">  </span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span><span class="xml">

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">block</span> content %}</span><span class="xml">

<span class="hljs-tag">&lt;<span class="hljs-title">h1</span>&gt;</span> صفحة المقال الواحد ذو رقم المُعرّف </span><span class="hljs-variable">{{id}}</span><span class="xml"> <span class="hljs-tag">&lt;/<span class="hljs-title">h1</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-variable">{{ url_for("index") }}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>اضغط هنا للعودة إلى الصّفحة الرّئيسيّة<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span>

</span><span class="hljs-template_tag">{% <span class="hljs-keyword">endblock</span> %}</span></code></pre>

<p>
	لنستخدم الآن الدّالة <code>url_for</code> داخل ملفّ <code>posts.html</code> لضرب مثال على كيفيّة تمرير مُعاملات إلى الدّالة.
</p>

<p>
	أضف ما يلي إلى ملفّ <code>posts.html</code> مُباشرة بعد الوسم <code>&lt;h1&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{<span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"posts.post_by_id"</span>, <span class="hljs-variable">id</span>=1)}}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">h2</span>&gt;</span> رابط المقال الأول <span class="hljs-tag">&lt;/<span class="hljs-title">h2</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-title">a</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"</span></span></span><span class="hljs-expression">{{<span class="hljs-variable">url</span>_<span class="hljs-variable">for</span>(<span class="hljs-string">"posts.post_by_id"</span>, <span class="hljs-variable">id</span>=2)}}</span><span class="xml"><span class="hljs-tag"><span class="hljs-value">"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-title">h2</span>&gt;</span> رابط المقال الثّاني <span class="hljs-tag">&lt;/<span class="hljs-title">h2</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-title">a</span>&gt;</span></span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cs">http:<span class="hljs-comment">//127.0.0.1:5000/posts/1</span>

http:<span class="hljs-comment">//127.0.0.1:5000/posts/2</span>
</code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cs">http:<span class="hljs-comment">//127.0.0.1:5000/posts/99 </span>

http:<span class="hljs-comment">//127.0.0.1:5000/posts/232 </span></code></pre>

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

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

<p>
	تعرّفنا في هذا الدّرس على جزء آخر من أساسيّات تطوير تطبيقات ويب أكثر تعقيدا وذات مهام مُتعدّدة، هذا الدّرس يُمثّل قسما صغيرا فقط ممّا يجب عليك معرفته حول كيفيّة التّعامل مع قوالب HTML ومحرّكها Jinja الذي يُرافق إطار العمل Flask افتراضيّا، لكنّك ستجده في مشاريع بايثون أخرى تتعلّق بتطوير الويب وبعض المجالات الأخرى ولو لم يكن إطار Flask حاضرا، لذا فتعلّم أساسيّات Jinja سيُخوّلك لتعلّم أساسيّات أطر عمل أخرى ومُختلف الأدوات التّي تعتمد عليه بشكل أسرع.
</p>
]]></description><guid isPermaLink="false">438</guid><pubDate>Mon, 20 Mar 2017 21:02:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x645;&#x64F;&#x62E;&#x637;&#x651;&#x637;&#x627;&#x62A; Blueprints &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%85%D9%8F%D8%AE%D8%B7%D9%91%D8%B7%D8%A7%D8%AA-blueprints-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r437/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.ea38349e3c981fa8874df03528af479e.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23197" data-unique="yedirw2fq" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.02e482f56c36cd0fbf5242b60881d706.png" alt="main.png"></p>

<p>
	 
</p>

<h3>
	إنشاء بيئة وهميّة بأداة Pyvenv
</h3>

<p>
	أولا، سنحتاج إلى إنشاء بيئة وهميّة لعزل اعتماديات التّطبيق عن اعتماديات النّظام، وبما أنّ لديك خبرة في لغة بايثون، فلا بد بأنّك تُفكّر في استخدام أداة virtualenv، يُمكنك استخدامها إن أردت، لكنّنا سنستعمل بايثون 3 في تطويرنا لهذا التّطبيق، وإذا اتّبعت <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9%D8%A9-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r401/" rel="">الدّرس</a><br>
	الذي أشرت إليه في الدّرس السّابق، فستعلم بأنّه من المُفضّل استعمال أداة pyvenv للتأكّد من أنّ البيئة الوهميّة ستكون خاصّة بلغة بايثون 3 وليس بايثون 2.
</p>

<p>
	اتّبع الطّريقة التّقليديّة لإنشاء بيئة وهميّة باستعمال أداة <code>pyvenv</code> عبر السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="pln">pyvenv venv</span></code></pre>

<p>
	إذا كنت تستخدم نظام Windows فقد لا يعمل السّطر أعلاه، لكن يُمكنك استخدام الأمر التّالي عوضا عنه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs mel"><span class="hljs-keyword"><span class="pln">python</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln">m venv</span></code></pre>

<p>
	فقط تأكّد من أنّ الأمر <code>python</code> يوصلك إلى مُفسّر بايثون 3 وليس مُفسّر بايثون 2.
</p>

<p>
	بعد انتهاء الأمر من التّنفيذ، قم بتفعيل البيئة الوهميّة بالسّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-built_in"><span class="pln">source</span></span><span class="pln"> venv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></code></pre>

<p>
	بعد تفعيل البيئة الوهميّة، قم بتنصيب إطار العمل Flask باستخدام أداة pip بالسّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cmake"><span class="pln">pip </span><span class="hljs-keyword"><span class="pln">install</span></span><span class="pln"> </span><span class="typ">Flask</span></code></pre>

<p>
	إذا كان السّطر ما قبل الأخير من المُخرجات كما يلي، فهذا يعني بأنّ كل شيء بخير:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="typ">Successfully</span><span class="pln"> installed </span><span class="typ">Flask</span><span class="pln"> itsdangerous </span><span class="typ">Jinja2</span><span class="pln"> </span><span class="typ">Werkzeug</span><span class="pln"> click </span><span class="typ">MarkupSafe</span></code></pre>

<h3 id="طريقة-العمل">
	طريقة العمل
</h3>

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

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

<p>
	مثال على الشّيفرة سيكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/users/views.py</span></span><span class="pln">

</span><span class="hljs-decorator"><span class="lit">@users</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/login'</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">login</span></span><span class="hljs-params"><span class="pun">()</span></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="pun">.</span><span class="pln">
    login_user</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> redirect</span><span class="pun">(</span><span class="pln">url_for</span><span class="pun">(</span><span class="hljs-string"><span class="str">'users.posts_by_author'</span></span><span class="pun">))</span></code></pre>

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

<h3 id="إنشاء-المخططات">
	إنشاء المُخطّطات
</h3>

<p>
	لدينا الآن مُخطّطان في تطبيقنا، واحد في مجلد المُستخدمين والآخر في مُجلّد المقالات.
</p>

<p>
	سنقوم أولا بإنشاء المُخطّط الخاصّ بالمُستخدمين في ملفّ <code>views.py</code> المتواجد داخل المُجلّد <code>users</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/users/views.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">Blueprint</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Blueprint</span><span class="pun">(</span><span class="hljs-string"><span class="str">'users'</span></span><span class="pun">,</span><span class="pln"> __name__</span><span class="pun">,</span><span class="pln"> template_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">,</span><span class="pln"> url_prefix</span><span class="pun">=</span><span class="hljs-string"><span class="str">'/users'</span></span><span class="pun">)</span></code></pre>

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

<p>
	مثلًا لتعريف الموجّه الرّئيسي <code>/</code> سيكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs ruby"><span class="hljs-variable"><span class="lit">@users</span></span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="hljs-string"><span class="str">'/'</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># /users</span></span></code></pre>

<p>
	ولتعريف موجّه التّسجيل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs ruby"><span class="hljs-variable"><span class="lit">@users</span></span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="hljs-string"><span class="str">'/register'</span></span><span class="pun">)</span><span class="pln"> </span><span class="hljs-comment"><span class="com"># /users/register</span></span></code></pre>

<p>
	وكما تُلاحظ، لا أحتاج إلى تعريف <code>/users</code> في بداية كل مُوجّه.
</p>

<p>
	لو لم نُخصّص مُجلّدًا للقوالب، لكان علينا جمع جميع ملفّات HTML في مجلّد <code>project/templates</code>.<br>
	هناك كذلك خيار لتفريق مجلّد الملفّات السّاكنة بنفس الطّريقة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="pln">users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Blueprint</span><span class="pun">(</span><span class="hljs-string"><span class="str">'users'</span></span><span class="pun">,</span><span class="pln"> __name__</span><span class="pun">,</span><span class="pln"> template_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">,</span><span class="pln"> static_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'static'</span></span><span class="pun">,</span><span class="pln"> url_prefix</span><span class="pun">=</span><span class="hljs-string"><span class="str">'/users'</span></span><span class="pun">)</span></code></pre>

<p>
	ولأنّنا سنجمع جميع الملفّات السّاكنة في مُجلّد <code>project/static</code> فهذا الخيار لن يكون مُفيدًا لنا.
</p>

<p>
	يُمكنك الآن إنشاء المُخطّط الخاصّ بالمقالات بنفس الطّريقة.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/posts/views.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">Blueprint</span><span class="pln">

posts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Blueprint</span><span class="pun">(</span><span class="hljs-string"><span class="str">'posts'</span></span><span class="pun">,</span><span class="pln"> __name__</span><span class="pun">,</span><span class="pln"> template_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">,</span><span class="pln"> url_prefix</span><span class="pun">=</span><span class="hljs-string"><span class="str">'/posts'</span></span><span class="pun">)</span></code></pre>

<h3 id="تسجيل-المخططات-مع-التطبيق-الرئيسي">
	تسجيل المُخطّطات مع التّطبيق الرّئيسي
</h3>

<p>
	بعد أن قُمنا بإنشاء مُخطّطات، حان الوقت لإخبار إطار فلاسك بأنّ هذه المُخّططات تابعة للتّطبيق، وطريقة القيام بذلك بسيطة.<br>
	افتح الملف <code>project/__init__.py</code> وضع به ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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="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="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><span class="pln">

</span><span class="hljs-decorator"><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><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">index</span></span><span class="hljs-params"><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">'Project Index'</span></span>
</code></pre>

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

<p>
	أمّا الموجّه الذي عرّفته في الأسفل فهو ليتمكّن المُستخدم من الوصول إلى الصّفحة الرّئيسية دون الحصول على خطأ من نوع 404.<br>
	ذلك لأنّ الموجّهات التّي سنعرّفها في المُخطّطات ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs vhdl"><span class="pun">/</span><span class="pln">posts
</span><span class="pun">/</span><span class="pln">posts</span><span class="pun">/</span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="pln">
</span><span class="pun">/</span><span class="pln">users
</span><span class="pun">/</span><span class="pln">users</span><span class="pun">/</span><span class="hljs-keyword"><span class="kwd">register</span></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></code></pre>

<p>
	لذا إن دخل المُستخدم إلى العنوان 127.0.0.1:5000 فلن يجد شيئا لأنّنا لم نُحدّد الموجّه الرّئيسي <code>/</code>، وهذا هو السّبب الذي جعلنا نُضيف المُوجّه بملفّ <code>__init__.py</code> في مجلّد المشروع <code>project</code>.
</p>

<h3 id="إنشاء-موجهين-رئيسيين">
	إنشاء مُوجّهين رئيسيّين
</h3>

<p>
	قلنا سابقًا بأنّ المُوجّهات ستكون داخل ملفّات <code>views.py</code> فإن أردنا أن نعرّف مثلًا موجّهًا للمقالات الرّئيسية، فسنقوم بذلك في ملّف <code>posts/views.py</code> أمّا الخاص بالمُستخدمين فسيكون في ملفّ <code>users/views.py</code> وهكذا.
</p>

<p>
	سنقوم الآن بإنشاء مُوجّه رئيسي لكل مُخطّط.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/posts/views.py</span></span><span class="pln">

</span><span class="hljs-decorator"><span class="lit">@posts</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="com"># 127.0.0.1:5000/posts</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">index</span></span><span class="hljs-params"><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">'Posts Index'</span></span></code></pre>

<p>
	أمّا المُوجّه الخاصّ بالمُستخدمين فسيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># project/users/views.py</span></span><span class="pln">

</span><span class="hljs-decorator"><span class="lit">@users</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="com"># 127.0.0.1:5000/users</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">index</span></span><span class="hljs-params"><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">'Users Index'</span></span></code></pre>

<p>
	وبهذه التّغييرات سيُصبح الملفّ <code>views.py</code> الخاصّ بالمُستخدمين كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><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">Blueprint</span><span class="pln">

users </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Blueprint</span><span class="pun">(</span><span class="hljs-string"><span class="str">'users'</span></span><span class="pun">,</span><span class="pln"> __name__</span><span class="pun">,</span><span class="pln"> template_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">,</span><span class="pln"> url_prefix</span><span class="pun">=</span><span class="hljs-string"><span class="str">'/users'</span></span><span class="pun">)</span><span class="pln">

</span><span class="hljs-decorator"><span class="lit">@users</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="com"># 127.0.0.1:5000/users</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">index</span></span><span class="hljs-params"><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">'Users Index'</span></span></code></pre>

<p>
	وملفّ <code>views.py</code> الخاص بالمقالات سيكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><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">Blueprint</span><span class="pln">

posts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Blueprint</span><span class="pun">(</span><span class="hljs-string"><span class="str">'posts'</span></span><span class="pun">,</span><span class="pln"> __name__</span><span class="pun">,</span><span class="pln"> template_folder</span><span class="pun">=</span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">,</span><span class="pln"> url_prefix</span><span class="pun">=</span><span class="hljs-string"><span class="str">'/posts'</span></span><span class="pun">)</span><span class="pln">

</span><span class="hljs-decorator"><span class="lit">@posts</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="com"># 127.0.0.1:5000/posts</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">index</span></span><span class="hljs-params"><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">'Posts Index'</span></span></code></pre>

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

<p>
	بعد أن قمنا بتسجيل المُخطّطات وأنهينا أساسيّات التّطبيق، علينا أن نقوم بتشغيل الخادوم لنتمكّن من مُعاينة ما قُمنا به، ولتشغيل التّطبيق، سنضع السّطر المسؤول عن الأمر في ملفّ باسم <code>run.py</code> في مجلّد <code>kalima</code>.
</p>

<p>
	محتويات الملفّ ستكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-comment"><span class="com"># run.py</span></span><span class="pln">

</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"> app

app</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">debug</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pun">)</span></code></pre>

<p>
	كما تُلاحظ، استدعينا الكائن <code>app</code> الذي سبق وأن عرّفناه في ملفّ <code>project/__init__.py</code> بعدها نقوم بتشغيل الخادوم بالطّريقة المُعتادة مع خيار تصحيح الأخطاء.
</p>

<p>
	بعد حفظ ملفّ <code>run.py</code> يُمكنك تشغيله عبر سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs ruby"><span class="hljs-variable"><span class="pln">$ </span></span><span class="pln">python run</span><span class="pun">.</span><span class="pln">py</span></code></pre>

<p>
	ستُلاحظ بأنّ الخادوم قد بدأ بالاشتغال كما العادة، لكنّ طريقة تشغيل الخادوم بهذه الطّريقة غير منصوح بها لأنّ النّسخة رقم 0.11 من Flask التّي أطلقت في أواخر عام 2016 جاءت بطريقة جديدة لتشغيل الخادوم عبر تنفيذ الأمر <code>flask run</code>.
</p>

<p>
	لكن الأمر <code>flask run</code> لن يعمل إلّا بعد تحديد اسم الحزمة أو الوحدة التّي يتواجد بها تطبيق Flask، وذلك عبر تعريف مُتغيّر بيئة باسم <code>FLASK_APP</code> وإعطائه القيمة حسب مكان تواجد تطبيق Flask الخاص بك.<br>
	لتعريف مُتغيّر البيئة يُمكنك تنفيذ الأمر التّالي من الطّرفيّة بعد التّأكد من أنّ البيئة الوهميّة لديك مُفعّلة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="pln">$ </span><span class="hljs-keyword"><span class="kwd">export</span></span><span class="pln"> FLASK_APP</span><span class="pun">=</span><span class="pln">app</span><span class="pun">.</span><span class="pln">py</span></code></pre>

<p>
	في نظام Windows يجب عليك استخدام الكلمة المفتاحيّة <code>set</code> عوضا عن <code>export</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">set</span></span><span class="pln"> FLASK_APP</span><span class="pun">=</span><span class="pln">app</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span></code></pre>

<p>
	في المثال أعلاه، نفترض بأنّ شيفرة تطبيق Flask مُتواجدة في الملفّ <code>app.py</code>.
</p>

<p>
	بعد تعريف مُتغيّر البيئة يُمكنك تشغيل الخادوم عبر تنفيذ الأمر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript"><span class="pln">flask </span><span class="hljs-command"><span class="pln">run</span></span></code></pre>

<p>
	عوضًا عن الأمر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pln">python app</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span></code></pre>

<p>
	في مشروعنا، تطبيق Flask مُتواجد داخل ملفّ <code>__init__.py</code> في مُجلّد <code>project</code> لذا فطريقة تعيين مُتغيّر البيئة سيكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs cmake"><span class="pln">$ </span><span class="hljs-keyword"><span class="kwd">export</span></span><span class="pln"> FLASK_APP</span><span class="pun">=</span><span class="hljs-keyword"><span class="pln">project</span></span><span class="pun">/</span><span class="pln">__init__</span><span class="pun">.</span><span class="pln">py</span></code></pre>

<p>
	بعد تحديد مُتغيّر البيئة، يُمكنك تجربة تشغيل الخادوم:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript"><span class="pln">flask </span><span class="hljs-command"><span class="pln">run</span></span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver"><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Serving</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln"> app </span><span class="hljs-string"><span class="str">"project"</span></span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Running</span><span class="pln"> </span><span class="hljs-command"><span class="hljs-keyword"><span class="pln">on</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">http</span></span><span class="pun">:</span><span class="com">//</span><span class="hljs-title"><span class="com">127</span></span><span class="hljs-number"><span class="com">.0</span></span><span class="hljs-number"><span class="com">.0</span></span><span class="hljs-number"><span class="com">.1</span></span><span class="com">:</span><span class="hljs-title"><span class="com">5000</span></span><span class="com">/ (</span><span class="hljs-title"><span class="com">Press</span></span><span class="com"> </span><span class="hljs-title"><span class="com">CTRL</span></span><span class="com">+</span><span class="hljs-title"><span class="com">C</span></span><span class="com"> </span><span class="hljs-title"><span class="com">to</span></span><span class="com"> </span><span class="hljs-title"><span class="com">quit</span></span><span class="com">)</span></span></code></pre>

<p>
	لتفعيل مُصحّح الأخطاء، كل ما عليك فعله هو تعريف مُتغيّر البيئة <code>FLASK_DEBUG</code> وتعيين القيمة 1 له:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-keyword"><span class="kwd">export</span></span><span class="pln"> FLASK_DEBUG</span><span class="pun">=</span><span class="hljs-number"><span class="lit">1</span></span><span class="pln"> </span></code></pre>

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

<p>
	ومُجدّدًا، استبدل <code>export</code> بالكلمة <code>set</code> إذا كنت تستخدم نظام Windows.
</p>

<p>
	بعد تشغيل الخادوم مع وضع تصحيح الأخطاء، فسيكون المُخرج مُشابها لما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver"><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Serving</span><span class="pln"> </span><span class="typ">Flask</span><span class="pln"> app </span><span class="hljs-string"><span class="str">"project"</span></span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Forcing</span><span class="pln"> debug mode </span><span class="hljs-command"><span class="hljs-keyword"><span class="pln">on</span></span></span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Running</span><span class="pln"> </span><span class="hljs-command"><span class="hljs-keyword"><span class="pln">on</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">http</span></span><span class="pun">:</span><span class="com">//</span><span class="hljs-title"><span class="com">127</span></span><span class="hljs-number"><span class="com">.0</span></span><span class="hljs-number"><span class="com">.0</span></span><span class="hljs-number"><span class="com">.1</span></span><span class="com">:</span><span class="hljs-title"><span class="com">5000</span></span><span class="com">/ (</span><span class="hljs-title"><span class="com">Press</span></span><span class="com"> </span><span class="hljs-title"><span class="com">CTRL</span></span><span class="com">+</span><span class="hljs-title"><span class="com">C</span></span><span class="com"> </span><span class="hljs-title"><span class="com">to</span></span><span class="com"> </span><span class="hljs-title"><span class="com">quit</span></span><span class="com">)</span></span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Restarting</span><span class="pln"> </span><span class="hljs-operator"><span class="kwd">with</span></span><span class="pln"> stat
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Debugger</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> active</span><span class="pun">!</span><span class="pln">
 </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Debugger</span><span class="pln"> pin code</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">573</span></span><span class="pun">-</span><span class="hljs-number"><span class="lit">756</span></span><span class="pun">-</span><span class="hljs-number"><span class="lit">626</span></span></code></pre>

<p>
	وإن أردت أن يصل الآخرون في شبكتك إلى موقعك، تستطيع إضافة <code>--host=0.0.0.0</code> إلى أمر تشغيل الخادوم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript"><span class="pln">flask </span><span class="hljs-command"><span class="pln">run</span></span><span class="pln"> </span><span class="hljs-comment"><span class="pun">--</span><span class="pln">host</span><span class="pun">=</span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span></span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">5000</span><span class="pun">/</span><span class="pln">
</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">5000</span><span class="pun">/</span><span class="pln">posts
</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">5000</span><span class="pun">/</span><span class="pln">users</span></code></pre>

<p>
	وستُلاحظ النّتائج:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs delphi"><span class="typ">Project</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">Index</span></span><span class="pln">

</span><span class="typ">Posts</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">Index</span></span><span class="pln">

</span><span class="typ">Users</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">Index</span></span></code></pre>

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

<p>
	تعرّفنا في الدّرس على كيفيّة إنشاء مُخطّطات وتسجيلها لمرونة أكثر في التّطوير ولإدارة أفضل للتّطبيقات الكبيرة، وتعرّفنا كذلك على كيفيّة تشغيله وكيفيّة إضافة مُوجّه لكل مُخطّط، في الدّرس القادم سنتعرّف على كيفيّة التّعامل مع قوالب HTML وكيفيّة الرّبط بين مُختلف موجّهات التّطبيق.
</p>
]]></description><guid isPermaLink="false">437</guid><pubDate>Wed, 15 Mar 2017 21:04:00 +0000</pubDate></item><item><title>&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x646;&#x638;&#x627;&#x645; &#x644;&#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x645;&#x64F;&#x62D;&#x62A;&#x648;&#x649; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Flask - &#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x645;&#x644;&#x641;&#x651;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x637;&#x644;&#x648;&#x628;&#x629;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%85%D9%8F%D8%AD%D8%AA%D9%88%D9%89-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%84%D9%81%D9%91%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B7%D9%84%D9%88%D8%A8%D8%A9-r435/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.b639e343f77fbb673195fa7e4c4970ee.png" /></p>

<h3>
	مقدّمة
</h3>

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

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23198" data-unique="xqfdwp2jn" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.46c1ce1ca0b903a61844e095832f65a3.png" alt="main.png"></p>

<h3 id="بنية-التطبيق-المعتادة">
	بنية التّطبيق المُعتادة
</h3>

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

<p>
	ملفّات التّطبيق المعتادة تكون على الشّكل التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm">├── app<span class="hljs-preprocessor">.py</span>    <span class="hljs-preprocessor"># ملفّ التّطبيق الرّئيسي</span>
├── config<span class="hljs-preprocessor">.py</span> <span class="hljs-preprocessor"># ملفّ الإعدادات</span>
├── static    <span class="hljs-preprocessor"># مجلّد الملفّات السّاكنة</span>
│   ├── css
│   │   └── style<span class="hljs-preprocessor">.css</span>
│   ├── img
│   │   └── logo<span class="hljs-preprocessor">.png</span>
│   └── js
│       └── main<span class="hljs-preprocessor">.js</span>
├── templates <span class="hljs-preprocessor"># مجلّد القوالب</span>
│   ├── index<span class="hljs-preprocessor">.html</span>
│   ├── posts<span class="hljs-preprocessor">.html</span></code></pre>

<p>
	مادام التّطبيق بسيطا فكلّ شيء سيكون على ما يرام، لكن ماذا لو كان التّطبيق يمتلك قسما لتسجيل المُستخدمين، عرض صفحاتهم الشّخصيّة، عرض المقالات، صفحات الأخطاء (مثل عدم تواجد صفحة أو خطأ بالخادوم …)، لوحة تحكّم للمُدير، لوحات التّحكم بأجزاء التّطبيق، واجهة برمجيّة للمُطوّرين <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وغير ذلك من الخصائص التّي يتمتّع بها كل تطبيق كبير ذو وظائف مُتعدّدة.
</p>

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

<h3 id="المخططات-blueprints">
	المُخطّطات Blueprints
</h3>

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

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

<p>
	هناك نوعان معروفان من المُخطّطات، النّوع الأول يُقسّم ملفّات القوالب مع كلّ وظيفة ليكون كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm">.
├── run<span class="hljs-preprocessor">.py</span>
├── config<span class="hljs-preprocessor">.py</span>
├── project
│   ├── __init__<span class="hljs-preprocessor">.py</span>
│   ├── posts
│   │   ├── __init__<span class="hljs-preprocessor">.py</span>
│   │   ├── templates
│   │   │   ├── index<span class="hljs-preprocessor">.html</span>
│   │   │   ├── post<span class="hljs-preprocessor">.html</span>
│   │   │   ├── posts_by_category<span class="hljs-preprocessor">.html</span>
│   │   ├── views<span class="hljs-preprocessor">.py</span>
│   ├── static
│   │   └── css
│   │       └── style<span class="hljs-preprocessor">.css</span>
│   ├── templates
│   │   ├── base<span class="hljs-preprocessor">.html</span>
│   └── users
│       ├── __init__<span class="hljs-preprocessor">.py</span>
│       ├── templates
│       │   ├── login<span class="hljs-preprocessor">.html</span>
│       │   └── register<span class="hljs-preprocessor">.html</span>
│       ├── views<span class="hljs-preprocessor">.py</span></code></pre>

<p>
	أمّا النّوع الثّاني فتجتمع فيه جميع ملفّات HTML في مُجلّد واحد كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm">.
├── run<span class="hljs-preprocessor">.py</span>
├── config<span class="hljs-preprocessor">.py</span>
├── project
│   ├── __init__<span class="hljs-preprocessor">.py</span>
│   ├── posts
│   │   ├── __init__<span class="hljs-preprocessor">.py</span>
│   │   ├── views<span class="hljs-preprocessor">.py</span>
│   └── users
│       ├── __init__<span class="hljs-preprocessor">.py</span>
│       ├── views<span class="hljs-preprocessor">.py</span>
│   ├── templates
│   │   ├── base<span class="hljs-preprocessor">.html</span>
│   │   ├── posts/
│   │   ├── users/
│   ├── static
│   │   └── css
│   │       └── style<span class="hljs-preprocessor">.css</span></code></pre>

<p>
	في المثالين السّابقين، لدينا مُخطّطان، مُخطّط خاصّ بالمقالات تحت مجلّد posts، وآخر خاصّ بالمُستخدمين في مجلّد users، ملفّ <code>run.py</code> مسؤول عن تشغيل التّطبيق وأمّا ملفّات <code>__ini__.py</code> فهي لجعل بايثون يفهم بأنّ كلّا من مجلّد المشروع <code>project</code> ومجلّدي المقالات والمُستخدمين عبارة عن حزم.
</p>

<p>
	أمّا ملفّا views.py فسيحتويان على الموجّهات المعنيّة بكلّ وظيفة، فمثلا مُوجّه عرض المقالات “/posts” سيكون في ملفّ <code>posts/views.py</code> أمّا موجّه تسجيل دخول المُستخدمين <code>/login</code> فسيكون في ملفّ <code>users/views.py</code>.
</p>

<p>
	لإخبار فلاسك بأنّ مجلّدي posts و users عبارة عن مُخطّطات، سنعرّف أولا كائنًا من صنف Blueprint في كل من ملفّات <code>__init__.py</code> في المُجلّدين، وبعدها سنقوم بتسجيلهما مع تطبيقنا الذي نُعرّفه في ملفّ <code>__init__.py</code> الأساسي -وهو المُتواجد في مجلّد project-.
</p>

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

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

<h3 id="بايثون-3">
	بايثون 3
</h3>

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

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

<p>
	إذا أردت أن تتعلم كيفيّة تجهيز بايثون 3 على نظامك، يُمكنك اتّباع <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AA%D9%88%D8%B2%D9%8A%D8%B9%D8%A9-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r401/" rel="">هذا الدّرس</a>.
</p>

<h3 id="تطبيق-كلمة">
	تطبيق كلمة
</h3>

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

<p>
	في البداية، سننشئ الملفّات التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm">.
├── run<span class="hljs-preprocessor">.py</span>
├── project
│   ├── __init__<span class="hljs-preprocessor">.py</span>
│   ├── posts
│   │   ├── __init__<span class="hljs-preprocessor">.py</span>
│   │   ├── templates
│   │   │   ├── posts<span class="hljs-preprocessor">.html</span>
│   │   ├── views<span class="hljs-preprocessor">.py</span>
│   ├── static
│   │   └── css
│   │       └── style<span class="hljs-preprocessor">.css</span>
│   ├── templates
│   │   ├── base<span class="hljs-preprocessor">.html</span>
│   └── users
│       ├── __init__<span class="hljs-preprocessor">.py</span>
│       ├── templates
│       │   ├── users<span class="hljs-preprocessor">.html</span>
│       │   ├── login<span class="hljs-preprocessor">.html</span>
│       ├── views<span class="hljs-preprocessor">.py</span></code></pre>

<p>
	يُمكنك إمّا إنشاء المُجلّدات والملفّات يدويّا أو عبر نسخ الشيفرة التّالية وحفظها في ملفّ باسم <code>create_app.py</code> لإنشاء الملفّات والمُجلّدات باستعمال لغة بايثون تلقائيّا.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver">import os
import sys


def mkapp(app_name, blueprints):
    dirs = [<span class="hljs-string">'{}'</span>, <span class="hljs-string">'{}/static'</span>, <span class="hljs-string">'{}/static/css'</span>, <span class="hljs-string">'{}/templates'</span>]
    static_files = [<span class="hljs-string">'{s}/css/style.css'</span>]
    templates_files = [<span class="hljs-string">'{t}/index.html'</span>, <span class="hljs-string">'{t}/base.html'</span>]


    <span class="hljs-keyword">for</span> d <span class="hljs-operator">in</span> dirs:
        os.mkdir(d.<span class="hljs-built_in">format</span>(app_name))
    <span class="hljs-built_in">open</span>(app_name + <span class="hljs-string">'/'</span> + <span class="hljs-string">"__init__.py"</span>, <span class="hljs-string">"w"</span>).<span class="hljs-built_in">close</span>() <span class="hljs-comment"># project/__init__.py</span>

    <span class="hljs-keyword">for</span> b <span class="hljs-operator">in</span> blueprints:
        os.mkdir(app_name + <span class="hljs-string">'/'</span> + b) <span class="hljs-comment"># project/posts</span>
        os.mkdir(app_name + <span class="hljs-string">'/'</span> + b + <span class="hljs-string">'/templates'</span>) <span class="hljs-comment"># project/posts/templates</span>
        <span class="hljs-built_in">open</span>(app_name + <span class="hljs-string">'/'</span> + b + <span class="hljs-string">'/'</span> + <span class="hljs-string">"views.py"</span>, <span class="hljs-string">"w"</span>).<span class="hljs-built_in">close</span>() <span class="hljs-comment"># project/posts/views.py</span>
        <span class="hljs-built_in">open</span>(app_name + <span class="hljs-string">'/'</span> + b + <span class="hljs-string">'/'</span> + <span class="hljs-string">"__init__.py"</span>, <span class="hljs-string">"w"</span>).<span class="hljs-built_in">close</span>() <span class="hljs-comment">#project/posts/__init__.py</span>
        <span class="hljs-built_in">open</span>(app_name + <span class="hljs-string">'/'</span> + b + <span class="hljs-string">'/templates/'</span> + b + <span class="hljs-string">".html"</span>, <span class="hljs-string">"w"</span>).<span class="hljs-built_in">close</span>() <span class="hljs-comment"># project/posts/templates/index.html</span>


    <span class="hljs-keyword">for</span> sf <span class="hljs-operator">in</span> static_files:
        static_file = app_name + <span class="hljs-string">'/'</span> + sf.<span class="hljs-built_in">format</span>(s=<span class="hljs-string">'static'</span>) <span class="hljs-comment"># project/static</span>
        <span class="hljs-built_in">open</span>(static_file, <span class="hljs-string">'w'</span>).<span class="hljs-built_in">close</span>()

    <span class="hljs-keyword">for</span> tf <span class="hljs-operator">in</span> templates_files:
        templates_file = app_name + <span class="hljs-string">'/'</span> + tf.<span class="hljs-built_in">format</span>(t=<span class="hljs-string">'templates'</span>) <span class="hljs-comment"># project/templates</span>
        <span class="hljs-built_in">open</span>(templates_file, <span class="hljs-string">'w'</span>).<span class="hljs-built_in">close</span>()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app = sys.argv[<span class="hljs-number">1</span>]
    blueprints = sys.argv[<span class="hljs-number">2</span>:]
    mkapp(app, blueprints)




</code></pre>

<p>
	يُمكنك تنفيذ السكربت بالأمر التّالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs ruby"><span class="hljs-variable">$ </span>python3 create_app.py project posts users</code></pre>

<p>
	بعدها أنشئ ملفّ <code>login.html</code> في مجلّد <code>project/users/templates</code> لأنّ السكربت لن يقوم بإنشائه.
</p>

<p>
	عليك كذلك إنشاء ملفّي <code>run.py</code> و<code>config.py</code> داخل مُجلّد <code>kalima</code>، الملفّ الأول مسؤول عن تشغيل الخادوم/ أمّا الملفّ الثّاني فمسؤول عن إعدادات التّطبيق.
</p>

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

<p>
	تعرّفنا في هذا الدّرس على بنية التّطبيق الذي سنبنيه وكيفيّة توزيع ملفّاته إذ أنشأنا المُجلّدات والملفّات التّي ستكون مسؤولة عن الجانب العملي للتّطبيق، في الدّرس القادم، سنبدأ بتجهيز البيئة البرمجيّة وتنصيب أهم الحزم التّي سنحتاج إليها للبدء بتطوير التّطبيق.
</p>
]]></description><guid isPermaLink="false">435</guid><pubDate>Sun, 12 Mar 2017 21:01:00 +0000</pubDate></item><item><title>&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x646;&#x638;&#x627;&#x645; &#x644;&#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x645;&#x64F;&#x62D;&#x62A;&#x648;&#x649; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Flask &#x648;&#x625;&#x636;&#x627;&#x641;&#x627;&#x62A;&#x647; &#x627;&#x644;&#x645;&#x64F;&#x62E;&#x62A;&#x644;&#x641;&#x629; - &#x645;&#x64F;&#x642;&#x62F;&#x651;&#x645;&#x629;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%85%D9%8F%D8%AD%D8%AA%D9%88%D9%89-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D9%88%D8%A5%D8%B6%D8%A7%D9%81%D8%A7%D8%AA%D9%87-%D8%A7%D9%84%D9%85%D9%8F%D8%AE%D8%AA%D9%84%D9%81%D8%A9-%D9%85%D9%8F%D9%82%D8%AF%D9%91%D9%85%D8%A9-r432/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.d25383618c24832a31d1d16ead725893.png" /></p>

<h2>
	مقدّمة
</h2>

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

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23200" data-unique="jxzzgbs67" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.54da262aa788467555387f95d946bc85.png"></p>

<p style="text-align: center;">
	 
</p>

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

<h2>
	المُتطلّبات
</h2>

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

<h3>
	سلاسل الدّروس التّي يجب عليك أن تطّلع عليها
</h3>

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

<ul>
<li>
		سلسلة <a href="https://academy.hsoub.com/programming/python/flask/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%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%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-r333/" rel="">مدخل إلى إطار العمل Flask</a>
	</li>
	<li>
		درس إنشاء تطبيق لاختصار الرّوابط باستخدام إطار العمل Flask بجزئيه <a href="https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%91%D9%84-r424/" rel="">الأول </a>و <a href="https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D9%91%D8%A7%D9%86%D9%8A-r425/" rel="">الثاني</a>.
	</li>
	<li>
		سلسلة <a href="https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D9%91%D8%AD%D9%82%D9%91%D9%82-%D9%85%D9%86-%D9%85%D9%8F%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A8%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-%D8%B9%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r416/" rel="">التّحقق من مُدخلات المُستخدم باستخدام مكتبة WTForms وإضافة Flask-WTF</a>
	</li>
</ul>
<p>
	ستكون لغة جافاسكربت مُفيدة كذلك، ولا مفرّ من إتقانها إن كنت ترغب بأن تُصبح مُطور ويب أفضل، كما أنّني لن أشرح كل كبيرة وصغيرة عند التّعامل معها في التّطبيق، وهذا لأنّ الهدف من السّلسلة هو تعليمك كيفيّة إتقان التّعامل مع إطار العمل فلاسك وهذا بالطّبع لا يشمل شيفرة جافاسكربت.
</p>

<p>
	ستحتاج كذلك إلى تعلّم أداة Git لإدارة نُسَخ التّطبيق والتّعامل مع التّطبيق بعد نشره على منصّة <a href="https://www.heroku.com/" rel="external nofollow">Heroku</a>.
</p>

<h2>
	ما الذي ستتعلّمه من هذه السّلسلة؟
</h2>

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

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

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

<h2>
	بنية التّطبيق
</h2>

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

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

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

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

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

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

<h2>
	هناك المزيد
</h2>

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

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

<p>
	هذا المقال عبارة عن مُقدّمة بسيطة لما سنخوضه في قادم الدّروس، في الدّرس القادم، ستبدأ المُتعة مع استكشاف كيفيّة التّعامل مع ملفّات ومُجلّدات التّطبيقات الكبيرة والمُعقّدة بطريقة بسيطة.
</p>
]]></description><guid isPermaLink="false">432</guid><pubDate>Thu, 09 Mar 2017 12:10:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x651;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x645;&#x643;&#x62A;&#x628;&#x629; WTForms &#x636;&#x645;&#x646; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Flask: &#x62D;&#x642;&#x648;&#x644; &#x627;&#x644;&#x62E;&#x64A;&#x627;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x64F;&#x62A;&#x639;&#x62F;&#x651;&#x62F;&#x629;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D9%91%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-wtforms-%D8%B6%D9%85%D9%86-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-flask-%D8%AD%D9%82%D9%88%D9%84-%D8%A7%D9%84%D8%AE%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%AA%D8%B9%D8%AF%D9%91%D8%AF%D8%A9-r431/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.8230d9e34a1bed2800220c755456953b.png" /></p>

<h3>
	مُقدّمة
</h3>

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

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22048" data-unique="ts7r0bx01" src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.8d5c84b367b9151e3e5ec8e913040d86.png"></p>

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

<h3 id="إنشاء-وتقديم-قائمة-منسدلة">
	إنشاء وتقديم قائمة مُنسدلة
</h3>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs php"><span class="pln">MA </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">المغرب</span><span class="pln">
AU </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">أستراليا</span><span class="pln">
BH </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">البحرين</span><span class="pln">
DZ </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">الجزائر</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">SelectField</span><span class="pln">

</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">PastebinEntry</span></span><span class="hljs-params"><span class="pun">(</span><span class="typ">Form</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    language </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SelectField</span><span class="pun">(</span><span class="pln">
            </span><span class="hljs-string"><span class="pln">u</span><span class="str">'Programming Language'</span></span><span class="pun">,</span><span class="pln"> 
            choices</span><span class="pun">=[(</span><span class="hljs-string"><span class="str">'cpp'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'C++'</span></span><span class="pun">),</span><span class="pln">
                     </span><span class="pun">(</span><span class="hljs-string"><span class="str">'py'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Python'</span></span><span class="pun">),</span><span class="pln">
                     </span><span class="pun">(</span><span class="hljs-string"><span class="str">'rb'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ruby'</span></span><span class="pun">)]</span><span class="pln">
            </span><span class="pun">)</span></code></pre>

<p>
	يُمكنك أن تُلاحظ بأنّ ما نُمرّره إلى المُعامل <code>choices</code> عبارة عن قائمة بمجموعات من عنصرين، وكما قلت سابقا، فالعنصر الأول هو ما سيصلك عندما يُرسل المُستخدم البيانات، أمّا العنصر الثّاني فسيظهر للمُستخدم لذا إن اختار المُستخدم الخيار Python فما سيصلك أنت عند جانب الخادوم هو السّلسلة النّصيّة <code>'py'</code>.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-variable"><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">language</span><span class="pun">.</span><span class="pln">label</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-variable"><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">language</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"> form</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">language</span></span><span class="pun">.</span><span class="pln">errors </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="pln">errors</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"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">language</span></span><span class="pun">.</span><span class="pln">errors </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><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> error </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="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><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>Python</code> فإنّ قيمة <code>form.language.data</code> ستكون <code>py</code> وبالتّالي ستستطيع مُقارنتها مع قيمة أخرى بسهولة وبشيفرة أقصر.
</p>

<h3 id="حقل-الاختيارات-المتعددة">
	حقل الاختيارات المُتعدّدة
</h3>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">SelectMultipleField</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="pln">language </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SelectMultipleField</span><span class="pun">(</span><span class="pln">
    </span><span class="hljs-string"><span class="pln">u</span><span class="str">'Programming Language'</span></span><span class="pun">,</span><span class="pln"> 
    choices</span><span class="pun">=[(</span><span class="hljs-string"><span class="str">'cpp'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'C++'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="pun">(</span><span class="hljs-string"><span class="str">'py'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Python'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="pun">(</span><span class="hljs-string"><span class="str">'rb'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Ruby'</span></span><span class="pun">)]</span><span class="pln">
    </span><span class="pun">)</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="hljs-variable"><span class="pln">form</span><span class="pun">.</span><span class="pln">language</span></span><span class="pun">(</span><span class="hljs-variable"><span class="pln">size</span></span><span class="pun">=</span><span class="lit">3</span><span class="pun">)}}</span></span></code></pre>

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

<p>
	عندما تُرسل الخيارات فإنّها تكون داخل قائمة بايثون في <code>form.language.data</code> ، وتستطيع الوصول إليها والتّعامل معها كما تتعامل مع قائمة عاديّة.
</p>

<h3 id="أزرار-الانتقاء">
	أزرار الانتقاء
</h3>

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

<p>
	يُمكنك إنشاء حقل لأزرار انتقاء عبر الصّنف <code>RadioField</code> الذي يُمكنك استيراده كذلك من مكتبة WTForms، والتّالي مثال على كيفيّة إنشاء حقل به خياران، <code>Yes</code> و <code>No</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="pln">radio </span><span class="pun">=</span><span class="pln"> </span><span class="typ">SelectField</span><span class="pun">(</span><span class="pln">
 </span><span class="hljs-string"><span class="pln">u</span><span class="str">'Are you happy?'</span></span><span class="pun">,</span><span class="pln">
 choices</span><span class="pun">=[(</span><span class="hljs-string"><span class="str">'yes'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Yes'</span></span><span class="pun">),</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-string"><span class="str">'no'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'No'</span></span><span class="pun">)]</span><span class="pln">
</span><span class="pun">)</span></code></pre>

<p>
	مُجدّدًا، العنصر الأول هو ما سيُرسل إلى الخادوم، أمّا العنصر الثّاني فهو ما يُعرض للمُستخدم.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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"> subfield </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">radio </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">tr</span></span><span class="str">&gt;</span></span><span class="pln">
        </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">td</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> subfield </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">td</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">td</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> subfield</span><span class="pun">.</span><span class="pln">label </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">td</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">tr</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>
	وكما تُلاحظ، فإنّنا نعرض الزرّ ثمّ اللصيقة Label الخاصّة به.
</p>

<h3 id="مربع-التأشير-check-box">
	مُربّع التأشير Check Box
</h3>

<p>
	تُستخدم مُربّعات التّأشير لتمكين المُستخدم من اختيار حقل مُعيّن ليبقى افتراضيّا، مثل مُربّع “تذكّرني” تحت نماذج تسجيل الدّخول، ولأنّه يُعنى بالحصول على المُوافقة أو الرّفض من المُستخدم، فهذا يعني بأنّه يقبل قيمتين منطقيّتين فقط، إمّا أن يؤشّر عليه المُستخدم (أي القيمة المنطقيّة True)، أو يتركه فارغًا ( القيمة المنطقيّة تكون False). لذا ففي WTForms يُمكننا استخدام مُربّع التأشير هذا باستيراد الصّنف <code>BooleanField</code> من المكتبة.
</p>

<p>
	تعريف الحقل يكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="pln">remember_me </span><span class="pun">=</span><span class="pln"> </span><span class="typ">BooleanField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Remember Me'</span></span><span class="pun">)</span></code></pre>

<p>
	وطريقة العرض على صفحة HTML هي نفسها طريقة عرض الحقل السّلسلة النّصيّة القصيرة TextField:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-variable"><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">remember_me</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">form</span><span class="pun">.</span><span class="pln">remember_me</span><span class="pun">.</span><span class="pln">label</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"> form</span><span class="pun">.</span><span class="pln">remember_me</span><span class="pun">.</span><span class="pln">errors </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="pln">errors</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"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">remember_me</span><span class="pun">.</span><span class="pln">errors </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><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> error </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="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><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>

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

<p>
	لذا يُمكنك استخدام شرط منطقي في شيفرتك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs dos"><span class="hljs-flow"><span class="kwd">if</span></span><span class="pln"> form</span><span class="pun">.</span><span class="hljs-comment"><span class="pln">remember_me</span><span class="pun">.</span><span class="pln">data</span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-comment"><span class="pln">remember_user</span><span class="pun">()</span></span></code></pre>

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

<p>
	إن كان المُستخدم قد أشّر على المُربّع فستكون قيمة <code>form.remember_me.data</code> صحيحة وبالتّالي ستُستدعى الدّالة <code>remember_user()</code> وأمّا إن لم يؤشّر المُستخدم على المُربّع فالقيمة ستكون <code>False</code> وبالتّالي سيتم تجاهل ذلك الجزء من الشّيفرة ولن تُستدعى الدّالة <code>remember_user()</code>.
</p>

<h3 id="الوصول-إلى-نوعية-الحقل">
	الوصول إلى نوعيّة الحقل
</h3>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pln">form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">username</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">type</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com">#=&gt; 'TextField'</span></span><span class="pln">
form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">password</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">type</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com">#=&gt; 'PasswordField'</span></span><span class="pln">
form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">remember</span></span><span class="pln">_me</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">type</span></span><span class="pln"> </span><span class="hljs-preprocessor"><span class="com">#=&gt; 'BooleanField'</span></span></code></pre>

<p>
	وكما تُلاحظ فالنّوع يكون اسم الصّنف على شكل سلسلة نصيّة، لذا تستطيع كتابة جملة شرطيّة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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"> field</span><span class="pun">.</span><span class="pln">type </span><span class="pun">==</span><span class="pln"> </span><span class="str">"BooleanField"</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">div</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> field </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"> field</span><span class="pun">.</span><span class="pln">label </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">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">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

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

<h3 id="تفادي-تكرار-شيفرة-عرض-الحقول-باستخدام-الدوال-في-محرك-القوالب-jinja">
	تفادي تكرار شيفرة عرض الحقول باستخدام الدّوال في مُحرّك القوالب Jinja
</h3>

<p>
	هل لاحظت بأنّ هناك الكثير من التّكرار في شيفرة عرض الحقول؟ إن لم تلاحظ بعد، فتأمّل الشّيفرة التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </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">for</span></span><span class="pln"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </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"> error </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><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><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"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </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">for</span></span><span class="pln"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </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"> error </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><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>
	الشّيفرة السّابقة تعرض حقلين فقط، والاختلاف الوحيد بينهما هو أنّ الأول حقل نص قصير، والثّاني حقل كلمة مرور، وسيكون من الجميل إن وضعنا الشّيفرة التّي تتكرّر في دالّة تقبل مُعاملًا يُعبّر عن الحقل.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> macro render_field</span><span class="pun">(</span><span class="pln">field</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">dt</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">label </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">dd</span></span><span class="str">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> field</span><span class="pun">(**</span><span class="pln">kwargs</span><span class="pun">)</span><span class="hljs-filter"><span class="pun">|</span><span class="hljs-keyword"><span class="pln">safe</span></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="kwd">if</span></span><span class="pln"> field</span><span class="pun">.</span><span class="pln">errors </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="pln">errors</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"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> field</span><span class="pun">.</span><span class="pln">errors </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><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> error </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="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><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">dd</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>macro</code>، ثمّ تُحدّد اسمًا له، وتُحدّد المُعاملات التّي يأخذها (في هذه الحالة يأخذ مُعاملًا واحدا يُمثّل الحقل)، بعدها نعرض اللصيقة الخاصّة بالحقل، ثمّ نعرض الحقل مع تمرير المُعاملات المفتاحية Keyword Arguments ونُنبّه مُحرّك القوالب بأنّ هذا الحقل آمن (لأنّ المُحتوى مكتوب بلغة HTML وjinja يقوم بمسح مُكوّنات HTML للتأمين من هجمات XSS)، بعدها يتم التّحقّق من أنّ هناك أخطاء من المُصادقين لعرضها، وستُلاحظ أنّ الماكرو ينتهي بالكلمة المفتاحيّة <code>endmacro</code> للدّلالة على أنّ ذلك الجزء من الشّيفرة قد انتهى.
</p>

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

<p>
	عند استعمالك للماكرو أعلاه، تستطيع تحويل الشّيفرة الطّويلة أعلاه إلى سطرين فقط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">render</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">field</span></span><span class="pun">(</span><span class="hljs-variable"><span class="pln">form</span><span class="pun">.</span><span class="pln">username</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">render</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">field</span></span><span class="pun">(</span><span class="hljs-variable"><span class="pln">form</span><span class="pun">.</span><span class="pln">password</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

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

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

<p>
	في الدّرس القادم، سنتعرّف على كيفيّة التّحقق من مُدخلات المُستخدم باستخدام مبدأ المُصادقين validators الذي تمنحه لنا مكتبة WTForms للتّحقق من أنّ ما يُرسله المُستخدم إلى الخادوم يُطابق صيغة أو شكلا مُعيّنا (كبريد إلكتروني أو مقطع نصي بطول مُحدّد).
</p>
]]></description><guid isPermaLink="false">431</guid><pubDate>Sun, 05 Mar 2017 07:17:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x651;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x645;&#x643;&#x62A;&#x628;&#x629; WTForms &#x636;&#x645;&#x646; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; Flask: &#x62D;&#x642;&#x648;&#x644; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635; &#x648;&#x627;&#x644;&#x623;&#x639;&#x62F;&#x627;&#x62F; &#x648;&#x627;&#x644;&#x62A;&#x648;&#x627;&#x631;&#x64A;&#x62E;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D9%91%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-wtforms-%D8%B6%D9%85%D9%86-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-flask-%D8%AD%D9%82%D9%88%D9%84-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%88%D8%A7%D9%84%D8%A3%D8%B9%D8%AF%D8%A7%D8%AF-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B1%D9%8A%D8%AE-r430/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/36465-Flask-WTF-4.png.02aee4d2157e2d285ca6178b018cd832.png" /></p>

<h2>
	مُقدّمة:
</h2>

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

<p style="text-align: center;">
	<img alt="36465-Flask-WTF-4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22002" data-unique="0e8pwe639" src="https://academy.hsoub.com/uploads/monthly_2017_02/36465-Flask-WTF-4.png.2f2acb6acae398e01320262cffe97004.png" style=""></p>

<h2 id="الحقول-ومكونات-النماذج">
	الحقول ومكوّنات النّماذج
</h2>

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

<h2 id="حقل-النص-القصير-وكلمة-المرور">
	حقل النّص القصير وكلمة المرور.
</h2>

<p>
	سبق وأن استخدمنا حقلي <code>input</code> من نوع <code>text</code> و <code>password</code>، وهذان الحقلان يُسمّيان <code>TextField</code> و <code>PasswordField</code> على التّوالي في مكتبة WTForms.<br>
	ويُمكننا تعريف كل حقل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver"><span class="hljs-keyword"><span class="pln">text</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Text Label'</span></span><span class="pun">)</span><span class="pln">
password </span><span class="pun">=</span><span class="pln"> </span><span class="typ">PasswordField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Password'</span></span><span class="pun">)</span></code></pre>

<p>
	وبالطّبع فسنحتاج إلى استيرادها من مكتبة WTForms :
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PasswordField</span></code></pre>

<p>
	ولتقديمها في ملفّ HTML يُمكنك الاستعانة بمُحرّك القوالب Jinja وعرض كل حقل كالآتي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">form</span><span class="pun">.</span><span class="pln">text</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">form</span><span class="pun">.</span><span class="pln">password</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	وللوصول إلى وسم <code>label</code> كل حقل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">form</span><span class="pun">.</span><span class="pln">text</span><span class="pun">.</span><span class="pln">label</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">form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">label</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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"> form</span><span class="pun">.</span><span class="pln">text</span><span class="pun">.</span><span class="pln">errors </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">for</span></span><span class="pln"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">text</span><span class="pun">.</span><span class="pln">errors </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"> error </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><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><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"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </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">for</span></span><span class="pln"> error </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </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"> error </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><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>

<h2 id="حقل-النص-الطويل-مساحة-النص-text-area">
	حقل النّص الطّويل (مساحة النّص، Text Area)
</h2>

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

<p>
	يُمكنك إنشاء حقل نصّي طويل باستخدام مكتبة WTForms عن<br>
	طريق الصّنف <code>TextAreaField</code>، وبالطّبع فلا بد من استيراده بنفس الطّريقة، لنقوم كالعادة بتعريف مُتغيّر في الصّنف الذي يسترد من الصّنف <code>FlaskForm</code> الذي نسترده في حالتنا من إضافة Flask-WTF، والمثال التّالي عبارة عن نموذج لتمكين المُستخدم من إرسال مقال عن طريق إرسال عنوانه ومُحتواه، والمُحتوى في هذه الحالة هو الحقل الذي سيكون طويلا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title"><span class="kwd">from</span></span><span class="pln"> flask_wtf </span><span class="hljs-import"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">FlaskForm</span></span><span class="pln">
</span><span class="hljs-title"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-import"><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">,</span><span class="pln"> </span><span class="typ">TextAreaField</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">PostForm</span></span><span class="hljs-container"><span class="pun">(</span><span class="hljs-type"><span class="typ">FlaskForm</span></span><span class="pun">)</span></span><span class="pun">:</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-type"><span class="typ">TextField</span></span><span class="hljs-container"><span class="pun">(</span><span class="str">'</span><span class="hljs-type"><span class="str">Title</span></span><span class="str">'</span><span class="pun">)</span></span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-type"><span class="typ">TextAreaField</span></span><span class="hljs-container"><span class="pun">(</span><span class="str">'</span><span class="hljs-type"><span class="str">Content</span></span><span class="str">'</span><span class="pun">)</span></span></span></code></pre>

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

<p>
	وبنفس الطّريقة السّابقة، نقوم بإنشاء كائن من الصّنف <code>PostForm</code> ونقوم بتمريره إلى ملف HTML.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<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">form</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pun">:</span></span><span class="pln">
    form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">PostForm</span><span class="pun">()</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> form</span><span class="pun">.</span><span class="pln">validate_on_submit</span><span class="pun">():</span><span class="pln">   
        title </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">title</span><span class="pun">.</span><span class="pln">data
        content </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">content</span><span class="pun">.</span><span class="pln">data
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render_template</span><span class="pun">(</span><span class="hljs-string"><span class="str">'form.html'</span></span><span class="pun">,</span><span class="pln"> form</span><span class="pun">=</span><span class="pln">form</span><span class="pun">)</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title"><span class="pln">form</span></span><span class="pun">.</span><span class="pln">title</span><span class="pun">.</span><span class="hljs-typedef"><span class="hljs-keyword"><span class="pln">data</span></span></span><span class="pln">
</span><span class="hljs-title"><span class="pln">form</span></span><span class="pun">.</span><span class="pln">content</span><span class="pun">.</span><span class="hljs-typedef"><span class="hljs-keyword"><span class="pln">data</span></span></span></code></pre>

<h2 id="حقل-الأعداد-الصحيحة">
	حقل الأعداد الصّحيحة
</h2>

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

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

<p>
	إليك مثالا على كيفيّة إنشاء نموذج يحمل حقل الأعداد الصّحيحة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> flask_wtf </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">FlaskForm</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">IntegerField</span><span class="pln">

</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">AgeForm</span></span><span class="hljs-params"><span class="pun">(</span><span class="typ">FlaskForm</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    age </span><span class="pun">=</span><span class="pln"> </span><span class="typ">IntegerField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Integer'</span></span><span class="pun">)</span></code></pre>

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

<h2 id="حقل-التاريخ">
	حقل التّاريخ
</h2>

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

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> flask_wtf </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">FlaskForm</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">DateField</span><span class="pln">

</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">AgeForm</span></span><span class="hljs-params"><span class="pun">(</span><span class="typ">FlaskForm</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    age </span><span class="pun">=</span><span class="pln"> </span><span class="typ">DateField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date'</span></span><span class="pun">)</span></code></pre>

<p>
	وطريقة تقديمه بصفحة HTML لا تتغيّر كذلك.
</p>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-string"><span class="str">'%Y-%m-%d'</span></span></code></pre>

<p>
	Y تعني السّنة بصيغتها الكاملة (مثل 1998، 2010، 2016 …).<br>
	m تعني الشّهر.<br>
	D تعني اليوم.<br>
	وبالتّالي فالصّيغة التّالية ستكون مقبولة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="lit">2016</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">13</span></code></pre>

<p>
	أمّا التّاريخ بالصّيغة التّاليّة فغير مقبولة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="lit">13</span><span class="pun">-</span><span class="lit">10</span><span class="pun">-</span><span class="lit">2016</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver"><span class="hljs-built_in"><span class="pln">date</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">DateField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">format</span></span><span class="pun">=</span><span class="hljs-string"><span class="str">'%d/%m/%Y'</span></span><span class="pun">)</span></code></pre>

<p>
	وبالتّالي فعند إدخال التّاريخ على الشّكل التّالي فسيُقبل ويُرسل إلى الخادوم دون مشاكل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="lit">13</span><span class="pun">/</span><span class="lit">10</span><span class="pun">/</span><span class="lit">2016</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs livecodeserver"><span class="hljs-built_in"><span class="pln">date</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">DateField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">format</span></span><span class="pun">=</span><span class="hljs-string"><span class="str">'%Y-%m'</span></span><span class="pun">)</span></code></pre>

<p>
	وبالتّالي فسيكون التّاريخ المقبول كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs "><span class="lit">2016</span><span class="pun">-</span><span class="lit">10</span></code></pre>

<h3 id="معالجة-التاريخ-بعد-استقباله">
	مُعالجة التّاريخ بعد استقباله
</h3>

<p>
	عندما يُدخل المُستخدم التّاريخ ثمّ يصل إلى الخادوم، فتستطيع الوصول إليه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title"><span class="pln">form</span></span><span class="pun">.</span><span class="pln">date</span><span class="pun">.</span><span class="hljs-typedef"><span class="hljs-keyword"><span class="pln">data</span></span></span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pln">form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">date</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">data</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">year</span></span></code></pre>

<p>
	وبنفس الطّريقة، تستطيع الوصول إلى الشّهر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pln">form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">date</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">data</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">month</span></span></code></pre>

<p>
	واليوم:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs avrasm"><span class="pln">form</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">date</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">data</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">day</span></span></code></pre>

<p>
	وكأي كائن من النّوع <code>datetime.date</code> فستتمكّن من الوصول إلى جميع المعلومات الأخرى المُتعلّقة بالتّاريخ.
</p>

<p>
	مُلاحظة:<br>
	الحقل DateField يقوم بإنشاء حقل نص قصير عادي، إن أردت استخدام الحقل الجديد في HTML5 بالخاصيّة <code>type="date"</code>، فتستطيع استيراده من الحزمة html5 في مكتبة WTForms كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> wtforms</span><span class="pun">.</span><span class="pln">fields</span><span class="pun">.</span><span class="pln">html5 </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">DateField</span></code></pre>

<p>
	إن أنشأت حقلا من هذا الصّنف فستحصل على ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs rust"><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"date"</span></span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"date"</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="atn">type</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"date"</span></span><span class="tag">&gt;</span></code></pre>

<p>
	لاحظ بأنّ قيمة الخاصيّة <code>type</code> قد تغيّرت من <code>text</code> إلى <code>date</code> وبالتّالي فستتمكّن من توفير تجربة استخدام أفضل عبر تمكين مُستخدمي تطبيقك من اختيار التّاريخ باستخدام الأداة المتوفّرة في لغة HTML5.
</p>

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

<p>
	تعرّفنا في هذا الدّرس على بعض من المكوّنات الشّائعة في مكتبة WTForms التّي يُمكنك الاستفادة منها في تطبيقاتك لتوفير حماية أفضل، وبما أنّ هناك العديد من الحقول في لغة HTML، فسنتطرّق إلى ما تبقّى في الدّرس التّالي.
</p>
]]></description><guid isPermaLink="false">430</guid><pubDate>Sun, 26 Feb 2017 08:26:00 +0000</pubDate></item><item><title>&#x639;&#x631;&#x636; &#x627;&#x644;&#x646;&#x651;&#x645;&#x627;&#x630;&#x62C; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Jinja &#x648;&#x627;&#x644;&#x648;&#x635;&#x648;&#x644; &#x625;&#x644;&#x649; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x646;&#x645;&#x627;&#x630;&#x62C; WTForms &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D9%86%D9%91%D9%85%D8%A7%D8%B0%D8%AC-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-jinja-%D9%88%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-wtforms-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r421/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtf-03.png.3884295eb0665be7da87c81650e9792a.png" /></p>

<h2>
	مُقدّمة
</h2>

<p>
	تعرّفنا في الدّرسين السّابقين على بعض المفاهيم المُتعلّقة بإدارة نماذج HTML والتّحقق من مُدخلات المُستخدم باستخدام مكتبة WTForms، إذ تعرّفنا على كيفيّة إنشاء صنف يُمثّل نموذج HTML وعلى كيفيّة تقديمه إلى قالب باسم <code>form.html</code>، وقد حان الوقت لنستغلّ إمكانيّات مُحرّك القوالب Jinja لعرض النّموذج والحقول التّي فيه بملفّ HTML وبالتّالي فسيتمكّن المُستخدم من ملء النّموذج من مُتصّفحه وإرسال البيانات إلى الخادوم (تطبيق Flask الخاص بنا)، لنقوم بعد ذلك بالوصول إلى المُدخلات ومُعالجتها.
</p>

<p style="text-align: center;">
	<img alt="flask-wtf-03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21441" data-unique="ylccjajfx" src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtf-03.png.240e226b7d7f497c1ccab035c394f806.png"></p>

<h2 id="أساسيات-عرض-النموذج">
	أساسيّات عرض النّموذج
</h2>

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

<p>
	<em>تذكير:</em> عند التّعامل مع إطار العمل فلاسك فإنّ ملفّات HTML تكون داخل مُجلّد باسم <code>templates</code>.
</p>

<p>
	سيكون مُحتوى ملفّ HTML بسيطا، وأهم شيء هو تقديم الحقول التّي سبق وأن حدّدناها في الصّنف <code>LoginForm</code> أي الحقلين <code>username</code> و <code>password</code> وسنتمكّن من الوصول إليهما كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_7">
<span class="pln">form</span><span class="pun">.</span><span class="pln">username

form</span><span class="pun">.</span><span class="pln">password</span></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<span class="tag">&lt;input</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">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span><span class="pln">


</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span></pre>

<p>
	لو تمعّنت في الشّيفرة أعلاه، ستجد بأنّها حقول HTML عاديّة، وهذا يُعطينا فكرة لكيفيّة استغلالها لعرض الحقول على قالب HTML باستخدام مُحرّك القوالب Jinja.<br>
	ما يعني بأنّنا سنتمكّن من عرض كل حقل على حدة كما يلي:<code class="hljs handlebars"><span class="xml"> </span></code>
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_11">
<span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username </span><span class="pun">}}</span><span class="pln">

</span><span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password </span><span class="pun">}}</span></pre>

<p>
	أمّا لصيقة كل حقل فسنتمكّن من الوصول إليها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_13">
<span class="pln">form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">label

form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">label</span></pre>

<p>
	والتّالي مُحتويات ما سبق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_15">
<span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"username"</span><span class="tag">&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">

</span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"password"</span><span class="tag">&gt;</span><span class="pln">Password</span><span class="tag">&lt;/label&gt;</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_18">
<span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">label </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username </span><span class="pun">}}</span><span class="pln">

</span><span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">label </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password </span><span class="pun">}}</span></pre>

<h3 id="عرض-الأخطاء-التي-ينتجها-المصادقون">
	عرض الأخطاء التّي يُنتجها المُصادقون
</h3>

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

<p>
	حسب ما سبق، فالوصول إلى الحقل يكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_20">
<span class="pln">form</span><span class="pun">.</span><span class="pln">field</span></pre>

<p>
	مع استبدال <code>field</code> باسم الحقل بالطّبع، مثل <code>form.password</code> أو <code>form.username</code>.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_22">
<span class="pln">form</span><span class="pun">.</span><span class="pln">field</span><span class="pun">.</span><span class="pln">errors</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_24">
<span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">field</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> error in form</span><span class="pun">.</span><span class="pln">field</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> error</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_26">
<span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> error in form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</span><span class="pln">
       </span><span class="pun">{{</span><span class="pln"> error </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"> endif </span><span class="pun">%}</span></pre>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_28">
<span class="pln">  </span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> field</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</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="pln">errors</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"> error in field</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</span><span class="pln">
      </span><span class="str">&lt;li&gt;</span><span class="pun">{{</span><span class="pln"> error </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><span class="pln">
  </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span></pre>

<h3 id="إضافة-خصائص-html-إلى-الحقل">
	إضافة خصائص HTML إلى الحقل
</h3>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_30">
<span class="pln">form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">(</span><span class="pln">placeholder</span><span class="pun">=</span><span class="pln"> </span><span class="str">'Enter your username'</span><span class="pun">)</span></pre>

<p>
	النّتيجة ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_32">
<span class="tag">&lt;input</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">placeholder</span><span class="pun">=</span><span class="atv">"Enter your username"</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">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span></pre>

<p>
	ولو أردت مثلا أن تُضيف الخاصيّة <code>required</code> الجديدة في HTML5 فيُمكنك القيام بالأمر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_34">
<span class="pln">form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">(</span><span class="pln">placeholder</span><span class="pun">=</span><span class="pln"> </span><span class="str">'Enter your username'</span><span class="pun">,</span><span class="pln"> required </span><span class="pun">=</span><span class="pln"> </span><span class="typ">True</span><span class="pun">)</span></pre>

<p>
	والنّتيجة ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_36">
<span class="tag">&lt;input</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">placeholder</span><span class="pun">=</span><span class="atv">"Enter your username"</span><span class="pln"> </span><span class="atn">required</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">value</span><span class="pun">=</span><span class="atv">""</span><span class="tag">&gt;</span></pre>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_38">
<span class="pln">form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">(</span><span class="pln">placeholder</span><span class="pun">=</span><span class="pln"> </span><span class="str">'Enter your username'</span><span class="pun">,</span><span class="pln"> required </span><span class="pun">=</span><span class="pln"> </span><span class="typ">True</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Default Value'</span><span class="pun">)</span></pre>

<p>
	النّتيجة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_40">
<span class="tag">&lt;input</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">placeholder</span><span class="pun">=</span><span class="atv">"Enter your username"</span><span class="pln"> </span><span class="atn">required</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">value</span><span class="pun">=</span><span class="atv">"Default Value"</span><span class="tag">&gt;</span></pre>

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

<h2 id="عرض-النموذج-على-صفحة-html-باستعمال-محرك-القوالب-jinja">
	عرض النّموذج على صفحة HTML باستعمال مُحرّك القوالب Jinja
</h2>

<p>
	<strong>تذكير:</strong> الشّيفرة التّالية تُمثّل الجزء المسؤول عن تمرير الكائن <code>form</code> إلى الملف <code>form.html</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_42">
<span class="pln">render_template</span><span class="pun">(</span><span class="str">'form.html'</span><span class="pun">,</span><span class="pln"> form </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">)</span></pre>

<p>
	انطلاقا من الكائن <code>form</code> سنتمكّن من الوصول إلى كل من الحقلين <code>username</code> و <code>password</code> في ملف HTML وسنتمكّن من عرضها وعرض أسمائها والأخطاء التّي يُصدرها كل مُصادق.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_44">
<span class="pun">&lt;</span><span class="pln">form method</span><span class="pun">=</span><span class="str">'post'</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="pun">{{</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">hidden_tag</span><span class="pun">()</span><span class="pln"> </span><span class="pun">}}</span><span class="pln">

    </span><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">label</span><span class="pun">}}</span><span class="pln">
    </span><span class="str">&lt;br&gt;</span><span class="pln">
    </span><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">username</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"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</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="pln">errors</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"> error in form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</span><span class="pln">
               </span><span class="str">&lt;li&gt;</span><span class="pun">{{</span><span class="pln"> error </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><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
    </span><span class="str">&lt;br&gt;</span><span class="pln">
    </span><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">label</span><span class="pun">}}</span><span class="pln">
    </span><span class="str">&lt;br&gt;</span><span class="pln">
    </span><span class="pun">{{</span><span class="pln">form</span><span class="pun">.</span><span class="pln">password</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"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</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="pln">errors</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"> error in form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">errors </span><span class="pun">%}</span><span class="pln">
               </span><span class="str">&lt;li&gt;</span><span class="pun">{{</span><span class="pln"> error </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><span class="pln">
    </span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">
    </span><span class="str">&lt;br&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'submit'</span><span class="pln"> value</span><span class="pun">=</span><span class="str">'Login'</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	كل ما فعلناه هو أنّنا جمعنا جميع القطع التّي شرحتها أعلاه مع الفصل بينها بفواصل <code>&lt;br&gt;</code>، إذ نقوم أولا بإنشاء وسم النّموذج <code>&lt;form&gt;</code> مع تحديد نوع الطّلب <code>post</code> ثمّ نقوم بإغلاق الوسم في آخر الملف.
</p>

<p>
	داخل وسمي <code>&lt;form&gt;&lt;/form&gt;</code>، سنقوم بتحديد الحقل الخفي الذي سيُمكّننا من تفادي هجمات CSRF عن طريق استدعاء التّابع <code>hidden_tag</code>، وبالتّالي ففي كل مرّة يُرسل فيها مُستخدم بياناته فستُرسل البيانات في الحقول مع الحقل الخفي ثمّ يتم التّحقق منه.
</p>

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

<p>
	وفي الأخير نضيف زرا ليتمكّن المُستخدم من إرسال البيانات.
</p>

<p>
	وهكذا سيُصبح النّموذج كما في الصّورة التّالية:
</p>

<p style="text-align: center;">
	<img alt="001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21440" data-unique="ekvavbeze" src="https://academy.hsoub.com/uploads/monthly_2017_02/001.png.e7dda79a226fcf4977313b99fac112a0.png"></p>

<p>
	وإن حاولت إرسال النّموذج دون ملئ الحقول فستحصل على خطئ من المصادق DataRequired :
</p>

<p style="text-align: center;">
	<img alt="002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21438" data-unique="idfszmnn1" src="https://academy.hsoub.com/uploads/monthly_2017_02/002.png.aaec7ccb377dea5cb7a80ffb31c9f99d.png"></p>

<p>
	وإن ملأت حقلا وتركت آخر، فالخطأ يظهر عند الحقل الفارغ فقط:
</p>

<p style="text-align: center;">
	<img alt="003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21439" data-unique="5ev77b47e" src="https://academy.hsoub.com/uploads/monthly_2017_02/003.png.390d2dc02b26412e6c407bd7ec88c0a9.png"></p>

<p>
	يُمكنك كذلك النّظر إلى مصدر الصّفحة إن أردت تفحّص ما تُنتجه مكتبة WTForms من حقول.
</p>

<p>
	وإليك الجزء الخاص بالحقل الخفي الذي يُستعمل للحماية من هجمات CSRF.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_47">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">display</span><span class="pun">:</span><span class="pln">none</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"csrf_token"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"csrf_token"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"hidden"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"1476126948##ffc7d39e3fe6820d20f495ec6d0be1772ea6f647"</span><span class="tag">&gt;&lt;/div&gt;</span></pre>

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

<h3 id="الوصول-إلى-البيانات-التي-يرسلها-المستخدم">
	الوصول إلى البيانات التّي يُرسلها المُستخدم
</h3>

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

<p>
	في السّابق كنّا نصل إلى ما يُرسله المُستخدم عن طريق القاموس <code>form</code> المُتواجد بالوحدة <code>request</code> التّي نقوم باستيرادها من حزمة إطار العمل Flask، ويحدث هذا إذا وفقط إذا كان نوع الطّلب هو <code>POST</code> وليس الطّلب <code>GET</code>، إذ نضع البيانات في مُتغيّرات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_49">
<span class="kwd">if</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">method </span><span class="pun">==</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">:</span><span class="pln">
    username </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">form</span><span class="pun">[</span><span class="str">'username'</span><span class="pun">]</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">form</span><span class="pun">[</span><span class="str">'password'</span><span class="pun">]</span><span class="pln">
    pass</span></pre>

<p>
	ثمّ نقوم بمُعالجة البيانات عوضا عن الكلمة المفتاحيّة <code>pass</code>.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_51">
<span class="pln">form</span><span class="pun">.</span><span class="pln">field</span><span class="pun">.</span><span class="pln">data</span></pre>

<p>
	مع تغيير <code>field</code> باسم الحقل، وعوضا عن الوصول إلى البيانات إذا كان الطّلب من النّوع <code>POST</code> فإنّنا نقوم بذلك إذا أرجع التّابع <code>validate_on_submit</code> القيمة المنطقيّة <code>True</code>.
</p>

<p>
	لذا فالشّيفرة السّابقة ستكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_53">
<span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">validate_on_submit</span><span class="pun">():</span><span class="pln">
    username </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">data
    password </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">data
    pass</span></pre>

<p>
	مع مُلاحظة أنّ التّابع <code>validate_on_submit</code> يُرجع القيمة True إذا كان الطّلب من نوع POST ولم تصدر أية أخطاء من المُصادقين، أي أنّ المُستخدم قد ضغط على زر الإرسال وأنّ الحقول آمنة وأنّ التّحقق منها قد تم بنجاح.
</p>

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

<p>
	وبهذا يُصبح المُوجّه الخاص بنا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6413_55">
<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"> methods</span><span class="pun">=[</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">])</span><span class="pln">
def form</span><span class="pun">():</span><span class="pln">
    form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">validate_on_submit</span><span class="pun">():</span><span class="pln">   
        username </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">username</span><span class="pun">.</span><span class="pln">data
        password </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">password</span><span class="pun">.</span><span class="pln">data
        </span><span class="kwd">if</span><span class="pln"> username </span><span class="pun">==</span><span class="pln"> </span><span class="str">"admin"</span><span class="pln"> and password </span><span class="pun">==</span><span class="pln"> </span><span class="str">"123456"</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Logged in'</span><span class="pln">
        </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Invalid'</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render_template</span><span class="pun">(</span><span class="str">'form.html'</span><span class="pun">,</span><span class="pln"> form </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">)</span></pre>

<p>
	<em>مُلاحظة:</em> في التّطبيقات الواقعيّة، يجب عليك دائما أن تُعيد توجيه المُستخدم إلى صفحة أخرى عند الانتهاء مُباشرة من مُعالجة البيانات تفاديا للنافذة التّنبيهيّة التّي تظهر عند مُحاولة إعادة تحميل الصّفحة. إن أردت الاستزادة عن هذا الموضوع فيُمكنك زيارة <a href="https://en.wikipedia.org/wiki/Post/Redirect/Get" rel="external nofollow">هذه الصّفحة</a>
</p>

<h1 id="خاتمة">
	خاتمة:
</h1>

<p>
	وهكذا نكون قد تعرّفنا على كيفيّة استغلال مكتبة WTForms و إضافة Flask-WTF لإنشاء ومُعالجة نماذج HTML بشكل أكثر أمانا وأكثر سهولة، سنتعرّف في ما يلي من الدّروس على كيفيّة استغلال مكتبة WTForms لإدارة حقول ومكوّنات HTML الأخرى مثل القوائم المُنسدلة ومربّعات الاختيار وغيرها، وسنتعرّف كذلك على مُصادقين آخرين لتوفير حماية أكثر لتطبيقاتنا.
</p>
]]></description><guid isPermaLink="false">421</guid><pubDate>Wed, 15 Feb 2017 06:53:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x651;&#x62D;&#x642;&#x651;&#x642; &#x645;&#x646; &#x645;&#x64F;&#x62F;&#x62E;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x64F;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x645;&#x643;&#x62A;&#x628;&#x629; WTForms &#x639;&#x644;&#x649; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D9%91%D8%AD%D9%82%D9%91%D9%82-%D9%85%D9%86-%D9%85%D9%8F%D8%AF%D8%AE%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A8%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-%D8%B9%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r416/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtf-02.png.61bd7555b12501de765f661521f59f0b.png" /></p>

<h2>
	مُقدّمة:
</h2>

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

<p style="text-align: center;">
	<img alt="flask-wtf-02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21142" data-unique="9w25l9yqu" src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtf-02.png.cbfe8d252c659a39e6231846f93179b8.png"></p>

<h1 id="كيف-تعمل-مكتبة-wtforms">
	كيف تعمل مكتبة WTForms ؟
</h1>

<p>
	من المهم أن تدرك بأنّ استخدام مكتبة WTForms يكون على عدّة مراحل:
</p>

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

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

<h2 id="تعريف-الصنف-المسؤول-عن-النموذج">
	تعريف الصّنف المسؤول عن النّموذج
</h2>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6861_7">
<span class="pln">from flask_wtf </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">FlaskForm</span><span class="pln">

from wtforms </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PasswordField</span><span class="pln">
from wtforms</span><span class="pun">.</span><span class="pln">validators </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">DataRequired</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pun">(</span><span class="typ">FlaskForm</span><span class="pun">):</span><span class="pln">
    username </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">(</span><span class="str">'Username'</span><span class="pun">,</span><span class="pln"> validators</span><span class="pun">=[</span><span class="typ">DataRequired</span><span class="pun">()])</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> </span><span class="typ">PasswordField</span><span class="pun">(</span><span class="str">'Password'</span><span class="pun">,</span><span class="pln"> validators</span><span class="pun">=[</span><span class="typ">DataRequired</span><span class="pun">()])</span></pre>

<p>
	نسترد أولا الصّنف <code>FlaskForm</code> الذي تحدّثنا عنه سابقا في الدّرس السّابق من إضافة Flask-WTF، بعدها نقوم باستيراد <code>TextField</code> الذي يُعبّر عن حقل نصي في نماذج HTML، أي بمعنى آخر، الوسم <code>&lt;input&gt;</code> مع الخاصيّة <code>type=text</code>، ونسترد كذلك الصّنف الذي يُسمى <code>PasswordField</code> الذي يعتبر حقلا لكلمة المرور أي الوسم <code>&lt;input&gt;</code> مع الخاصيّة <code>type=password</code> في لغة HTML، ولاحظ بأنّنا نسترد هذه الأصناف التّي تٌعبّر عن الحقول من مكتبة WTForms وليس من إضافة Flask-WTF.<br>
	بعدها نقوم باستيراد المُصَادِق <code>DataRequired</code> من الوحدة <code>validators</code> المتواجدة بالمكتبة WTForms، سيُمكّننا هذا المُصادق من التّحقق من أنّ الحقل لا يحمل قيمة فارغة عند إرسال البيانات (بمعنى آخر، سيُصبح الحقل مطلوبا).
</p>

<p>
	بعد استيراد ما نحتاج إليه، سنقوم بإنشاء صنف باسم <code>LoginForm</code> ليُمثّل النّموذج الخاص بتسجيل الدّخول، لاحظ بأنّ هذا الصّنف يرث من الصّنف <code>FlaskForm</code> الذي قمنا باستيراده من إضافة Flask-WTF.
</p>

<p>
	وبما أنّ النّموذج سيحتوي حقلين فقط، حقل لاسم المُستخدم وحقل آخر لكلمة المرور، ثمّ زر لتأكيد وإرسال البيانات Submit button، فقد قمنا بتعريفهما داخل الصّنف، إذ عرّفنا أولا حقل اسم المُستخدم بتعريف مُتغيّر باسم <code>username</code> ليكون كائنا من الصّنف <code>TextField</code> مع تمرير مُعاملين، الأول عبارة عن سلسلة نصيّة تُمثّل لصيقة الحقل أو Field Label، أمّا المُعامل الآخر فعبارة عن قائمة بالمُصادقين، وفي حالتنا فإنّ القائمة تحتوي على مُصادق واحد فقط وهو <code>DataRequired()</code> لجعل الحقل مطلوبا (أي منع المُستخدم من إرسال الحقل فارغا).<br>
	نقوم بنفس الشيء مع حقل كلمة المرور، مع جعل الكائن من الصّنف <code>PasswordField</code> لتظهر مُدخلات المُستخدم على شكل نجمات عوضا عن نص واضح، كما أنّنا نُشير إلى أنّه حقل مطلوب كذلك عبر تمرير <code>DataRequired</code> كعنصر من قائمة إلى المُعامل <code>validators</code>.<br>
	بالنّسبة لزر إرسال البيانات فسنقوم بكتابته مُباشرة بلغة HTML في ملفّ القالب.
</p>

<h3 id="أين-توضع-الشيفرة-المسؤولة-عن-النماذج">
	أين توضع الشّيفرة المسؤولة عن النّماذج؟
</h3>

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

<p>
	لكن من المُفضّل دائما اتّباع أفضل المُمارسات Best practices وهي ما يقوم به الجميع والمنصوح به لتوفير طريقة تطوير موحّدة ولتسهيل قراءة شيفرتك على الآخرين، وأفضل ممارسة في ما يتعلّق بالأصناف المسؤولة عن نماذج HTML هي بوضع الشّيفرة المسؤولة عن النّماذج في ملف باسم <code>forms.py</code> داخل مُجلّد التّطبيق لتوفير تقسيم منظّم للشّيفرة.
</p>

<h2 id="تقديم-النموذج-من-الموجه-إلى-قالب-html">
	تقديم النّموذج من المُوجّه إلى قالب HTML
</h2>

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

<p>
	لتبسيط الأمور، سأجمع الصّنف <code>LoginForm</code> و شيفرة التّطبيق في نفس الملف، وسيكون التّطبيق بسيطا ليفهمه الجميع.<br>
	الشّيفرة الكاملة ستكون كالتّالي (قمت بفصل شيفرة النّموذج وشيفرة التّطبيق بفاصل صغير):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6861_9">
<span class="pln">from flask_wtf </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">FlaskForm</span><span class="pln">

from wtforms </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PasswordField</span><span class="pln">
from wtforms</span><span class="pun">.</span><span class="pln">validators </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">DataRequired</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pun">(</span><span class="typ">FlaskForm</span><span class="pun">):</span><span class="pln">
    username </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">(</span><span class="str">'Username'</span><span class="pun">,</span><span class="pln"> validators</span><span class="pun">=[</span><span class="typ">DataRequired</span><span class="pun">()])</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> </span><span class="typ">PasswordField</span><span class="pun">(</span><span class="str">'Password'</span><span class="pun">,</span><span class="pln"> validators</span><span class="pun">=[</span><span class="typ">DataRequired</span><span class="pun">()])</span><span class="pln">

</span><span class="com"># ---------------------------</span><span class="pln">

from flask </span><span class="kwd">import</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="str">'SECRET_KEY'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'T\x1f\x85\x9b\xfe^\x0f\x14\x9f\xa3x\xa4\xb5\x92\xbe'</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">'/'</span><span class="pun">,</span><span class="pln"> methods</span><span class="pun">=[</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">])</span><span class="pln">
def form</span><span class="pun">():</span><span class="pln">
    form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">validate_on_submit</span><span class="pun">():</span><span class="pln">   
        </span><span class="com"># Handle received data</span><span class="pln">
        pass

    </span><span class="kwd">return</span><span class="pln"> render_template</span><span class="pun">(</span><span class="str">'form.html'</span><span class="pun">,</span><span class="pln"> form </span><span class="pun">=</span><span class="pln"> form</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">
    app</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">debug</span><span class="pun">=</span><span class="typ">True</span><span class="pun">)</span></pre>

<p>
	كما تُلاحظ أعلاه، قمنا بإنشاء تطبيق بسيط نسترد فيه كلا من الصّنف <code>Flask</code> والدّالة <code>render_template</code>، ثمّ ننشئ الكائن <code>app</code> وبعدها نقوم بتحديد مفتاح سري لتتمكّن مكتبة WTForms من توليد حقل خفي للحماية من هجمات CSRF، وبعدها نقوم بتعريف المُوجّه ونُشغّل الخادوم في آخر سطرين.
</p>

<p>
	أهم شيء في التّطبيق هو الموجّه الرّئيسي ومُحتوى الدّالة <code>form</code> التي سنقوم من خلالها بتقديم ومُعالجة النّموذج وبياناته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6861_11">
<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"> methods</span><span class="pun">=[</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">])</span><span class="pln">
def form</span><span class="pun">():</span><span class="pln">
    form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> form</span><span class="pun">.</span><span class="pln">validate_on_submit</span><span class="pun">():</span><span class="pln">
        </span><span class="com"># Handle received data</span><span class="pln">
        pass

    render_template</span><span class="pun">(</span><span class="str">'form.html'</span><span class="pun">,</span><span class="pln"> form</span><span class="pun">=</span><span class="pln">form</span><span class="pun">)</span></pre>

<p>
	أولا نقوم بتحديد أنواع الطّلبات التّي سيقبلها المُوجّه بتمرير قائمة إلى المعامل <code>methods</code> لإخبار فلاسك بأنّ هذا المُوجّه سيستقبل كلا من طلبات <code>GET</code> التّي ستُقدّم النّموذج وطلبات <code>POST</code> التّي ستستقبل ومن ثمّ نُعالجها البيانات.<br>
	بعدها نقوم بتعريف الكائن <code>form</code> من الصّنف <code>LoginForm</code>، يُمكنك الآن تجاهل الشّرط <code>if form.validate_on_submit()</code> لأنّه يهتم بمُعالجة البيانات والمُصادقة عليها ولن نقوم بُمعالجتها حاليا لكن عليك أن تعلم بأنّ المُعالجة ستتمّ في مكان التّعليق <code>Handle received data</code>، في الأخير نقوم بتقديم الملفّ <code>form.html</code> مع تمرير الكائن <code>form</code> لنتمكّن من الوصول إليه في القالب.
</p>

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

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

<p>
	 
</p>
]]></description><guid isPermaLink="false">416</guid><pubDate>Tue, 07 Feb 2017 10:04:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x645;&#x643;&#x62A;&#x628;&#x629; WTForms &#x644;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x646;&#x645;&#x627;&#x630;&#x62C; HTML &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtforms.png.7a0aed8e0128fe385e104a456c46ce48.png" /></p>

<h2>
	مقدّمة
</h2>

<p>
	بعد أن تعرّفنا على كيفيّة التّعامل مع قاعدة بياناتنا لإجراء العمليّات الشّائعة مثل الإضافة، القراءة والحذف في سلسلة <a href="https://academy.hsoub.com/tags/flask%20101/" rel="">مدخل إلى إطار العمل Flask</a> فقد حان الوقت للانتقال إلى مبدأ آخر من مبادئ تطوير الويب، ألا وهو كيفيّة التّحقق من مُدخلات المُستخدم، وسنتعرّف معا في هذا الدّرس على كيفيّة استغلال كل ما تعلّمناه لنُمكّن المُستخدم الذي يستعمل تطبيقنا من إرسال بياناته إلى التّطبيق بطريقة آمنة، ومن ثمّ ستتمكّن أنت من استغلال ما ستتعلّمه لإدخال هذه البيانات إلى قواعد بيانات تطبيقاتك، وخلال هذا المشوار سنعرّف على كيفيّة مُعالجة نماذج HTML ليُرسلها المستخدم إلى الخادوم عن طريق صفحة HTML، وذلك باستخدام كل من مكتبة WTForms و إضافة Flask-WTF التّي تُسهّل لنا التّعامل مع المكتبة، والغرض من كل هذا هو التّعرف على كيفيّة إنشاء وإدارة النّماذج لاستعمالها في مختلف الصّفحات في تطبيقاتك (صفحة تسجيل الدّخول، صفحة تسجيل مستخدمين جدد، صفحة إضافة مقال …).
</p>

<p style="text-align: center;">
	<img alt="flask-wtforms.png" class="ipsImage ipsImage_thumbnailed" data-fileid="20957" data-unique="301krd2u7" src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-wtforms.png.6e9d27092767c2ab94f1207a9e5dc67f.png" style=""></p>

<h1 id="المتطلبات">
	المُتطلّبات
</h1>

<p>
	يُعتبر هذا الدّرس مُقدّمة لسلسلة جديدة حول كيفيّة إدارة نماذج HTML عند استخدام لغة بايثون وإطار العمل Flask لبناء تطبيقات الويب، لذا فسيتوجّب عليك فهم أساسيّات إطار العمل وكذا فهم آليّة عمل نماذج HTML أو HTML Forms.<br>
	إن لم تكن لك خبرة في التّعامل مع إطار العمل Flask فأنصحك بهذه <a href="https://academy.hsoub.com/tags/flask%20101/" rel=""> السّلسلة من الدّروس</a>.
</p>

<h1 id="لماذا-wtforms">
	لماذا WTForms
</h1>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4955_7">
<span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/login'</span><span class="pun">,</span><span class="pln"> methods </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'POST'</span><span class="pun">])</span><span class="pln">
def login</span><span class="pun">():</span><span class="pln">
    username </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">form</span><span class="pun">[</span><span class="str">'username'</span><span class="pun">]</span><span class="pln">
    password </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">form</span><span class="pun">[</span><span class="str">'password'</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> username </span><span class="pun">==</span><span class="pln"> </span><span class="str">'admin'</span><span class="pln"> and password </span><span class="pun">==</span><span class="pln"> </span><span class="str">'admin'</span><span class="pun">:</span><span class="pln">
        </span><span class="com"># login the user ...</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> redirect</span><span class="pun">(</span><span class="pln">url_for</span><span class="pun">(</span><span class="str">'index'</span><span class="pun">))</span></pre>

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

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

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

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

<h2 id="الحماية-من-هجمات-csrf">
	الحماية من هجمات CSRF
</h2>

<p>
	بالإضافة إلى مُساعدتنا على تأكيد البيانات وتقييدها بشروط خاصّة، فمكتبة WTForms تحمينا من هجمات CSRF (اختصار لـ Cross-site request forgery)، وترجمته ‘تزوير الطلب عبر المواقع’، وهي نوع معيّن من الهجمات تُمكّن المخترق من القيام بأمور خطيرة متنكّرا على هيئة المُستخدم الضّحيّة (الذي قد سجّل دخوله بتطبيقك)، وقد استخدمت هذه الهجمة من قبل لتحويل أموال بشكل غير شرعي من طرف مُخترق لأحد الأبناك في السّابق، وظهرت هذه الثّغرة من قبل في موقع Youtube ما خوّل للمُخترق بالقيام بجميع العمليّات التّي يُمكن أن يقوم بها المُستخدم الذي سجّل دخوله، ويُمكنك زيارة <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="external nofollow">صفحة ويكيبيديا</a> عن الهجمة لمزيد من المعلومات.
</p>

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

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

<h2 id="التحقق-من-المدخلات-بالواجهة-الأمامية-أم-الواجهة-الخلفية">
	التّحقق من المُدخلات بالواجهة الأماميّة أم الواجهة الخلفيّة؟
</h2>

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

<p>
	الواجهة الأماميّة أو جهة العميل Client side مُصطلح يهم كل ما يحدث في مُتصفّح المُستخدم، وعادة ما تتم مُعالجة البيانات فيه باستخدام لغة جافاسكربت أو ميّزات HTML5 بحيث نستطيع مثلا أن نتأكّد من أنّ المُدخل المطلوب لا يُرسَل فارغا أو أنّه بطول مُعيّن وأمور أخرى.
</p>

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

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

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

<h1 id="إضافة-flask-wtf">
	إضافة Flask-WTF
</h1>

<p>
	لاستخدام مكتبة WTForms، سنلجأ إلى إضافة خاصّة بها لإطار العمل فلاسك، وتُسمى هذه الإضافة Flask-WTF اختصارا لـ Flask-WTForms ، لذا تأكّد من أنّ البيئة الوهميّة مُفعّلة ونفّذ الأمر التّالي لتنصيب الإضافة (والمكتبة كذلك):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4955_9">
<span class="pln">pip install </span><span class="typ">Flask</span><span class="pun">-</span><span class="pln">WTF</span></pre>

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

<h1 id="استخدام-مكتبة-wtforms-مع-أطر-العمل-الأخرى">
	استخدام مكتبة WTForms مع أطر العمل الأخرى
</h1>

<p>
	إنّ استخدام WTForms أمر شائع بين مُطوري الويب الذين يستخدمون أطر العمل الصّغيرة مثل Flask و Bottle و Pyramid، وحقيقة أنّ هذه السّلسلة من الدّروس موجّهة إلى مُطوري الويب الذين يستخدمون إطار العمل Flask لا تعني بالضّرورة بأنّك لن تستفيد من هذا الدّرس إذا كنت تستعمل أحد أطر العمل الأخرى، وقد قرّرت أن أجعل الأمثلة بسيطة جدا ليتمكّن الكل من فهم كيفيّة العمل المبدئيّة، كما أنّ الهدف من هذه السّلسلة هو تقريب مفهوم التحقق من بيانات المُستخدم إلى أكبر شريحة ممكنة من المُطورين لتوفير حماية أفضل لتطبيقاتهم، وبالتّالي فهي سلسلة مُستقلّة تماما عن أي سلسلة دروس أخرى، رغم أنّني أنصحك بقراءة سلسلة <a href="https://academy.hsoub.com/tags/flask%20101/" rel="">مدخل إلى إطار العمل فلاسك</a> قبل الشّروع في هذه السّلسلة.
</p>

<h2 id="تحديد-مفتاح-سري">
	تحديد مفتاح سري
</h2>

<p>
	إن قرأت <a href="https://academy.hsoub.com/programming/python/flask/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D9%86%D8%B8%D8%A7%D9%85-%D9%84%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%88-%D8%A7%D9%84%D8%AE%D8%B1%D9%88%D8%AC-%D9%88%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B3%D8%A7%D8%B3%D8%A9-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-flask-r349/" rel="">الدرس</a> الذي شرحت فيه كيفيّة إنشاء نظام بسيط لتسجيل دخول وخروج المُستخدمين ، فقد كان علينا تحديد مفتاح سري لجعل الجلسة أكثر أمانا بحيث يصعب على المُخترق الوصول إليها، وبما أنّ توفير مفتاح سري أمر ضروري في مُعظم الأوقات (لأنّ مُعظم التّطبيقات تعتمد على الجلسة على كل حال)، فإنّ الإضافات التّي تحتاج إلى سلسلة عشوائيّة من الأحرف لاستخدامها لتوليد سلاسل أخرى مُشفّرة تلجأ إلى الإعداد <code>SECRET_KEY</code>.
</p>

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

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

<p>
	ولتوليد مفتاح سري جيّد، يُمكنك استخدام الدّالّة <code>urandom</code> من الوحدة<code>os</code> على مُفسّر بايثون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4955_11">
<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">urandom</span><span class="pun">(</span><span class="lit">16</span><span class="pun">)</span><span class="pln">
</span><span class="str">' T\x1f\x85\x9b\xfe^\x0f\x14\x9f\xa3x\xa4\xb5\x92\xbe'</span></pre>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4955_13">
<span class="pln">app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="str">'SECRET_KEY'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'T\x1f\x85\x9b\xfe^\x0f\x14\x9f\xa3x\xa4\xb5\x92\xbe'</span></pre>

<p>
	والتّالي هو ما أعنيه بتعريف الكائن <code>app</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4955_15">
<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></pre>

<p>
	وهو نفس الكائن الذي تستعمله لتحديد موجّهات التّطبيق الأساسيّة.
</p>

<p>
	<em>مُلاحظة:</em> إن حاولت استخدام WTForms دون توفير مفتاح سري فستحصل على خطأ نصّه كما يلي: “Exception: Must provide secret_key to use csrf.”.
</p>

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

<p>
	تعرّفنا في هذا المقال على أهم المفاهيم الأساسيّة التّي يتوجّب عليك الإلمام بها لاستكمال مشوارك في تطوير الويب، فقد تعرّفنا على الأسباب التّي ستجعلك تتحقّق من مُدخلات المُستخدم، ولمَ يُفضّل استخدام مكتبة مثل WTForms عوضا عن القيام بذلك بنفسك، وتعرّفنا كذلك على هجمة CSRF التّي تعتبر واحدة من الهجمات التّي يُمكن أن يتعرّض لها تطبيقك في أي وقت، وقد كان هذا الدّرس تمهيدا بسيطا لسلسلة من الدّروس حول التّحقق من مُدخلات المُستخدم باستخدام مكتبة WTForms.
</p>
]]></description><guid isPermaLink="false">411</guid><pubDate>Wed, 01 Feb 2017 12:34:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x644;&#x627;&#x62E;&#x62A;&#x635;&#x627;&#x631; &#x627;&#x644;&#x631;&#x651;&#x648;&#x627;&#x628;&#x637; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x648;&#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Flask &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x651;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D9%91%D8%A7%D9%86%D9%8A-r425/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-shortner-01.png.6276f065edaf3e173f990e43ed6c92d3.png" /></p>

<h2>
	مُقدّمة:
</h2>

<p>
	بعد أن <a href="https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%91%D9%84-r424/" rel="">أعددنا السّند الخلفي لتطبيقنا،</a> حان الوقت لإعداد النّظام الأمامي لتحسين تجربة الاستخدام، سنقوم في هذا الدّرس بإنشاء ملفّ HTML ليحتوي على حقل يُمكن المُستخدم من لصق الرّابط إليه، وسنستخدم لغة جافاسكربت لإرسال الرّابط إلى تطبيق Flask واستقبال الرّابط المُختصر، بعدها سنقوم بطرح الرّابط المُختصر مع إمكانيّة نسخه عن طريق الضّغط على زر واحد.
</p>

<p style="text-align: center;">
	 
</p>

<h1 id="متطلبات-هذا-الجزء">
	مُتطلّبات هذا الجزء
</h1>

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

<p>
	وتجدر الإشارة إلى أنّك ستحتاج إلى معرفة بسيطة بأداة git لتتمكّن من التّعامل مع منصّة Heroku لخدمات الاستضافة السّحابيّة.
</p>

<p>
	<a href="https://academy.hsoub.com/programming/javascript" rel="">دروس جافاسكريبت</a><br><a href="https://academy.hsoub.com/programming/workflow/git/" rel="">دروس git</a>
</p>

<h1 id="الهدف-من-هذا-الجزء">
	الهدف من هذا الجزء
</h1>

<p>
	التّطبيق حاليا يعمل بشكل جيّد، يُمكنك زيارة رابط والحصول على المُعرّف الخاص وإضافته كلاحق لاسم النّطاق، وهكذا ستحصل على رابط مُختصر، صحيح بأنّ التّطبيق يختصر الرّوابط لكنّ طريقة العمل ليست ملائمة للمُستخدم العادي، ما سنقوم به في هذا الجزء هو تنسيق وإعداد ما يراه المُستخدم لجعل اختصار الرّوابط أكثر سهولة، ويُمكنك الاطّلاع على التّطبيق كاملا عبر <a href="http://qssrtk.herokuapp.com/" rel="external nofollow">هذا الرّابط</a>
</p>

<h1 id="إعداد-ملف-html">
	إعداد ملفّ HTML
</h1>

<p>
	سنقوم باستخدام ملف HTML واحد باسم <code>index.html</code> بداخل مُجلّد <code>templates</code> وسنربطه بملفّ جافاسكريبت باسم <code>index.js</code> وملفّ css باسم <code>style.css</code> اللذان سيكونان بداخل مجلّد <code>static</code>.<br>
	ما يعني بأنّ الملفّات والمجلّدات ستكون كالتالي:
</p>

<pre class="ipsCode" id="ips_uid_2935_7">
├── app.db
├── app.py
├── create_db.py
├── static
│   ├── css
│   │   └── style.css
│   └── js
│       └── index.js
└── templates
    └── index.html</pre>

<p>
	لتقديم ملفّ HTML سنقوم بتعديل الموجّه الرّئيسيّ ليُصبح كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_9">
<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">
def index</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">"index.html"</span><span class="pun">)</span></pre>

<p>
	بعدها سنُضيف الشيفرة التّالية إلى ملفّ <code>index.html</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2935_11">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </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;title&gt;</span><span class="pln">قصّرتك</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">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;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"{{ url_for('static', filename='css/style.css') }}"</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;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">قصّرتُك</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
        </span><span class="tag">&lt;h3&gt;</span><span class="pln"> خدمة تقصير الروابط الأكثر بساطة </span><span class="tag">&lt;/h3&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">id</span><span class="pun">=</span><span class="atv">'bg-box'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"link"</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">'input'</span><span class="pln"> </span><span class="atn">placeholder</span><span class="pun">=</span><span class="atv">'ضع رابطك هنا لتقصيره'</span><span class="pln"> </span><span class="atn">onchange</span><span class="pun">=</span><span class="atv">'</span><span class="pln">change</span><span class="pun">()</span><span class="atv">'</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">'text'</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'result'</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">'الرّابط المُختصر هنا'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'cp'</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">'#'</span><span class="pln"> </span><span class="atn">onclick</span><span class="pun">=</span><span class="atv">'</span><span class="pln">copy</span><span class="pun">()</span><span class="atv">'</span><span class="tag">&gt;</span><span class="pln">انسخ</span><span class="tag">&lt;/a&gt;</span><span class="pln">
        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'msg'</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">'#'</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"{{ url_for("</span><span class="atn">static</span><span class="atv">", filename="</span><span class="atn">js</span><span class="pun">/</span><span class="atn">index</span><span class="pln">.</span><span class="atn">js</span><span class="atv">") }}"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/script&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>style.css</code> في أعلى الملف و<code>index.js</code> في أسفله.<br>
	ستحتوي الصّفحة على حقل ليضع فيه المُستخدم رابطه (سمّيناه <code>link</code>)، وحقل لعرض النّتيجة (أي الرّابط المُختصر)، ثم أضفنا رابطا ليعمل كزر لنسخ الرّابط المُختصر وكذلك وضعنا وسم <code>span</code> لنعرض عليه رسالة النّجاح (أو الإخفاق) في نسخ الرّابط.
</p>

<p>
	لاحظ كذلك بأنّنا نستدعي دالتين من ملفّ جافاسكربت هما <code>change()</code> و <code>copy()</code> مُباشرة بعد حدثي <code>onchange</code> و <code>onclick</code> على التّوالي. الأولى مسؤولة عن إرسال طلب لاختصار الرّابِط والأخرى لتمكين المُستخدم من نسخ الرّابط المُختصر.
</p>

<h1 id="إرسال-واستقبال-الطلبات-من-وإلى-تطبيق-flask-بالاستعانة-بلغة-جافاسكريبت">
	إرسال واستقبال الطّلبات من وإلى تطبيق Flask بالاستعانة بلغة جافاسكريبت
</h1>

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

<p>
	مُحتوى ملفّ جافاسكربت سيكون كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_13">
<span class="pln">function request</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">method</span><span class="pun">,</span><span class="pln">data</span><span class="pun">,</span><span class="pln">c</span><span class="pun">){</span><span class="pln"> 
 request </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">XMLHttpRequest</span><span class="pun">;</span><span class="pln">
 request</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="pln">method</span><span class="pun">||</span><span class="str">'get'</span><span class="pun">,</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
 request</span><span class="pun">.</span><span class="pln">onload</span><span class="pun">=</span><span class="pln">b</span><span class="pun">;</span><span class="pln">
 request</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="pln">data</span><span class="pun">||</span><span class="pln">null</span><span class="pun">)</span><span class="pln">

 result </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"result"</span><span class="pun">);</span><span class="pln">
 result</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">'انتظر رجاء...'</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">

function callback</span><span class="pun">(</span><span class="pln">e</span><span class="pun">){</span><span class="pln">
      short_link </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"result"</span><span class="pun">);</span><span class="pln">
      short_link</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">location</span><span class="pun">.</span><span class="pln">host </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">response 
</span><span class="pun">}</span><span class="pln">

function change</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
url </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"input"</span><span class="pun">).</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
request</span><span class="pun">(</span><span class="str">'shorten?link='</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> url</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">,</span><span class="pln"> </span><span class="str">'get'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// الدّالة المسؤولة عن نسخ الرّابِط المُختصر إلى لوحة مفاتيح المُستخدم</span><span class="pln">
function copy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    result </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"result"</span><span class="pun">);</span><span class="pln">
    msg </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"msg"</span><span class="pun">);</span><span class="pln">
    result</span><span class="pun">.</span><span class="pln">select</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        var copy </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">execCommand</span><span class="pun">(</span><span class="str">'copy'</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">copy</span><span class="pun">)</span><span class="pln"> msg</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'نُسخَ الرّابِط بنجاح!'</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln"> msg</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'هناك خطأ ما! أعد المُحاولة رجاء'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        msg</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'المُتصفّح لا يدعم هذه العمليّة'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الدّالة request مسؤولة عن تنفيذ طلب XMLHttpRequest، حيث تستقبل الرّابِط الأصلي ثمّ تقوم الدّالة <code>callback</code> باستقبال الجواب (أي المُعرّف الخاصّ بالرّابط)، ثمّ تقوم بإسناده إلى العنصر الذي يحمل المُعرّف <code>result</code> في صفحة HTML (أي حقل النّتيجة).<br>
	لاحظ بأنّنا استخدمنا الخاصيّة <code>window.location.host</code> للحصول على اسم النّطاق، وذلك لمرونة أكثر بحيث لا نضطر إلى تغييره يدويا كلّما غيّرنا نطاق التّطبيق أو المُستضيف، والأمر مُفيد كذلك إذا أردت استخدام أكثر من اسم نطاق واحد.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_16">
<span class="pln">var copy </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">execCommand</span><span class="pun">(</span><span class="str">'copy'</span><span class="pun">);</span></pre>

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

<h1 id="نشر-التطبيق-على-منصة-heroku">
	نشر التّطبيق على منصّة Heroku.
</h1>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_18">
<span class="pln">app</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">debug</span><span class="pun">=</span><span class="typ">True</span><span class="pun">,</span><span class="pln"> host</span><span class="pun">=</span><span class="str">'0.0.0.0'</span><span class="pun">)</span></pre>

<p>
	إلى ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_20">
<span class="pln">app</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">host</span><span class="pun">=</span><span class="str">'0.0.0.0'</span><span class="pun">)</span></pre>

<p>
	وبما أنّ Heroku يعتمد على نظام Postgresql لإدارة قاعدة البيانات فيجب علينا تغيير رابط قاعدة البيانات.<br>
	الجميل في منصّة Heroku هي إمكانيّة الوصول إلى رابط قاعدة البيانات عن طريق مُتغيّر بيئة، وهذا المُتغيّر يُسمى <code>DATABASE_URL</code> وللوصول إى قيمته يكفي الاعتماد على الوحدة <code>os</code> مع الكائن <code>environ</code> وطريقة الوصول إلى قيمة هذا المُتغيّر هي كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_22">
<span class="pln">os</span><span class="pun">.</span><span class="pln">environ</span><span class="pun">[</span><span class="str">'DATABASE_URL'</span><span class="pun">]</span></pre>

<p>
	لكن لا تنس أن تسترد الوحدة <code>os</code> في أعلى الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_24">
<span class="kwd">import</span><span class="pln"> os</span></pre>

<p>
	وبالتّالي فالتّغيير الذي يجب علينا القيام به هو تعويض السّطر الأول بالسّطر الثّاني في الشّيفرة التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_26">
<span class="pln">app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="str">'SQLALCHEMY_DATABASE_URI'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'sqlite:///app.db'</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="str">'SQLALCHEMY_DATABASE_URI'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">environ</span><span class="pun">[</span><span class="str">'DATABASE_URL'</span><span class="pun">]</span></pre>

<p>
	سنقوم بتنصيب حزمة <code>psycopg2</code> ليتمكّن SQLAlchemy من التّعامل مع قواعد بيانات Postgresql وسنستخدم خادوم <code>gunicorn</code> لنشر التّطبيق، لذلك عليك تنصيبه كذلك (تأكّد من أن البيئة الوهميّة لا تزال مُفعّلة):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_28">
<span class="pln">pip install psycopg2 gunicorn</span></pre>

<p>
	سيتوجّب علينا كذلك إنشاء ملفّ باسم <code>requirements.txt</code> لتعريف Heroku بمُتطلّبات التّطبيق من حزم ووحدات، وذلك ليقوم بتنصيبها عند النّشر.<br>
	لن نقوم بإنشاء هذا الملفّ يدويا، وسنستعمل أداة <code>pip</code> لإنشاء الملفّ، تأكّد فقط بأنّك لا تزال تعمل تحت البيئة الوهميّة ثمّ نفّذ الأمر التّالي لإنشاء الملفّ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_30">
<span class="pln">pip freeze </span><span class="pun">&gt;</span><span class="pln"> requirements</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	بعد انتهاء التّنفيذ سيظهر ملفّ جديد باسم <code>requirements.txt</code> وستكون مُحتوياته شيئا مُشابها لما يلي (ربّما تتغيّر أرقام الإصدارات أو قد تظهر حزم جديدة حسب تاريخ تطبيقك لهذا المشروع):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_32">
<span class="pln">click</span><span class="pun">==</span><span class="lit">6.6</span><span class="pln">
</span><span class="typ">Flask</span><span class="pun">==</span><span class="lit">0.11</span><span class="pun">.</span><span class="lit">1</span><span class="pln">
</span><span class="typ">Flask</span><span class="pun">-</span><span class="typ">SQLAlchemy</span><span class="pun">==</span><span class="lit">2.1</span><span class="pln">
gunicorn</span><span class="pun">==</span><span class="lit">19.6</span><span class="pun">.</span><span class="lit">0</span><span class="pln">
hashids</span><span class="pun">==</span><span class="lit">1.1</span><span class="pun">.</span><span class="lit">0</span><span class="pln">
itsdangerous</span><span class="pun">==</span><span class="lit">0.24</span><span class="pln">
</span><span class="typ">Jinja2</span><span class="pun">==</span><span class="lit">2.8</span><span class="pln">
</span><span class="typ">MarkupSafe</span><span class="pun">==</span><span class="lit">0.23</span><span class="pln">
psycopg2</span><span class="pun">==</span><span class="lit">2.6</span><span class="pun">.</span><span class="lit">2</span><span class="pln">
</span><span class="typ">SQLAlchemy</span><span class="pun">==</span><span class="lit">1.0</span><span class="pun">.</span><span class="lit">14</span><span class="pln">
</span><span class="typ">Werkzeug</span><span class="pun">==</span><span class="lit">0.11</span><span class="pun">.</span><span class="lit">10</span></pre>

<p>
	هذه هي الاعتماديات (أو الحزم التي يعتمد عليها التّطبيق) التي يعتمد عليها تطبيقنا، ولو استخدمت إضافة من إضافات Flask (Flask-login على سبيل المثال) لَظهَرتْ في هذا الملف.
</p>

<p>
	يجب كذلك إنشاء ملفّ باسم<code>Procfile</code> لتعريف منصّة Heroku بملفّ التّطبيق الرّئيسيّ، وسيحتوي هذا الملفّ ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_34">
<span class="pln">web</span><span class="pun">:</span><span class="pln"> gunicorn app</span><span class="pun">:</span><span class="pln">app</span></pre>

<p>
	لاحظ بأنّ الاسم <code>app</code> الأول هو المهم، وهو اسم ملفّ التّطبيق (أي <code>app.py</code>) ولو كان اسم الملف الرّئيسي مثلا <code>run.py</code> لكان مُحتوى ملفّ <code>Procfile</code> كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_36">
<span class="pln">web</span><span class="pun">:</span><span class="pln"> gunicorn run</span><span class="pun">:</span><span class="pln">app</span></pre>

<p>
	عليك كذلك تنصيب <a href="https://academy.hsoub.com/programming/workflow/git/" rel="">أداة git</a> لتتمكّن من نشر التّطبيق ورفعه إلى المنصّة.
</p>

<h2 id="التسجيل-في-منصة-heroku">
	التّسجيل في منصّة Heroku
</h2>

<p>
	لتسجيل حساب جديد في منصّة Heroku ادخل إلى <a href="https://signup.heroku.com/" rel="external nofollow">هذا الرّابط</a> ، ثمّ املأ الحقول بما يُناسب، ويُمكنك ترك خانة Company name فارغة إن أردت.<br>
	عند ملء النّموذج سيكون كالتّالي:
</p>

<p style="text-align: center;">
	<img alt="001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21764" data-unique="8a96nxv53" src="https://academy.hsoub.com/uploads/monthly_2017_02/001.png.f741f619eb117da1acea150a4391c8a4.png" style=""></p>

<p>
	اضغط على Create Free Account ثمّ فعّل بريدك الإلكتروني، بعد النّقر على رابط تفعيل البريد الإلكتروني ستنتقل إلى صفحة يُطلب منك فيها تعيين كلمة مرور وإعادة كتابتها كإجراء احتياطي. بعدها اضغط على Set password and log in (الخانة التي تسألك عمّا إذا كنت تريد الحصول على مُحتوى تقني عبر بريدك بشكل دوري ليست مُهمّة ولك كامل الحريّة في الاختيار بين القبول أو ضدّه).
</p>

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

<h2 id="إنشاء-التطبيق">
	إنشاء التطبيق
</h2>

<p>
	بعد أن وصلت إلى لوحة التّحكم، يُمكنك الآن إنشاء تطبيق عبر الضّغط على زر “Create New App”، يُمكنك تعيين اسم للتّطبيق في خانة “App Name” سيكون هذا الاسم الذي ستختاره مُتواجدا في عنوان URL التّطبيق، ويُمكنك تركه فارغا وسيختار Heroku اسما عشوائيّا مُتاحا. ويُمكنك كذلك تعديل المنطقة الجغرافيّة للخادوم إن أردت.<br>
	بعد الانتهاء، اضغط على “Create App” لتُنشئ التّطبيق، تبقى لنا خطوة أخرى وهي تنصيب أداة Heroku Toolbelt التّي تُمكّننا من إدارة التّطبيقات عن طريق سطر الأوامر.
</p>

<p>
	لتنصيب Heroku Toolbelt انتقل إلى <a href="https://toolbelt.heroku.com" rel="external nofollow">هذا الرّابط</a> واختر نظام التّشغيل الخاص بك وقم بالتّنصيب بالطّريقة الاعتياديّة. بالنّسبة لمُستخدمي توزيعة Debian أو ما بُنيَ عليه من توزيعات يُمكنك تنفيذ الأمر التّالي على الطّرفيّة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_38">
<span class="pln">$ wget </span><span class="pun">-</span><span class="pln">O</span><span class="pun">-</span><span class="pln"> https</span><span class="pun">:</span><span class="com">//toolbelt.heroku.com/install-ubuntu.sh | sh</span></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2935_41">
<span class="pln">$ heroku login</span></pre>

<p>
	بعد إدخال بريدك الإلكتروني وكلمة المرور ستُلاحظ رسالة كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_43">
<span class="typ">Logged</span><span class="pln"> in as email@example</span><span class="pun">.</span><span class="pln">com</span></pre>

<p>
	بعدها أنشئ مُستودع git في مُجلّد التّطبيق واربطه مع المستودع الخاص بالمنصة عن طريق تنفيذ الأوامر التّاليّة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_45">
<span class="pln">$ git init

$ heroku git</span><span class="pun">:</span><span class="pln">remote </span><span class="pun">-</span><span class="pln">a app</span><span class="pun">-</span><span class="pln">name</span></pre>

<p>
	مع استبدال <code>app-name</code> باسم التّطبيق الذي اخترته (إن لم تختره فستجده في هذه <a href="https://dashboard.heroku.com" rel="external nofollow">الصّفحة</a> )
</p>

<p>
	يُفضّل إضافة مجلّد <code>venv</code> الخاصّ بالبيئة الوهميّة إلى ملفّ <code>.gitignore</code> لتجاهله.
</p>

<p>
	بعدها يُمكنك نشر التّطبيق عن طريق الأوامر التّالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_47">
<span class="pln">$ git add </span><span class="pun">.</span><span class="pln">
$ git commit </span><span class="pun">-</span><span class="pln">am </span><span class="str">"initial commit"</span><span class="pln">
$ git push heroku master</span></pre>

<p>
	بعد أن تُرفَع الملفّات بنجاح، ستهتم منصّة Heroku بتنصيب الحزم اللازمة عن طريق ملف <code>requirements.txt</code> الذي أعددناه سابقا.
</p>

<p>
	بعد انتهاء الأمر، بقيت خطوة أخيرة، وهي خطوة إنشاء جدول قاعدة البيانات، وللقيام بذلك اذهب إلى هذا الرّابط:
</p>

<p style="text-align: left;">
	<a href="https://dashboard.heroku.com/apps/app-name/resources" rel="external nofollow">https://dashboard.heroku.com/apps/app-name/resources</a>
</p>

<p>
	مع تغيير <code>app-name</code> إلى اسم تطبيقك.<br>
	وابحث في خانة “Quickly add add-ons from Elements” عن إضافة Heroku Postgres ثمّ اضغط على زر Provision، وبعدها يكفي تنفيذ الأمر التّالي على سطر الأوامر لإنشاء قاعدة البيانات والجدول الخاص بالرّوابط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_49">
<span class="pln">heroku run python create_db</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	إذا لاحظت رسالة مُشابهة لما يلي فلا تقلق فهي مُجرّد تنبيه ولا تُشكل أيّة مُشكلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_51">
<span class="pln">warnings</span><span class="pun">.</span><span class="pln">warn</span><span class="pun">(</span><span class="str">'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.'</span><span class="pun">)</span></pre>

<p>
	بعد الانتهاء من الخطوة السّابقة سيتكون قد أكملت جميع الخطوات اللازمة لتطوير تطبيق ونشره للعالم ويُمكنك زيارة تطبيقك عبر عنوان URL الخاص به أو تنفيذ الأمر التّالي من سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2935_53">
<span class="pln">heroku open</span></pre>

<h1 id="ختاما">
	ختاما
</h1>

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

<p>
	وأنبّه إلى أنّ هذا المشروع لم يكن للقارئ المبتدئ وإذا واجهت مشاكل مع هذا المشروع أو وجدته مُعقّدا بعض الشيء، فلا تقلق وتابع جديد الأكاديميّة لأنّنا سننشر سلسلة أخرى أكثر تفصيلا عن إطار العمل Flask فكن في الموعد.
</p>
]]></description><guid isPermaLink="false">425</guid><pubDate>Sat, 10 Dec 2016 23:00:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x644;&#x627;&#x62E;&#x62A;&#x635;&#x627;&#x631; &#x627;&#x644;&#x631;&#x651;&#x648;&#x627;&#x628;&#x637; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x644;&#x63A;&#x629; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x648;&#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Flask - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x651;&#x644;</title><link>https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%91%D9%84-r424/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-shortner-01.png.8fe6f4585c2b4167626b33c71626bb32.png" /></p>

<h2>
	مُقدّمة:
</h2>

<p>
	بعد أن تعلّمنا في الدّروس السّابقة كيفيّة استخدام إطار العمل Flask الخاص بلغة بايثون لإنشاء نظام تدوين بسيط، سنكمل مغامرتنا مع هذا الإطار بالمضي قُدما وتعلّم بعض التّقنيات الأكثر تقدّما وسننشئ تطبيقا بسيطا لاختصار الرّوابط في طريقنا، يُمكنك مُعاينة التّطبيق الذي سنبنيه من هذا <a href="http://qssrtk.herokuapp.com/" rel="external nofollow">الرّابط</a>.
</p>

<p style="text-align: center;">
	<img alt="flask-shortner-01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21763" data-unique="h7mzfscjx" src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-shortner-01.png.3da711fb2d186ce925c5977bf010645d.png"></p>

<p>
	التّطبيق سيكون عبارة عن خدمة لاختصار الرّوابط، فمثلا عوض كتابة الرّابط على الشّكل:<br><a href="https://mostaql.com/u/abdelhadidyouri" rel="external">https://mostaql.com/u/abdelhadidyouri</a><br>
	يُمكن اختصاره لما يلي:  bit.ly/OdrLKju<br>
	ومن المرجح أنّك صادفت هذا النوع من الرّوابط على مواقع التّواصل الاجتماعي. سنقوم في هذا الدّرس والدّرس الموالي بتبسيط فكرة اختصار الرّوابط وبرمجة تطبيق خدمي يُمكنك نشره على الأنترنت وربطه بنطاق من اختيارك وطرحه للجميع للاستفادة منه.
</p>

<h1 id="فكرة-التطبيق">
	فكرة التّطبيق
</h1>

<p>
	مهمّة التّطبيق هي تحويل رابط طويل إلى رابط قصير ما يعني بأنّنا سنحتاج إلى حفظ الرّابط في قاعدة بيانات ومنحه مُعرّفا خاصّا به، في هذه الحالة سيكون رقم مُعرّف أو id الرّابط، فمثلا لنقل بأنّ المُستخدم أدخل الرّابط academy.hsoub.com إلى قاعدة البيانات عبر نموذج HTML في الصّفحة الرّئيسيّة، عندما يدخل الرّابط إلى قاعدة البيانات سيحمل رقم المُعرّف 1 والرّابط التّالي سيحمل رقم المعرّف 2 وهكذا دواليك.ما يعني بأنّ الرّابط عندما يدخل إلى قاعدة البيانات يصبح بإمكاننا استدعاؤه باستخدام رقم المُعرّف الخاصّ به، وبالتّالي يُصبح الرّابط الأول كالتّالي:
</p>

<p style="text-align: left;">
	127.0.0.1:5000/1
</p>

<p>
	عند ربطه باسم نطاق مخصّص سيصبح كالتّالي:
</p>

<p style="text-align: left;">
	example.com/1
</p>

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

<h1 id="إعداد-البيئة-الوهمية-وتنصيب-الحزم">
	إعداد البيئة الوهميّة وتنصيب الحزم
</h1>

<p>
	سنقوم مُجدّدا باستخدام أداة virtualenv في هذا المشروع، أنشئ مجلّدا باسم <code>url_shortener</code> وقم بتنفيذ الأمر التّالي داخله:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_7">
<span class="pln">$ virtualenv venv</span></pre>

<p>
	إذا واجهت أية مشاكل يُمكنك العودة إلى هذا <a href="https://academy.hsoub.com/programming/python/flask/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-r337/" rel="">الدّرس</a><br>
	بعد إنشاء البيئة الوهميّة، فعّلها ونصّب الحزم المطلوبة بتنفيذ السّطرين التّاليين:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_10">
<span class="pln">$ </span><span class="pun">.</span><span class="pln"> venv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate
$ pip install flask </span><span class="typ">Flask</span><span class="pun">-</span><span class="typ">SQLAlchemy</span><span class="pln"> hashids</span></pre>

<h1 id="تشفير-الأعداد-الصحيحة-باستخدام-مكتبة-hashids">
	تشفير الأعداد الصّحيحة باستخدام مكتبة Hashids
</h1>

<p>
	رغم أنّ الطّريقة أعلاه تعمل بشكل جيّد وتؤدّي الغرض الذي نريده (اختصار الرّابط) لا يزال هناك مُشكلة سهولة التّنبؤ بالرّوابط التّي اختصرها المُستخدمون السّابقون، مثلا لو كان المُعرّف الذي حصلت عليه يحمل الرّقم 421 فمن السّهل عليك أن تحصل على جميع الرّوابط التّي كانت قد اختُصِرَت من قبل، وبكتابة اسم النّطاق مع رقم 420 ستحصل على الرّابط الذي اختصره المُستخدم الذي سبقك.<br>
	لحل هذه المُشكلة يُمكننا تشفير الأعداد وتحويلها إلى أحرف عشوائيّة مثلا العدد 1 سيكون JshO والعدد 2 سيكون QhIk ما يعني بأنّه من المُستحيل التنبؤ بالرّوابط التي اختُصِرَت مُسبقا.<br>
	سنستخدم في هذا الدّرس مكتبة Hashids لتحويل الأعداد إلى سلسلة نصيّة عشوائيّة. ويُمكن استخدامها كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_12">
<span class="pln">from hashids </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Hashids</span><span class="pln">
hashids </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Hashids</span><span class="pun">(</span><span class="pln">salt</span><span class="pun">=</span><span class="str">'SALT KEY'</span><span class="pun">,</span><span class="pln">min_length</span><span class="pun">=</span><span class="lit">4</span><span class="pun">)</span><span class="pln">

hashid </span><span class="pun">=</span><span class="pln"> hashids</span><span class="pun">.</span><span class="pln">encode</span><span class="pun">(</span><span class="lit">123</span><span class="pun">)</span><span class="pln"> </span><span class="com"># 'Y975'</span><span class="pln">

number </span><span class="pun">=</span><span class="pln"> hashids</span><span class="pun">.</span><span class="pln">decode</span><span class="pun">(</span><span class="str">'Y975'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># (123,)</span></pre>

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

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_14">
<span class="pln">number </span><span class="pun">=</span><span class="pln"> hashids</span><span class="pun">.</span><span class="pln">decode</span><span class="pun">(</span><span class="str">'Y975'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># (123,)</span><span class="pln">

ints </span><span class="pun">=</span><span class="pln"> hashids</span><span class="pun">.</span><span class="pln">decode</span><span class="pun">(</span><span class="str">'Y975'</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="com"># 123</span></pre>

<h1 id="تجهيز-قاعدة-البيانات-باستعمال-sqlalchemy">
	تجهيز قاعدة البيانات باستعمال SQLAlchemy
</h1>

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

<p>
	بدلا من استخدام جمل SQL للقيام بالأمر، سنعتمد على أداة SQLAlchemy للقيام بالعمليّات المُتعلّقة بقاعدة البيانات، الميّزة هنا هي أنّك تستطيع التّعامل مع قاعدة البيانات مُباشرة بلغة بايثون، والتّالي مثال على جملة SQL ومقابلتها المكتوبة بلغة بايثون بالاستعانة بـSQLAlchemy:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_17">
<span class="pln">SELECT </span><span class="pun">*</span><span class="pln"> FROM users

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></pre>

<p>
	يُوفّر لنا SQLAlchemy كذلك طريقة بسيطة للتّعامل مع مُختلف أنواع قواعد البيانات فبمجرّد تغيير سطر واحد يُمكنك الانتقال من SQLite إلى Postgresql أو Mysql والعكس، وهذا الأمر مُفيد في حالة كنت تمتلك أكثر من بيئة فبيئة التّطوير (على حاسوبك) يُمكن أن تستخدم SQLite أمّا في بيئة الإنتاج (على منصّة PythonAnywhere أو Heroku) فيُمكن استخدام MySQL أو Postgresql. كل هذا دون عناء التّعامل مع مكتبة خاصّة بكل واحدة منها، فأداة SQLAlchemy تقوم بالأشياء المعقّدة وراء الكواليس.
</p>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_19">
<span class="pln">id </span><span class="pun">|</span><span class="pln"> url
</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">  http</span><span class="pun">:</span><span class="com">//academy.hsoub.com/</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">  https</span><span class="pun">:</span><span class="com">//mostaql.com/u/abdelhadidyouri</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">  https</span><span class="pun">:</span><span class="com">//academy.hsoub.com/programming/python/flask</span></pre>

<p>
	كل ما عليك فعله هو فتح ملفّ باسم <code>app.py</code> وقم باستيراد المكتبات والأدوات التي سنحتاج إليها وقم بإعداد الاتّصال بقاعدة بيانات SQLite باسم <code>app.db</code> عبر نسخ الشّيفرة التّالية ولصقها في بداية الملفّ.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_21">
<span class="com"># Imports</span><span class="pln">

from flask </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Flask</span><span class="pun">,</span><span class="pln"> redirect</span><span class="pun">,</span><span class="pln"> request</span><span class="pun">,</span><span class="pln"> render_template
from flask_sqlalchemy </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">SQLAlchemy</span><span class="pln">
from hashids </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Hashids</span><span class="pln">

</span><span class="com"># Config</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">
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">
app</span><span class="pun">.</span><span class="pln">config</span><span class="pun">[</span><span class="str">'SQLALCHEMY_DATABASE_URI'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'sqlite:///app.db'</span><span class="pln">
SALT </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hashids SALT'</span></pre>

<p>
	الأسطر الثلاثة الأولى مسؤولة عن استيراد الأدوات التي سنعتمد عليها، أما سطر تعريف المُتغيّر <code>db</code> فهو ضروري لربط التّطبيق مع أداة SQLAlchemy أما السّطر الذي يليه فهو عبارة عن مسار قاعدة البيانات والمُتغيّر SALT يحمل قيمة مفتاح Hashids الذي تحدّثنا عنه سابقا.
</p>

<p>
	الشّيفرة التّي سنحتاج إليها لإنشاء جدول الرّوابط هي كالتّالي (انسخها وألصقها بعد الشيفرة السّابقة):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_23">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Url</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">

    </span><span class="com"># Create table `urls` |id|url|</span><span class="pln">

    __tablename__ </span><span class="pun">=</span><span class="pln"> </span><span class="str">"urls"</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="typ">True</span><span class="pun">)</span><span class="pln"> 
    url </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">

    def __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> url</span><span class="pun">):</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">url </span><span class="pun">=</span><span class="pln"> url</span></pre>

<p>
	نبدأ بصنف يحمل نفس اسم الجدول (من المُفضّل أن يكون اسما مُفردا) هذا الصّنف يرثُ من الكائن <code>db.Model</code>. بعدها نسمّي الجدول ونقوم بتحديد الأعمدة، لاحظ بأنّ أنشأنا رقم المُعرّف عبارة عن عدد صحيح (Integer) وقمنا بتمريرالقيمة <code>True</code> للمُعامل primary_key وذلك لزيادة العدد بشكل آلي كلّما أضفنا رابطا جديدا، أما السطر الموالي فهو لإنشاء عمود الرّابط من نوع نصيّ. والدّالة <strong>init</strong> متواجدة للتمكين من إضافة الرّابط إلى قاعدة البيانات.
</p>

<p>
	ولا تنس وضع الشيفرة المسؤولة عن تشغيل الخادوم ومُصحّح الأخطاء في آخر الملف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_25">
<span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">'__main__'</span><span class="pun">:</span><span class="pln">
    app</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="pln">debug</span><span class="pun">=</span><span class="typ">True</span><span class="pun">)</span></pre>

<h1 id="إنشاء-قاعدة-البيانات">
	إنشاء قاعدة البيانات
</h1>

<p>
	بعد أن أعددنا قاعدة البيانات بقي علينا إنشاؤها ويُمكن ذلك عبر كتابة ملفّ بايثون صغير يقوم بالعمليّة، افتح ملفّا باسم create_db.py وضع به ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_27">
<span class="pln">from app </span><span class="kwd">import</span><span class="pln"> db

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

<p>
	نفّذ الملفّ من سطر الأوامر، بعدها ستُلاحظ ملفّا جديدا باسم <code>app.db</code> (هذا الاسم قد سبق وأن وضعناه كقيمة لـ<code>SQLALCHEMY_DATABASE_URI</code>).<br>
	إذا أنشِئ الملف الجديد بنجاح، فهذا يعني بأنّنا انتهينا من مهمّة إنشاء قاعدة البيانات.
</p>

<h1 id="إعداد-موجه-اختصار-الروابط">
	إعداد موجّه اختصار الرّوابط
</h1>

<p>
	سيكون موجّه اختصار الرّوابط باسم <code>shorten</code> وهي كلمة تعني “اختصر”، وسيقوم هذا الموجّه بإضافة الرّابط الذي سنحصل عليه من طلب HTTP من نوع GET إلى قاعدة البيانات ومن ثم تشفير رقم مُعرّفه باستخدام مكتبة Hashids وبعدها إرجاع مُعرّف الرّابط بعد تشفيره.
</p>

<p>
	وسيكون المُوجّه كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_29">
<span class="com"># Controllers</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">'/shorten'</span><span class="pun">)</span><span class="pln">
def shorten</span><span class="pun">():</span><span class="pln">
    </span><span class="com"># الحصول على الرّابط</span><span class="pln">
    link </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">args</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'link'</span><span class="pun">)</span><span class="pln">
    </span><span class="com"># التّحقق من أنّ الرّابط صالح</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> link and link </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pln"> and not link</span><span class="pun">.</span><span class="pln">count</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> and not link</span><span class="pun">.</span><span class="pln">count</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="lit">0</span><span class="pun">:</span><span class="pln">
        </span><span class="com"># إضافة بادئة http إذا لم تتواجد</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> link</span><span class="pun">[:</span><span class="lit">4</span><span class="pun">].</span><span class="pln">lower</span><span class="pun">()</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="str">'http'</span><span class="pun">:</span><span class="pln">
            link </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://{}'</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">link</span><span class="pun">)</span><span class="pln">
        </span><span class="com"># إضافة الرّابط إلى قاعدة البيانات</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="typ">Url</span><span class="pun">(</span><span class="pln">url</span><span class="pun">=</span><span class="pln">link</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="com"># استخراج رقم مُعرّف آخر رابط مُضاف (أي الرّابط المُضاف في هذا الموجّه)</span><span class="pln">
        url_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">query</span><span class="pun">(</span><span class="typ">Url</span><span class="pun">).</span><span class="pln">order_by</span><span class="pun">(</span><span class="typ">Url</span><span class="pun">.</span><span class="pln">id</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">id
        </span><span class="com"># تشفير رقم المُعرّف</span><span class="pln">
        id_code </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Hashids</span><span class="pun">(</span><span class="pln">salt</span><span class="pun">=</span><span class="pln">SALT</span><span class="pun">,</span><span class="pln"> min_length</span><span class="pun">=</span><span class="lit">4</span><span class="pun">).</span><span class="pln">encode</span><span class="pun">(</span><span class="pln">url_id</span><span class="pun">)</span><span class="pln">
        </span><span class="com"># إضافة علامة / إلى بداية المعرّف الخاص بالرّابط ('/HFdK')</span><span class="pln">
        short_link </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> id_code  
        </span><span class="com"># إرجاع المعرّف</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> short_link 
    </span><span class="com"># في حالة عدم صلاحيّة الرّابط، عد إلى الصّفحة الرّئيسيّة</span><span class="pln">
    </span><span class="kwd">else</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">"index.html"</span><span class="pun">)</span></pre>

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

<p>
	مثال لتشفير بعض الرّوابط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_31">
<span class="pln">http</span><span class="pun">:</span><span class="com">//127.0.0.1:5000/shorten?link=http://google.com</span><span class="pln">

</span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="typ">QxvP</span><span class="pln">

http</span><span class="pun">:</span><span class="com">//127.0.0.1:5000/shorten?link=http://mostaql.com</span><span class="pln">

</span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">wrJw

http</span><span class="pun">:</span><span class="com">//127.0.0.1:5000/shorten?link=http://academy.hsoub.com</span><span class="pln">

</span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">QB5w</span></pre>

<h1 id="موجه-إعادة-التوجيه-إلى-الرابط-الأصلي">
	موجّه إعادة التّوجيه إلى الرّابط الأصلي
</h1>

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

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_33">
<span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">5000</span><span class="pun">/</span><span class="pln">QB5w</span></pre>

<p>
	فيجب على التطبيق أن يعيد توجيهه إلى الرّابط الأصلي المرتبط بالمُعرّف QB5w.<br>
	سيكون المُوجّه كالتّالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_35">
<span class="lit">@app</span><span class="pun">.</span><span class="pln">route</span><span class="pun">(</span><span class="str">'/&lt;id&gt;'</span><span class="pun">)</span><span class="pln">
def url</span><span class="pun">(</span><span class="pln">id</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># تحويل المُعرّف إلى عدد  (فك تشفيره)</span><span class="pln">
    original_id </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Hashids</span><span class="pun">(</span><span class="pln">salt</span><span class="pun">=</span><span class="pln">SALT</span><span class="pun">,</span><span class="pln"> min_length</span><span class="pun">=</span><span class="lit">4</span><span class="pun">).</span><span class="pln">decode</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
    </span><span class="com"># إذا كان المعرف مرتبطا بمجموعة فاحصل على العنصر الأول</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> original_id</span><span class="pun">:</span><span class="pln">
        original_id </span><span class="pun">=</span><span class="pln"> original_id</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
        </span><span class="com"># الحصول على الرّابط من خلال رقم مُعرّفه</span><span class="pln">
        original_url </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Url</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">original_id</span><span class="pun">).</span><span class="pln">first</span><span class="pun">().</span><span class="pln">url

        </span><span class="com"># إعادة توجيه المُستخدم إلى الرّابط الأصلي</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> redirect</span><span class="pun">(</span><span class="pln">original_url </span><span class="pun">,</span><span class="pln"> code</span><span class="pun">=</span><span class="lit">302</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">else</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">'index.html'</span><span class="pun">)</span></pre>

<p>
	هنا قُمنا بفك تشفير المُعرّف ومن ثمّ الحصول عليه من قاعدة البيانات عبر السّطر التّالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_37">
<span class="pln">original_url </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Url</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">original_id</span><span class="pun">).</span><span class="pln">first</span><span class="pun">().</span><span class="pln">url</span></pre>

<p>
	وهذا شبيه بما فعلناه سابقا في درس ربط تطبيق Flask بقاعدة بيانات SQLite ولو أردنا كتابة الاستعلام بلغة SQL كنّا سنكتب شيئا شبيها لما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_515_40">
<span class="pln">select url from urls </span><span class="kwd">where</span><span class="pln"> id</span><span class="pun">=</span><span class="pln">original_id</span></pre>

<p>
	لاحظ كذلك بأنّنا نُقدّم ملفّا باسم <code>index.html</code> إذا لم يكن المعرّف مُرتبطا بعدد معيّن، لا يهم محتوى هذا الملف، يُمكنك كذلك أن تُرجع ملفّا يُخبر المُستخدم بأنّ المُعرّف غير صحيح أو ببساطة إرجاع خطأ 404 من ملفّ HTML بسيط.
</p>

<h1 id="خاتمة">
	خاتمة:
</h1>

<p>
	تعرّفنا في هذا الدّرس على كل ما سنحتاج إليه لاختصار الرّوابط، لكنّنا لم نُقدّم أي صفحة مرئية للمُستخدم العادي، كل ما قمنا به هو إعداد النّظام الخلفي أو ما يُسمى بالـBack-end وهو الجزء المسؤول عن إدخال الرّوابط إلى قاعدة البيانات وتوليد مُعرّف نصي لكل رابط انطلاقا من رقم مُعرّفه، وكذلك تحويل الرّابط المُختصر إلى الرّابط الأصلي. ما يلزمنا الآن هو النّظام الأمامي أو Front-end وهو كل ما يخص ما يراه المُستخدم العادي وما يحدث في جهته (تُسمى كذلك جهة العميل Client Side).<br>
	في <a href="https://academy.hsoub.com/programming/python/flask/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%84%D8%A7%D8%AE%D8%AA%D8%B5%D8%A7%D8%B1-%D8%A7%D9%84%D8%B1%D9%91%D9%88%D8%A7%D8%A8%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D9%88%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D9%91%D8%A7%D9%86%D9%8A-r425/" rel="">الدّرس القادم</a> سنقوم بإعداد ملفّ HTML مع حقل يُمكن للمُستخدم أن يلصق به رابطه ويضغط على زر ENTER من لوحة المفاتيح لاختصار الرّابط، وكذا زر يُمكّنه من نسخ الرّابط المُختصر (باستخدام لغة جافاسكربت).<br>
	سنقوم كذلك بنشر تطبيقنا على منصّة Heroku للتّطبيقات السّحابيّة.
</p>
]]></description><guid isPermaLink="false">424</guid><pubDate>Sun, 04 Dec 2016 23:00:00 +0000</pubDate></item><item><title>&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; Flask &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; PythonAnywhere</title><link>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/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-07.png.21ee0ba2345829246edb20381c6d876d.png" /></p>

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

<p style="text-align: center;">
	<img alt="flask-07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21762" data-unique="7dkfiq0rx" src="https://academy.hsoub.com/uploads/monthly_2017_02/flask-07.png.79d8fe8eff3792d64015bce5476e1623.png" style=""></p>

<h1 id="التسجيل-في-منصة-pythonanywhere">
	التّسجيل في منصّة PythonAnywhere
</h1>

<p>
	ادخل إلى <a href="https://www.pythonanywhere.com/registration/register/beginner/" rel="external nofollow">هذا الرّبط</a> ثمّ قم بإدخال المعلومات المطلوبة، مع مُلاحظة أنّ اسم المُستخدم (Username) سيكون في عنوان URL الخاص بموقعك، مثلا لو اخترت <code>dyouri</code> كاسم مُستخدم فسيكون عنوان الموقع كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_4928_8">
http://dyouri.pythonanywhere.com/</pre>

<p>
	بعد ملء المعلومات المطلوبة، تحقّق من بريدك الإلكتروني وقم بتفعيله عن طريق الضّغط على رابط التّفعيل الذي ستجده في رسالة من PythonAnywhere بعنوان “confirm your email address”.
</p>

<p>
	بعد تفعيل الحساب، عد إلى الصّفحة الرّئيسية واضغط على تبويب Web ثمّ على زر “Create a new web app” ثمّ اضغط على Next ثمّ اختر Flask و Python 2.7<br>
	في المسار غيّر <code>flask_app.py</code> إلى <code>app.py</code> ثمّ اضغط Next.
</p>

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

<p>
	الآن، عد إلى مجلّد المشروع على حاسوبك وقم بضغطه كملفّ zip إما ببرنامج كـWinrar أو Ark أو غيرها من البرامج.<br>
	بعد الحصول على ملفّ <code>zip</code> يحتوي على ملفّات التّطبيق المُتواجدة على حاسوبك، عد إلى لوحة تحكّم PythonAnywhere واضغط على زر “Upload a file” وارفع الملفّ المضغوط.<br>
	بعد رفع الملفّ ادخل إلى رابط “Open Bash console here” للوصول إلى سطر الأوامر.<br>
	ستُلاحظ شاشة سوداء بها سطر مُشابه لما يلي:
</p>

<pre class="ipsCode" id="ips_uid_4928_11">
16:33 ~/mysite $</pre>

<p>
	لفكّ الضغط على الملف الذي يحتوي على ملفّات التّطبيق أدخل الأمر التّالي واضغط على Enter:
</p>

<pre class="ipsCode" id="ips_uid_4928_13">
unzip flask_app.zip</pre>

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

<ul>
<li>
		مُلاحظة:* إذا لم تضغط ملفّ <code>database.db</code> مع ملفّات التّطبيق، سيتوجّب عليك إنشاؤه مُباشرة بعد فكّ الضّغط عن الملفّ المضغوط، وذلك عبر تنفيذ الأمر:
	</li>
</ul>
<p>
	 
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4928_16">
<span class="pln">$ python create_db</span><span class="pun">.</span><span class="pln">py</span></pre>

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

<p>
	انتهينا من هذه السّلسلة البسيطة التّي استعرضنا فيها جانبا ممّا تستطيع القيام به بلغة بايثون وإطار العمل Flask. لتستفيد أكثر من هذه السّلسلة، استغل ما تعلّمته لتُنشأ تطبيقات بأفكار أخرى (منصّة أسئلة وأجوبة، تطبيق للسّماح للآخرين بنشر خواطرهم مُشابه لموقع Twitter). وسننشر كذلك سلاسل أخرى تخصّ تطوير تطبيقات الويب بلغة بايثون وإطار Flask، السّلسلة القادمة ستكون عن كيفيّة إنشاء تطبيق بسيط لاختصار الرّوابط، أمّا السّلسلة التّي ستكون بعدها فستختصّ بتطوير التّطبيقات الكبيرة والأكثر تعقيدا، وفيها سنُغطّي مُختلف إضافات إطار فلاسك وطرق حماية التّطبيق من الهجمات وسدّ الثّغرات الأمنيّة الشّائعة، سنكون السّلسلة طويلة بعض الشّيء لكنّ إنهاءها يستحق الوقت الذي ستستثمره فكن في الموعد <img alt=":)" data-emoticon="true" height="20" src="https://academy.hsoub.com/uploads/monthly_2015_02/smile.png.cf72ab87c1aaefd42371e0a7de39cfae.png" srcset="https://academy.hsoub.com/uploads/emoticons/smile@2x.png 2x" title=":)" width="20"></p>
]]></description><guid isPermaLink="false">423</guid><pubDate>Mon, 28 Nov 2016 23:00:00 +0000</pubDate></item></channel></rss>
