<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Django</title><link>https://academy.hsoub.com/programming/python/django/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Django</description><language>ar</language><item><title>&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x628;&#x64A;&#x626;&#x629; &#x62A;&#x637;&#x648;&#x64A;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%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%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2049/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/----.png.734bd56d2f99ab447e7e44862dd2c551.png" /></p>
<p>
	عرفت حتى الآن الغرض من <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل</a> <span ipsnoautolink="true">جانغو Django</span>، وسنوضّح الآن كيفية إعداد واختبار بيئة تطوير جانغوعلى أنظمة التشغيل ويندوز ولينكس (أوبنتو) وماك أو إس macOS، إذ يجب أن يعطيك هذا المقال ما تحتاجه لتكون قادرًا على البدء في تطوير تطبيقات جانغو بغض النظر عن نظام التشغيل الذي تستخدمه.
</p>

<ul>
	<li>
		<strong>المتطلبات الأساسية</strong>: معرفة أساسية باستخدام سطر الأوامر أو الطرفية Terminal وكيفية تثبيت الحزم البرمجية على نظام تشغيل حاسوب التطوير خاصتك.
	</li>
	<li>
		<strong>الهدف</strong>: تشغيل بيئة تطوير جانغو على حاسوبك.
	</li>
</ul>

<p>
	تتألف هذه السلسلة الفرعية من السلسلة الأشمل <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%AA%D8%B7%D9%88%D9%8A%D8%B1%20%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تعلم تطوير الويب</a> من المقالات التالية:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2041/" rel="">مدخل إلى إطار عمل الويب جانغو Django</a>
	</li>
	<li>
		<span ipsnoautolink="true">إعداد بيئة تطوير تطبيقات جانغو</span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D9%87%D9%8A%D9%83%D9%84%D9%8A-%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-r2090/" rel="">تطبيق عملي لتعلم جانغو - الجزء الأول: إنشاء موقع ويب هيكلي لمكتبة محلية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-r2092/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثاني: استخدام النماذج Models</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-%D9%85%D9%88%D9%82%D8%B9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-admin-r2105/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثالث: موقع مدير جانغو Django Admin</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B1%D8%A7%D8%A8%D8%B9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9-r2106/" rel="">تطبيق عملي لتعلم جانغو - الجزء الرابع: إنشاء صفحة المكتبة الرئيسية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AE%D8%A7%D9%85%D8%B3-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-r2107/" rel="">تطبيق عملي لتعلم جانغو - الجزء الخامس: العروض Views العامة والتفصيلية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B3%D8%A7%D8%AF%D8%B3-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-sessions-r2118/" rel="">تطبيق عملي لتعلم جانغو - الجزء السادس: إدارة الجلسات Sessions</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B3%D8%A7%D8%A8%D8%B9-%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%88%D8%A3%D8%B0%D9%88%D9%86%D8%A7%D8%AA%D9%87%D9%85-r2119/" rel="">تطبيق عملي لتعلم جانغو - الجزء السابع: استيثاق المستخدمين وأذوناتهم</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%85%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%85%D8%A7%D8%B1%D8%A7%D8%AA-forms-r2120/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثامن: العمل مع الاستمارات Forms</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AA%D8%A7%D8%B3%D8%B9-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r2121/" rel="">تطبيق عملي لتعلم جانغو - الجزء التاسع: اختبار تطبيق جانغو</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-10-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%A7%D8%AC-r2122/" rel="">تطبيق عملي لتعلم جانغو - الجزء 10: نشر تطبيق جانغو في بيئة الإنتاج</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r2123/" rel="">تعرف على أمان تطبيقات جانغو</a>
	</li>
</ul>

<h2>
	نظرة عامة إلى بيئة تطوير جانغو
</h2>

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

<h3>
	ما هي بيئة تطوير جانغو؟
</h3>

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

<p>
	هناك أدوات طرفية أخرى تشكل جزءًا من بيئة التطوير، ولكن لن نتحدث عنها، ويتضمن ذلك أشياءً مثل <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AD%D8%B1%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%B9%D9%85%D9%84%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1438/" rel="">محرر النصوص</a>، أو بيئة تطوير شاملة IDE لتحرير الشيفرة البرمجية، وأداة إدارة التحكم بالمصادر مثل <a href="https://academy.hsoub.com/programming/workflow/git/%D9%85%D8%A7-%D9%87%D9%88-git%D8%9F-r1592/" rel="">غيت Git</a> لإدارة النسخ المختلفة من شيفرتك البرمجية بأمان. سنفترض أن محرر نصوص مُثبَّت مسبقًا.
</p>

<h3>
	خيارات إعداد جانغو
</h3>

<p>
	يُعَد جانغو مرنًا جدًا من حيث كيفية ومكان تثبيته وإعداده، إذ يمكن أن يكون جانغو:
</p>

<ul>
	<li>
		مثبتًا على أنظمة تشغيل مختلفة.
	</li>
	<li>
		مثبتًا من المصدر من نظام إدارة الحزم Python Package Index -أو PyPi اختصارًا- ومن تطبيق مدير الحزم للحاسوب المضيف في كثير من الحالات.
	</li>
	<li>
		مُعَدًا لاستخدام واحدة من عدة قواعد بيانات، والتي يمكن أن تحتاج إلى التثبيت والإعداد بصورة منفصلة.
	</li>
	<li>
		يُشغَّل في بيئة نظام بايثون الرئيسي، أو ضمن بيئات بايثون الافتراضية المنفصلة.
	</li>
</ul>

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

<p>
	<strong>ملاحظة</strong>: خيارات التثبيت الممكنة الأخرى موضَّحة في توثيق جانغو الرسمي، وسنقدّم روابطًا إلى التوثيق المناسب لاحقًا.
</p>

<h4>
	أنظمة التشغيل المدعومة
</h4>

<p>
	يمكن تشغيل تطبيقات جانغو على أيّ جهاز تقريبًا يمكنه تشغيل <a href="https://wiki.hsoub.com/Python" rel="external">لغة بايثون 3 </a>مثل أنظمة ويندوز وماك أو إس ولينكس/ يونيكس وسولاريس Solaris. يجب أن يتمتع أي حاسوب تقريبًا بالأداء اللازم لتشغيل جانغو أثناء عملية التطوير. سنقدم في هذا المقال إرشادات لأنظمة ويندوز وماك أو إس ولينكس/ يونيكس.
</p>

<h4>
	نسخة بايثون التي يجب استخدامها
</h4>

<p>
	يمكنك استخدام أيّ نسخة من بايثون يدعمها إصدار جانغو المستهدف. النسخ المسموح بها بالنسبة لإصدار جانغو 4.0.2 هي إصدار بايثون 3.8 إلى 3.10 (اطلع على <a href="https://docs.djangoproject.com/en/4.0/faq/install/#what-python-version-can-i-use-with-django" rel="external nofollow">نسخة بايثون التي يمكن استخدامها مع جانغو</a>).
</p>

<p>
	يوصي مشروع جانغو (ويدعم رسميًا) باستخدام أحدث إصدار مدعوم من بايثون.
</p>

<h4>
	مكان تنزيل جانغو
</h4>

<p>
	هناك ثلاثة أماكن لتنزيل جانغو، هي:
</p>

<ul>
	<li>
		مستودع حزم بايثون Python Package Repository -أو اختصارًا PyPi- باستخدام أداة Pip، وهي أفضل طريقة للحصول على أحدث نسخة مستقرة من جانغو.
	</li>
	<li>
		استخدم نسخةً من مدير حزم حاسوبك، إذ تقدم توزيعات جانغو المُجمَّعة مع أنظمة التشغيل آلية تثبيت مألوفة. يمكن أن تكون النسخة المُضمَّنة قديمة جدًا، ولا يمكن تثبيتها إلا في بيئة بايثون الخاصة بالنظام (وهذا ما لا تريده).
	</li>
	<li>
		التثبيت من المصدر، إذ يمكنك الحصول على أحدث نسخة من جانغو وتثبيتها من المصدر، وهذا غير موصَى به للمبتدئين ولكنه ضروري عندما تكون مستعدًا لبدء المساهمة في جانغو.
	</li>
</ul>

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

<h4>
	قاعدة البيانات المستخدمة
</h4>

<p>
	يدعم جانغو رسميًا قواعد بيانات <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%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-postgresql-r481/" rel="">PostgreSQL</a> و MariaDB و <a href="https://academy.hsoub.com/devops/servers/databases/mysql/" rel="">MySQL</a> و Oracle و SQLite، وهناك مكتبات مجتمعية توفر مستويات مختلفة من الدعم لقواعد بيانات <a href="https://academy.hsoub.com/programming/sql/" rel="">SQL</a> و NoSQL الشائعة الأخرى. نوصيك باختيار قاعدة البيانات نفسها لكل من الإنتاج والتطوير، إذ لا تزال هناك مشاكل محتملة يُفضَّل تجنبها بالرغم من أن جانغو يجرّد العديد من الاختلافات في قاعدة البيانات باستخدام رابط الكائنات العلائقي Object-Relational Mapper -أو ORM اختصارًا.
</p>

<p>
	سنستخدم في هذا المقال قاعدة بيانات SQLite التي تخزن بياناتها في ملف؛ إذ صُمِّمت قاعدة بيانات SQLite للاستخدام بوصفها قاعدة بيانات خفيفة الوزن ولا يمكنها دعم مستوى عالٍ من التزامن، ولكنها تُعَد اختيارًا ممتازًا للتطبيقات التي تكون للقراءة فقط.
</p>

<p>
	<strong>ملاحظة</strong>: أُعِّد جانغو لاستخدام قاعدة بيانات SQLite افتراضيًا عند بدء مشروع موقع الويب باستخدام الأدوات المعيارية (django-admin)، وتُعَد خيارًا رائعًا عند البدء لأنها لا تتطلب أي إعداد أو ضبط إضافي.
</p>

<h4>
	التثبيت على مستوى النظام أم في بيئة بايثون الافتراضية
</h4>

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

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

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

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

<h2>
	تثبيت لغة بايثون 3
</h2>

<p>
	يجب تثبيت بايثون على نظام التشغيل لاستخدام جانغو، وإذا كنت تستخدم بايثون 3، فستحتاج أداة الخاصة بمستودع حزم بايثون <a href="https://pypi.org/" rel="external nofollow">Python Package Index</a> وهي pip3 التي تُستخدَم لإدارة (تثبيت وتحديث وحذف) حزم أو مكتبات بايثون التي تستخدمها تطبيقات جانغو وتطبيقات بايثون الأخرى.
</p>

<p>
	يشرح هذا القسم بإيجاز كيفية التحقق من نسخ بايثون الموجودة مسبقًا ويوضح طريقة تثبيت نسخ جديدة حسب الحاجة لنظام التشغيل أوبنتو لينكس 20.04 ونظام ماك أو إس ونظام ويندوز 10.
</p>

<p>
	<strong>ملاحظة</strong>: يمكن أن تتمكن من تثبيت بايثون وأداة pip من مدير الحزم الخاص بنظام التشغيل، أو عبر آليات أخرى اعتمادًا على منصتك التي تستخدمها، إذ يمكنك تنزيل ملفات التثبيت المطلوبة من <a href="https://www.python.org/downloads/" rel="external nofollow">موقع بايثون</a> وتثبيتها باستخدام الطريقة المناسبة الخاصة بالمنصة.
</p>

<h3>
	تثبيت لغة بايثون على نظام التشغيل لينكس أوبنتو
</h3>

<p>
	يتضمن نظام أوبنتو لينكس LTS‏ 20.04 بايثون 3.8.10 افتراضيًا، ويمكنك التأكّد من ذلك من خلال تشغيل الأمر التالي في طرفية باش Bash:
</p>

<pre class="ipsCode">python3 -V
 Python 3.8.10
</pre>

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

<pre class="ipsCode">sudo apt install python3-pip
</pre>

<p>
	<strong>ملاحظة</strong>: تُعَد بايثون 3.8 أقدم نسخة يدعمها جانغو 4.0. يوصي إطار عمل جانغو بالتحديث إلى أحدث نسخة، ولكنك لا تحتاج إلى استخدام أحدث نسخة في هذه السلسلة من المقالات. إذا أردت تحديث بايثون، فيمكنك البحث عن التعليمات على الإنترنت.
</p>

<h3>
	تثبيت لغة بايثون على نظام ماك أو إس
</h3>

<p>
	لا تتضمن النسخة إل كابيتان El Capitan من نظام ماك أو إس والنسخ الأحدث الأخرى لغةَ بايثون 3، ويمكنك التأكّد من ذلك من خلال تشغيل الأوامر التالية في طرفية zsh أو طرفية باش:
</p>

<pre class="ipsCode">$ python3 -V
  python3: command not found
</pre>

<p>
	يمكنك بسهولة تثبيت بايثون 3 (إضافةً إلى أداة pip3) من <a href="https://www.python.org/" rel="external nofollow">موقع بايثون</a> كما يلي:
</p>

<ol>
	<li>
		نزّل برنامج التثبيت المطلوب:
		<ul>
			<li>
				انتقل إلى <a href="https://www.python.org/downloads/macos/" rel="external nofollow">موقع بايثون الرسمي</a>.
			</li>
			<li>
				نزّل <a href="https://docs.djangoproject.com/en/4.0/faq/install/#what-python-version-can-i-use-with-django" rel="external nofollow">أحدث نسخة مدعومة</a> تعمل مع جانغو 4.0.2 (وهي نسخة بايثون 3.10.2 في وقت كتابة هذا المقال).
			</li>
		</ul>
	</li>
	<li>
		حدّد موقع الملف باستخدام مدير الملفات فايندر Finder، وانقر نقرًا مزدوجًا على ملف الحزمة، ثم اتبع خطوات التثبيت.
	</li>
</ol>

<p>
	يمكنك الآن تأكيد التثبيت الناجح من خلال التحقق من نسخة بايثون 3 كما يلي:
</p>

<pre class="ipsCode">python3 -V
 Python 3.10.2
</pre>

<p>
	يمكنك التحقق من تثبيت أداة pip3 من خلال سرد الحزم المتاحة:
</p>

<pre class="ipsCode">pip3 list
</pre>

<h3>
	تثبيت لغة بايثون على نظام ويندوز 10 أو 11
</h3>

<p>
	لا يتضمن نظام ويندوز لغة بايثون افتراضيًا، ولكن يمكنك تثبيتها بسهولة (إضافةً إلى أداة pip3) من <a href="https://www.python.org/" rel="external nofollow">موقع بايثون</a> كما يلي:
</p>

<ol>
	<li>
		نزّل برنامج التثبيت المطلوب بالطريقة التالية:
		<ul>
			<li>
				انتقل إلى <a href="https://www.python.org/downloads/windows/" rel="external nofollow">موقع بايثون</a>.
			</li>
			<li>
				نزّل أحدث نسخة مدعومة تعمل مع جانغو 4.0.2 (وهي نسخة بايثون 3.10.2 في وقت كتابة هذا المقال).
			</li>
		</ul>
	</li>
	<li>
		ثبّت بايثون بالنقر المزدوج على الملف الذي نزّلته واتبّع خطوات التثبيت.
	</li>
	<li>
		تأكد من تحديد المربع المسمَّى "إضافة بايثون إلى المسار Add Python to PATH".
	</li>
</ol>

<p>
	يمكنك بعد ذلك التحقق من تثبيت بايثون 3 من خلال إدخال النص التالي في موجّه الأوامر:
</p>

<pre class="ipsCode">py -3 -V
 Python 3.10.2
</pre>

<p>
	يضمّن مثبِّت نظام ويندوز الأداة pip3 (مدير حزمة بايثون) افتراضيًا، ويمكنك سرد الحزم المُثبَّتة كما يلي:
</p>

<pre class="ipsCode">pip3 list
</pre>

<p>
	<strong>ملاحظة</strong>: يجب على المثبِّت إعداد كل ما تحتاجه حتى يعمل الأمر السابق. إذا تلقيتَ رسالةً مفادها أنه لا يمكن العثور على بايثون، فيمكن أن تكون قد نسيت إضافتها إلى مسار نظامك، ويمكنك تطبيق ذلك من خلال تشغيل المثبت مرةً أخرى وتحديد الخيار "تعديل Modify" وتحديد المربع المسمى "إضافة بايثون إلى متغيرات البيئة Add Python to Environment Variables" في الصفحة الثانية.
</p>

<h2>
	استخدام جانغو ضمن بيئة بايثون الافتراضية
</h2>

<p>
	المكتبات التي سنستخدمها لإنشاء بيئاتنا الافتراضية هي <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html" rel="external nofollow">virtualenvwrapper</a> (لينكس وماك أو إس) و<a href="https://pypi.org/project/virtualenvwrapper-win/" rel="external nofollow">virtualenvwrapper-win</a> (ويندوز)، إذ تستخدم هاتان المكتبتان أداة <a href="https://virtualenv.pypa.io/en/latest/" rel="external nofollow">virtualenv</a>. تنشئ الأدوات المغلِّفة واجهة متناسقة لإدارة الواجهات على جميع المنصات.
</p>

<h3>
	تثبيت برمجيات البيئة الافتراضية
</h3>

<p>
	سنتعرّف الآن على كيفية إعداد البيئة الافتراضية في كل من أنظمة تشغيل أوبنتو وماك وويندوز.
</p>

<h4>
	إعداد بيئة أوبنتو الافتراضية
</h4>

<p>
	يمكنك بعد تثبيت بايثون وأداة pip تثبيت المكتبة virtualenvwrapper التي تتضمن المكتبة virtualenv. يمكنك الاطلاع على <a href="https://virtualenvwrapper.readthedocs.io/en/latest/install.html" rel="external nofollow">دليل التثبيت الرسمي</a> أو اتباع الإرشادات التالية.
</p>

<p>
	ثبّت الأداة أو المكتبة باستخدام الأداة pip3 كما يلي:
</p>

<pre class="ipsCode">sudo pip3 install virtualenvwrapper
</pre>

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

<pre class="ipsCode">export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 '
export PROJECT_HOME=$HOME/Devel
source /usr/local/bin/virtualenvwrapper.sh
</pre>

<p>
	<strong>ملاحظة</strong>: تشير المتغيرات <code>VIRTUALENVWRAPPER_PYTHON</code> و <code>VIRTUALENVWRAPPER_VIRTUALENV_ARGS</code> إلى موقع التثبيت العادي لبايثون 3، ويشير المصدر <code>‎/usr/local/bin/virtualenvwrapper.sh</code> إلى الموقع الاعتيادي للسكربت <code>virtualenvwrapper.sh</code>. إذا لم تعمل مكتبة virtualenv عند اختبارها، فالشيء الوحيد الذي يجب التحقق منه هو أن بايثون والسكربت موجودان في الموقع المتوقع، ثم غيّر ملف بدء التشغيل بطريقة مناسبة. يمكنك العثور على المواقع الصحيحة لنظامك باستخدام الأوامر <code>which virtualenvwrapper.sh</code> و <code>which python3</code>.
</p>

<p>
	أعِد بعد ذلك تحميل ملف بدء التشغيل من خلال تشغيل الأمر التالي في الطرفية:
</p>

<pre class="ipsCode">source ~/.bashrc
</pre>

<p>
	يجب الآن أن ترى مجموعة من السكربتات التي تُشغَّل كما يلي:
</p>

<pre class="ipsCode">virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject
# …
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details
</pre>

<p>
	يمكنك الآن إنشاء بيئة افتراضية جديدة باستخدام الأمر <code>mkvirtualenv</code>.
</p>

<h4>
	إعداد البيئة الافتراضية لنظام ماك أو إس
</h4>

<p>
	يطابق إعداد المكتبة virtualenvwrapper على نظام ماك أو إس تقريبًا إعدادها على نظام أوبنتو، ويمكنك اتباع التعليمات إما من <a href="https://virtualenvwrapper.readthedocs.io/en/latest/install.html" rel="external nofollow">دليل التثبيت الرسمي</a>، أو من الخطوات التي سنوضحها فيما يلي.
</p>

<p>
	ثبّت المكتبة Virtualenvwrapper (وتجميع المكتبة virtualenv) باستخدام الأداة pip كما يلي:
</p>

<pre class="ipsCode">sudo pip3 install virtualenvwrapper
</pre>

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

<pre class="ipsCode">export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export PROJECT_HOME=$HOME/Devel
source /usr/local/bin/virtualenvwrapper.sh
</pre>

<p>
	<strong>ملاحظة</strong>: يشير المتغير <code>VIRTUALENVWRAPPER_PYTHON</code> إلى موقع التثبيت العادي لبايثون 3، ويشير المصدر <code>‎/usr/local/bin/virtualenvwrapper.sh</code> إلى الموقع الاعتيادي للسكربت <code>virtualenvwrapper.sh</code>. إذا لم تعمل المكتبة virtualenv عند اختبارها، فالشيء الوحيد الذي يجب التحقق منه هو أن بايثون والسكربت موجودان في الموقع المتوقع، ثم غيّر ملف بدء التشغيل بطريقة مناسبة.
</p>

<p>
	انتهى اختبار أحد التثبيتات على نظام ماك أو إس مثلًا بالأسطر التالية التي تُعَد ضرورية في ملف بدء التشغيل:
</p>

<pre class="ipsCode">export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_PYTHON=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3
export PROJECT_HOME=$HOME/Devel
source /Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh
</pre>

<p>
	يمكنك العثور على المواقع الصحيحة لنظامك باستخدام الأوامر <code>which virtualenvwrapper.sh</code> و <code>which python3</code>.
</p>

<p>
	أعِد بعد ذلك تحميل ملف بدء التشغيل من خلال إجراء الاستدعاء التالي في الطرفية:
</p>

<pre class="ipsCode">source ~/.bash_profile
</pre>

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

<p>
	<strong>ملاحظة</strong>: إذا لم تتمكن من العثور على ملف بدء التشغيل لتعديله في أداة البحث، فيمكنك فتحه في الطرفية باستخدام الأمر <code>nano</code>.
</p>

<p>
	تبدو الأوامر كما يلي بافتراض أنك تستخدم باش Bash:
</p>

<pre class="ipsCode">cd ~  # الانتقال إلى المجلد الرئيسي
ls -la #قائمة محتويات المجلد. ‫يجب أن ترى ‎.bash_profile
nano .bash_profile # ‫افتح الملف في محرر نصوص نانو nano ضمن الطرفية
# انتقل إلى نهاية الملف، وانسخ الأسطر السابقة
# استخدم‫ Ctrl + X للخروج من نانو، واختر Y لحفظ الملف.
</pre>

<h4>
	إعداد بيئة ويندوز الافتراضية
</h4>

<p>
	يُعَد تثبيت مكتبة <a href="https://pypi.org/project/virtualenvwrapper-win/" rel="external nofollow">virtualenvwrapper-win</a> أبسط من إعداد مكتبة virtualenvwrapper، لأنك لا تحتاج إلى إعداد مكان تخزين الأداة لمعلومات البيئة الافتراضية، فهناك قيمة افتراضية، وكل ما عليك فعله هو تشغيل الأمر التالي في موجّه الأوامر:
</p>

<pre class="ipsCode">pip3 install virtualenvwrapper-win
</pre>

<p>
	يمكنك الآن إنشاء بيئة افتراضية جديدة باستخدام الأمر <code>mkvirtualenv</code>.
</p>

<h3>
	إنشاء بيئة افتراضية
</h3>

<p>
	يكون العمل مع البيئات الافتراضية متشابهًا جدًا على جميع المنصات بعد تثبيت المكتبة virtualenvwrapper أو virtualenvwrapper-win.
</p>

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

<pre class="ipsCode">$ mkvirtualenv my_django_environment

Running virtualenv with interpreter /usr/bin/python3
# …
virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details
(my_django_environment) ubuntu@ubuntu:~$
</pre>

<p>
	أصبحت الآن ضمن البيئة الافتراضية، ويمكنك تثبيت جانغو والبدء في التطوير.
</p>

<p>
	<strong>ملاحظة</strong>: يُرجَى من الآن فصاعدًا في هذا المقال (وهذه السلسلة من المقالات) افتراض أن أيّ أوامر مُشغَّلة ضمن بيئة بايثون الافتراضية تشبه الأمر الذي ضبطناه سابقًا.
</p>

<h3>
	استخدام البيئة الافتراضية
</h3>

<p>
	لا يوجد سوى عدد قليل من الأوامر المفيدة الأخرى التي يجب أن تعرفها، إذ يوجد المزيد في توثيق الأدوات، ولكن الأوامر التالية هي التي سنستخدمها بانتظام:
</p>

<ul>
	<li>
		<code>deactivate</code>: الخروج من بيئة بايثون الافتراضية الحالية.
	</li>
	<li>
		<code>workon</code>: سرد البيئات الافتراضية المتاحة.
	</li>
	<li>
		<code>workon name_of_environment</code>: تنشيط بيئة بايثون الافتراضية المحددة.
	</li>
	<li>
		<code>rmvirtualenv name_of_environment</code>: إزالة البيئة المحددة.
	</li>
</ul>

<h2>
	تثبيت جانغو
</h2>

<p>
	يمكنك استخدام الأداة pip3 لتثبيت جانغو بعد إنشاء بيئة افتراضية واستدعاء الأمر <code>workon</code> للدخول إليها كما يلي:
</p>

<pre class="ipsCode">pip3 install django~=4.0
</pre>

<p>
	يمكنك اختبار تثبيت جانغو من خلال تشغيل الأمر التالي، وهو مجرد اختبار لإمكانية أن تعثر بايثون على وحدة جانغو:
</p>

<pre class="ipsCode"># Linux/macOS
python3 -m django --version
 4.0.2

# Windows
py -3 -m django --version
 4.0.2
</pre>

<p>
	<strong>ملاحظة</strong>: إن لم يُظهِر أمر ويندوز السابق وجود وحدة جانغو، فجرّب الأمر التالي:
</p>

<pre class="ipsCode">py -m django --version
</pre>

<p>
	تُشغَّل سكربتات بايثون 3 في ويندوز من خلال أن نضع <code>py -3</code> في بداية الأمر، بالرغم من أن ذلك يمكن أن يختلف اعتمادًا على التثبيت المحدد، وحاول حذف المعدِّل <code>‎-3</code> إذا واجهت أي مشاكل مع الأوامر. بينما يكون الأمر هو <code>python3</code> في لينكس وماك.
</p>

<p>
	<strong>ملاحظة</strong>: تستخدم هذه السلسلة من المقالات أمر لينكس <code>python3</code> لاستدعاء بايثون 3، فإذا كنت تعمل على نظام ويندوز، فاستبدل هذه البادئة بالبادئة <code>py -3</code>.
</p>

<h2>
	أدوات بايثون الأخرى
</h2>

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

<p>
	لاحظ أنه يجب عليك استخدام <a href="https://djangopackages.org/grids/g/linters/" rel="external nofollow">منقّح صياغة جانغو</a> مثل <a href="https://pypi.org/project/pylint-django/" rel="external nofollow">pylint-django</a>. يمكن أن تبلّغ منقحات صياغة بايثون شائعة الاستخدام مثل <code>pylint</code> بصورة غير صحيحة عن أخطاء في الملفات المعيارية التي جرى إنشاؤها لجانغو.
</p>

<h2>
	اختبار تثبيتك لجانغو Django
</h2>

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

<pre class="ipsCode">mkdir django_test
cd django_test
</pre>

<p>
	يمكنك بعد ذلك إنشاء موقع هيكلي جديد بالاسم "mytestsite" باستخدام الأداة django-admin كما هو موضح. يمكنك -بعد إنشاء الموقع- الانتقال إلى المجلد حيث ستجد السكربت الرئيسي لإدارة المشاريع والذي يُسمَّى manage.py.
</p>

<pre class="ipsCode">django-admin startproject mytestsite
cd mytestsite
</pre>

<p>
	يمكننا تشغيل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">خادم الويب</a> الخاص بالتطوير من داخل هذا المجلد باستخدام manage.py والأمر <code>runserver</code> كما يلي:
</p>

<pre class="ipsCode">$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks…

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
March 01, 2022 - 01:19:16
Django version 4.0.2, using settings 'mytestsite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
</pre>

<p>
	<strong>ملاحظة</strong>: يعرض الأمرُ السابق الأمرَ الخاص بنظام لينكس أو ماك. يمكنك تجاهل التحذيرات بشأن عمليات التهجير غير المُطبَّقة "‎18 unapplied migration(s)‎" حاليًا.
</p>

<p>
	يمكنك بمجرد تشغيل الخادم عرض الموقع بالانتقال إلى عنوان URL التالي على متصفح الويب المحلي الخاص بك: <code>http://127.0.0.1:8000/‎</code>، ويجب أن تشاهد موقعًا يشبه ما يلي:
</p>

<p style="text-align: center;">
	<img alt="01_django_skeleton_app_homepage_django_4_0.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132644" data-unique="9kjb7lb2e" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2023_08/01_django_skeleton_app_homepage_django_4_0.thumb.png.f171a32623f5fb9665e47836df536387.png">
</p>

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

<p>
	لديك الآن بيئة تطوير جانغو التي تعمل على حاسوبك. رأيتَ في قسم الاختبار بإيجاز كيف يمكننا إنشاء موقع جانغو جديد باستخدام الأمر <code>django-admin startproject</code> وتشغيله في متصفحك باستخدام خادم تطوير الويب (<code>python3 manage.py runserver</code>). سنتوسّع في هذه العملية ونبني تطبيق ويب بسيط وكامل في المقال التالي.
</p>

<p>
	اطّلع أيضًا على المقالات التالية:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/" rel="">تثبيت إطار العمل جانغو على أوبنتو</a>.
	</li>
	<li>
		<a href="https://docs.djangoproject.com/en/4.0/intro/install/" rel="external nofollow">دليل التثبيت السريع</a> (توثيق جانغو).
	</li>
	<li>
		<a href="https://docs.djangoproject.com/en/4.0/topics/install/" rel="external nofollow">كيفية تثبيت جانغو - الدليل الكامل</a> (توثيق جانغو): يغطي كيفية إزالة جانغو أيضًا.
	</li>
	<li>
		<a href="https://docs.djangoproject.com/en/4.0/howto/windows/" rel="external nofollow">كيفية تثبيت جانغو على نظام ويندوز</a> (توثيق جانغو).
	</li>
</ul>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment" rel="external nofollow">Setting up a Django development environment</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D9%87%D9%8A%D9%83%D9%84%D9%8A-%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-r2090/" rel="">تطبيق عملي لتعلم جانغو - الجزء الأول: إنشاء موقع ويب هيكلي لمكتبة محلية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2041/" rel="">مدخل إلى إطار عمل الويب جانغو من طرف الخادم</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%AC%D8%A7%D9%87%D8%B2-%D9%84%D9%84%D9%86%D8%B4%D8%B1-%D9%85%D8%B9-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%88-gunicorn-r663/" rel="">إعداد تطبيق جانغو جاهز للنشر مع قاعدة بيانات Postgres وخادم Nginx و Gunicorn</a>
	</li>
	<li>
		 <a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AD%D8%B2%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B3%D9%87%D9%84-%D8%AA%D8%B9%D8%A7%D9%85%D9%84%D9%83-%D9%85%D8%B9-django-r656/" rel="">حزم بايثون الثمانية التي تسهل تعاملك مع Django</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2049</guid><pubDate>Wed, 16 Aug 2023 16:06:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django</title><link>https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2041/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/django.png.de406cf88d825ae0e500ccb9eb0876df.png" /></p>
<p>
	يُعد <span ipsnoautolink="true">جانغو Django</span> إطار عمل ويب شائع جدًا من طرف الخادم ويمتلك ميزات كاملة وهو مكتوب بلغة البرمجة <span ipsnoautolink="true">بايثون</span>. سنوضح في هذه السلسلة من المقالات سبب كون جانغو أحد أكثر إطارات عمل خادم الويب شيوعًا وكيفية إعداد بيئة التطوير والبدء في استخدامه لإنشاء تطبيقات الويب.
</p>

<p>
	تتألف هذه السلسلة الفرعية من السلسلة الأشمل <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%AA%D8%B7%D9%88%D9%8A%D8%B1%20%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تعلم تطوير الويب</a> من المقالات التالية:
</p>

<ul>
	<li>
		مدخل إلى إطار عمل الويب جانغو Django
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%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%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2049/" rel="">إعداد بيئة تطوير تطبيقات جانغو</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D9%87%D9%8A%D9%83%D9%84%D9%8A-%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D9%85%D8%AD%D9%84%D9%8A%D8%A9-r2090/" rel="">تطبيق عملي لتعلم جانغو - الجزء الأول: إنشاء موقع ويب هيكلي لمكتبة محلية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-r2092/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثاني: استخدام النماذج Models</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-%D9%85%D9%88%D9%82%D8%B9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-admin-r2105/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثالث: موقع مدير جانغو Django Admin</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B1%D8%A7%D8%A8%D8%B9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9-r2106/" rel="">تطبيق عملي لتعلم جانغو - الجزء الرابع: إنشاء صفحة المكتبة الرئيسية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AE%D8%A7%D9%85%D8%B3-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-r2107/" rel="">تطبيق عملي لتعلم جانغو - الجزء الخامس: العروض Views العامة والتفصيلية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B3%D8%A7%D8%AF%D8%B3-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-sessions-r2118/" rel="">تطبيق عملي لتعلم جانغو - الجزء السادس: إدارة الجلسات Sessions</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%B3%D8%A7%D8%A8%D8%B9-%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%88%D8%A3%D8%B0%D9%88%D9%86%D8%A7%D8%AA%D9%87%D9%85-r2119/" rel="">تطبيق عملي لتعلم جانغو - الجزء السابع: استيثاق المستخدمين وأذوناتهم</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%85%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%85%D8%A7%D8%B1%D8%A7%D8%AA-forms-r2120/" rel="">تطبيق عملي لتعلم جانغو - الجزء الثامن: العمل مع الاستمارات Forms</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AA%D8%A7%D8%B3%D8%B9-%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r2121/" rel="">تطبيق عملي لتعلم جانغو - الجزء التاسع: اختبار تطبيق جانغو</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%AA%D8%B9%D9%84%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-10-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%A7%D8%AC-r2122/" rel="">تطبيق عملي لتعلم جانغو - الجزء 10: نشر تطبيق جانغو في بيئة الإنتاج</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r2123/" rel="">تعرف على أمان تطبيقات جانغو</a>
	</li>
</ul>

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

<p>
	لست بحاجة إلى معرفة إطار عمل جانغو <span ipsnoautolink="true"><a href="https://academy.hsoub.com/programming/python/django/" rel="">Django</a></span> قبل البدء، ولكنك تحتاج إلى فهم ماهية برمجة الويب من طرف الخادم وأطر الويب من خلال الاطلاع على <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r783/" rel="">سلسلة مقالات الخطوات الأولى لبرمجة موقع الويب من طرف الخادم</a>. يُوصَى بمعرفة مفاهيم <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81-%D8%AA%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%86%D8%B5%D8%A7%D8%A6%D8%AD-%D9%88%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%84%D8%B1%D8%AD%D9%84%D8%AA%D9%83-%D9%81%D9%8A-%D8%B9%D8%A7%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r206/" rel="">البرمجة</a> ولغة <a href="https://wiki.hsoub.com/Python" rel="external" target="_blank">بايثون</a>، ولكنها ليست ضرورية لفهم المفاهيم الأساسية.
</p>

<p>
	<strong>ملاحظة</strong>: تُعَد لغة بايثون إحدى أسهل لغات البرمجة ليقرأها ويفهمها المبتدئون، ولكن إذا أردت فهم هذه السلسلة من المقالات بصورة أفضل، فيمكنك الاطلاع على توثيق لغة <a href="https://wiki.hsoub.com/Python" rel="external" target="_blank">بايثون</a> في موسوعة حسوب، وقراءة كتاب <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">البرمجة بلغة بايثون</a> من أكاديمية حسوب.
</p>
<iframe allowfullscreen="" class="ipsEmbed_finishedLoading" data-controller="core.front.core.autosizeiframe" data-embedauthorid="3889" data-embedcontent="" data-embedid="embed6140830744" src="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/?do=embed" style="overflow: hidden; height: 470px; max-width: 500px; margin: auto;"></iframe>

<p>
	تتألف هذه السلسلة الفرعية من السلسلة الأشمل <a href="https://academy.hsoub.com/search/?tags=%D8%AA%D8%B9%D9%84%D9%85%20%D8%AA%D8%B7%D9%88%D9%8A%D8%B1%20%D8%A7%D9%84%D9%88%D9%8A%D8%A8&amp;updated_after=any&amp;sortby=newest" rel="">تعلم تطوير الويب</a> من المقالات التالية:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2041/" rel="">مدخل إلى إطار عمل الويب جانغو من طرف الخادم</a>: سنجيب في مقالنا الأول على سؤال "ما هو إطار عمل جانغو؟" وسنقدّم نظرةً عامة على ما يجعله إطار عمل مميز، وسنحدّد الميزات الرئيسية بما في ذلك بعض الوظائف المتقدمة التي لن يكون لدينا الوقت لتغطيتها بالتفصيل. سنوضّح أيضًا بعض أساسيات تطبيق جانغو لإعطائك فكرة عمّا يمكنه تطبيقه قبل إعداده والبدء به.
	</li>
	<li>
		إعداد بيئة تطوير جانغو: سنوضّح بعد معرفة الغرض من إطار عمل جانغو كيفية إعداد واختبار بيئة تطويره على أنظمة تشغيل ويندوز ولينكس (أوبونتو Ubuntu) وماك أو إس MacOS. يجب أن يعطيك هذا المقال ما تحتاج إليه لتكون قادرًا على البدء في تطوير تطبيقات جانغو بغض النظر عن نظام التشغيل الشائع الذي تستخدمه.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الأول: إنشاء موقع ويب هيكلي لمكتبة محلية: يشرح هذا المقال ما ستتعلمه، ويوفر نظرةً عامة على موقع "المكتبة المحلية Local Library"، وهو مثال لموقع الويب الذي سنعمل من خلاله ونطوّره في مقالات لاحقة. يوضح هذا المقال كيفية إنشاء مشروع موقع الويب الهيكلي، والذي يمكنك بعد ذلك ملؤه بالإعدادات الخاصة بالموقع وعناوين URL والنماذج والعروض والقوالب.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الثاني: استخدام النماذج Models: يوضح هذا المقال كيفية تحديد النماذج Models لموقع ويب المكتبة المحلية؛ إذ تمثل النماذج بنى البيانات التي نريد تخزين بيانات التطبيق فيها، وتسمح لجانغو بتخزين البيانات في قاعدة بياناتنا وتعديلها لاحقًا. يشرح هذا المقال أيضًا مفهوم النموذج وكيفية التصريح عنه وبعض أنواع الحقول الرئيسية، ويعرض بإيجاز بعض الطرق الرئيسية التي يمكنك من خلالها الوصول إلى بيانات النموذج.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الثالث: موقع مدير جانغو: أنشأنا نماذج موقع ويب المكتبة المحلية، وسنستخدم الآن موقع مدير جانغو Django Admin لإضافة بعض بيانات الكتب الحقيقية، إذ سنوضح أولًا كيفية تسجيل النماذج في موقع المدير، ثم سنوضح كيفية تسجيل الدخول وإنشاء بعض البيانات، وسنعرض بعض الطرق التي يمكنك من خلالها تحسين عرض موقع المدير.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الرابع: إنشاء الصفحة الرئيسية: نحن الآن جاهزون لإضافة الشيفرة البرمجية لعرض صفحتنا الأولى الكاملة، وهي الصفحة الرئيسية للمكتبة المحلية التي تعرض عددًا من السجلات لكل نوعٍ من النماذج وتوفر روابط تنقّل جانبية إلى صفحاتنا الأخرى، وسنكتسب خبرةً عملية في كتابة روابط عناوين URL والعروض الأساسية والحصول على السجلات من قاعدة البيانات واستخدام القوالب.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الخامس: عروض القائمة المعممة والعروض التفصيلية: سنوسّع في هذا المقال موقع المكتبة المحلية من خلال إضافة قائمة وصفحات تفصيلية للكتب والمؤلفين، إذ سنتعرف على العروض المعمَّمة Generic Views المستندة إلى الأصناف، وسنوضّح كيف يمكنها تقليل مقدار الشيفرة البرمجية التي يجب عليك كتابتها لحالات الاستخدام الشائعة، وسننتقل إلى معالجة عناوين URL بمزيد من التفصيل مع توضيح كيفية إجراء مطابقة الأنماط الأساسية.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء السادس: إطار عمل الجلسة: سنوسّع في هذا المقال موقع المكتبة المحلية من خلال إضافة عدّاد زيارات مستند إلى جلسات الصفحة الرئيسية، إذ يُعَد ذلك مثالًا بسيطًا نسبيًا، ولكنه يوضّح كيفية استخدام إطار عمل الجلسة لتوفير سلوك مستمر للمستخدمين المجهولين على مواقعك الخاصة.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء السابع: استيثاق المستخدمين وأذوناتهم: سنشرح في هذا المقال كيفية السماح للمستخدمين بتسجيل الدخول إلى موقعك بحساباتهم الخاصة وكيفية التحكم بما يمكنهم فعله ومشاهدته بناءً على ما إذا قد سجّلوا الدخول أم لا وبناءً على أذوناتهم، إذ سنوسّع موقع ويب المكتبة المحلية من خلال إضافة صفحات تسجيل الدخول والخروج وصفحات خاصة بالمستخدمين والموظفين لعرض الكتب المستعارة.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء الثامن: التعامل مع الاستمارات: سنشرح في هذا المقال كيفية التعامل مع استمارات HTML في إطار عمل جانغو وخاصة استخدام أسهل طريقة لكتابة الاستمارات Forms لإنشاء نسخ من النماذج Model وتحديثها وحذفها، إذ سنوسّع موقع الويب للمكتبة المحلية بحيث يمكن لأمناء المكتبة تجديد الكتب وإنشاء المؤلفين وتحديثهم وحذفهم باستخدام الاستمارات بدلًا من استخدام تطبيق المدير.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء التاسع: اختبار تطبيق جانغو: يصبح الاختبار اليدوي لمواقع الويب أصعب مع زيادة حجمها، بسبب وجود المزيد لاختباره، إضافةً إلى زيادة تعقيد التفاعلات بين المكونات، إذ يمكن أن يتطلب تغيير بسيط في منطقة واحدة العديدَ من الاختبارات الإضافية للتحقق من تأثيره على مناطق أخرى. تتمثل إحدى طرق التخفيف من هذه المشاكل في كتابة الاختبارات الآلية التي يمكن تشغيلها بسهولة وموثوقية في كل مرة تُجري فيها تغييرًا. يوضّح هذا المقال كيفية جعل اختبار الوحدة Unit Testing لموقع الويب آليًا باستخدام إطار اختبار جانغو.
	</li>
	<li>
		تطبيق عملي لتعلم إطار عمل جانغو - الجزء العاشر: نشر تطبيق جانغو في بيئة الإنتاج: أنشأتَ واختبرتَ موقعًا رائعًا للمكتبة المحلية، ويجب الآن تثبيته على خادم ويب عام حتى يصل إليه موظفو المكتبة وأعضاؤها عبر الإنترنت. يقدّم هذا المقال نظرةً عامةً حول كيفية البحث عن مضيف لنشر موقع الويب وما يجب فعله لتجهيز موقعك للإنتاج.
	</li>
	<li>
		أمان تطبيق جانغو: تُعَد حماية بيانات المستخدم جزءًا أساسيًا من تصميم أيّ موقع ويب، إذ شرحنا سابقًا بعض الهجمات الأمنية الأكثر شيوعًا في مقال <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r2020/" rel="">أمان مواقع الويب</a>، وسيقدّم هذا المقال شرحًا عمليًا لكيفية تعامل أدوات الحماية المُضمَّنة في إطار عمل جانغو مع هذه الهجمات.
	</li>
</ul>

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

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

<h2>
	مقدمة إلى إطار العمل جانغو
</h2>

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

<ul>
	<li>
		<p>
			<strong>المتطلبات الأساسية</strong>: المهارات الحاسوبية الأساسية، وفهم عام <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r783/" rel="">لبرمجة مواقع الويب من طرف الخادم</a> وخاصةً <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B9%D9%84%D9%89-%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%85%D8%B9-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-%D9%81%D9%8A-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D8%AF%D9%8A%D9%86%D8%A7%D9%85%D9%8A%D9%83%D9%8A-r782/" rel="">تفاعلات الخادم مع العميل في مواقع الويب</a>.
		</p>
	</li>
	<li>
		<p>
			<strong>الهدف</strong>: التعرف على إطار عمل جانغو والوظائف التي يوفرها وأساسيات بناء تطبيق جانغو.
		</p>
	</li>
</ul>

<h3>
	ما هو جانغو؟
</h3>

<p>
	يُعَد جانغو <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل</a> ويب عالي المستوى يستخدم <a href="https://academy.hsoub.com/python/" rel="">لغة بايثون</a> ويتيح التطوير السريع لمواقع الويب الآمنة والقابلة للصيانة. صمّم مطورون ذوو خبرة إطار عمل جانغو الذي يخلصك من الكثير من متاعب تطوير الويب، بحيث يمكنك التركيز على كتابة تطبيقك دون الحاجة إلى إعادة اختراع العجلة، وهو إطار عمل مجاني ومفتوح المصدر وله مجتمع مزدهر ونشط وتوثيق رائع والعديد من خيارات الدعم المجاني والمدفوع.
</p>

<p>
	يساعدك جانغو في كتابة برمجيات تتمتع بالمواصفات التالية:
</p>

<ul>
	<li>
		<p>
			<strong>مكتملة</strong>: يتبع جانغو فلسفة أنه يتضمن كل شيء "Batteries Included" ويوفر تقريبًا كل ما يرغب المطوّرون في تطبيقه. بما أن كل ما تحتاجه هو جزء من منتج واحد، فإن كل شيء يعمل مع بعضه بعضًا بسلاسة ويتبع مبادئ تصميم متناسقة ويحتوي على توثيق شامل ومُحدَّث.
		</p>
	</li>
	<li>
		<p>
			<strong>متعددة الاستعمالات</strong>: يمكن استخدام جانغو -وقد اُستخدِم فعليًا- لبناء أيّ نوع من مواقع الويب تقريبًا بدءًا من أنظمة إدارة المحتوى ومواقع الويكي مرورًا بشبكات التواصل الاجتماعي والمواقع الإخبارية. يمكن لجانغو العمل مع أيّ إطار عمل من طرف العميل، ويمكنه تقديم المحتوى بأي تنسيق تقريبًا، مثل <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>، و RSS Feeds، و <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a>، و XML. يوفّر جانغو داخليًا خيارات لأي وظيفة تقريبًا ترغب فيها مثل دعم العديد من <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA/" rel="">أنواع قواعد البيانات </a>الشائعة ومحركات القوالب وغيرها، ولكن يمكن توسيعه لاستخدام مكونات أخرى إذا لزم الأمر.
		</p>
	</li>
	<li>
		<p>
			<strong>آمنة</strong>: يساعد جانغو المطورين على تجنب العديد من الأخطاء الأمنية الشائعة من خلال توفير إطار عمل مُصمَّم لتطبيق الأشياء الصحيحة بهدف حماية الموقع آليًا، فمثلًا يوفر جانغو طريقةً آمنةً لإدارة حسابات المستخدمين وكلمات المرور وتجنب الأخطاء الشائعة مثل وضع معلومات الجلسة في ملفات تعريف الارتباط Cookies، حيث تكون معرضةً للخطر، وذلك من خلال جعل ملفات تعريف الارتباط cookies تحتوي على مفتاح فقط وتخزين البيانات الفعلية في قاعدة البيانات، أو تخزين كلمات المرور مباشرةً بدلًا من تعمية Hash كلمة المرور التي هي قيمة ذات طول ثابت تُنشَأ من خلال إرسال كلمة المرور عبر دالة تعمية مُشفَّرة Cryptographic Hash Function. يمكن لجانغو التحقق مما إذا كانت كلمة المرور المدخَلة صحيحة من خلال تشغيلها عبر دالة التعمية وموازنة الخرج مع قيمة التعمية المخزنة، ولكن حتى إذا اُخترِقت قيمة التعمية المخزنة، فمن الصعب على المهاجم معرفة كلمة المرور الأصلية نظرًا لطبيعة الدالة أحادية الاتجاه. يتيح جانغو الحماية ضد العديد من الثغرات افتراضيًا بما في ذلك حقن استعلامات SQL وهجمات السكربتات العابرة للمواقع وتزوير الطلبات عبر المواقع والاختطاف بالنقر clickjacking (اطلع على مقال <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r2020/" rel="">أمان مواقع الويب</a> لمزيد من التفاصيل حول هذه الهجمات).
		</p>
	</li>
	<li>
		<p>
			<strong>قابلة للتوسّع</strong>: يستخدم جانغو معمارية "لا شيء مشترك shared-nothing" القائمة على المكونات، إذ يكون كل جزء من المعمارية مستقلًا عن الأجزاء الأخرى، وبالتالي يمكن استبداله أو تغييره حسب الحاجة. يعني وجود فصل واضح بين الأجزاء المختلفة أنه يمكن توسيع حركة الزوار المتزايدة من خلال إضافة عتاد على أي مستوى من خوادم التخزين المؤقت، أو خوادم قواعد البيانات، أو خوادم التطبيقات. وقد نجحت بعض المواقع الأكثر ازدحامًا في توسيع جانغو لتلبية مطالبهم مثل إنستغرام وديسكاس Disqus.
		</p>
	</li>
	<li>
		<p>
			<strong>قابلة للصيانة</strong>: كُتِبت شيفرة جانغو البرمجية باستخدام مبادئ وأنماط التصميم التي تشجع على إنشاء شيفرة برمجية قابلة للصيانة وإعادة الاستخدام؛ إذ يستخدم جانغو مبدأ لا تكرر نفسك Don't Repeat Yourself -أو DRY اختصارًا، لذلك لا يوجد تكرار غير ضروري، مما يقلل من كمية الشيفرة البرمجية. كما يدعم جانغو تجميع الوظائف المرتبطة ببعضها ضمن تطبيقات قابلة لإعادة الاستخدام، وتجميع الشيفرة البرمجية المرتبطة ببعضها ضمن وحدات على مستوى أدنى مثل نمط نموذج-عرض-مُتحكِّم Model View Controller -أو MVC اختصارًا.
		</p>
	</li>
	<li>
		<p>
			<strong>قابلة للنقل</strong>: كُتِب إطار عمل جانغو باستخدام لغة بايثون التي تعمل على العديد من المنصات، وهذا يعني أنك لست مرتبطًا بأي منصة خوادم معينة، ويمكنك تشغيل تطبيقاتك على العديد من إصدارات لينكس وويندوز وماك أو إس. كما يدعم العديد من مزودي استضافة الويب إطار عمل جانغو بصورة جيدة، ويوفّر مزودو استضافة الويب في أغلب الأحيان بنيةً أساسيةً محدّدة وتوثيقًا لاستضافة مواقع جانغو.
		</p>
	</li>
</ul>

<h3>
	تاريخ إطار عمل جانغو
</h3>

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

<p>
	استمر إطار عمل جانغو في النمو والتحسن من الإصدار الأول 1.0 في الشهر التاسع من عام 2008 وحتى الإصدار 4.0 الصادر مؤخرًا في عام 2022. أضاف كل إصدار وظائفًا جديدة وإصلاحات للأخطاء بدءًا من دعم الأنواع الجديدة من قواعد البيانات ومحركات القوالب والتخزين المؤقت وإضافة دوال وأصناف العرض المعمَّمة التي تقلل من مقدار الشيفرة البرمجية التي يجب أن يكتبها المطورون لعددٍ من المهام البرمجية.
</p>

<p>
	<strong>ملاحظة</strong>: تحقَّق من <a href="https://docs.djangoproject.com/en/4.1/releases/" rel="external nofollow" target="_blank">ملاحظات الإصدارات</a> على موقع جانغو لترى ما الذي تغير في الإصدارات الأخيرة ومقدار العمل المبذول في تحسين جانغو.
</p>

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

<h3>
	ما مدى شعبية جانغو؟
</h3>

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

<p>
	تشمل المواقع البارزة التي تستخدم جانغو: ديسكاس Disqus وإنستغرام و Knight Foundation و MacArthur Foundation وموزيلا Mozilla وناشيونال جيوغرافيك National Geographic و Open Knowledge Foundation وينترست Pinterest و Open Stack (المصدر: <a href="https://www.djangoproject.com/start/overview/" rel="external nofollow" target="_blank">موقع جانغو الرسمي</a>).
</p>

<h3>
	هل جانغو إطار عمل متشبث برأيه؟
</h3>

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

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

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

<h3>
	كيف تبدو شيفرة جانغو البرمجية؟
</h3>

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

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

<p style="text-align: center;">
	<img alt="01_basic-django.png" class="ipsImage ipsImage_thumbnailed" data-fileid="132427" data-unique="vcrrqf986" src="https://academy.hsoub.com/uploads/monthly_2023_08/01_basic-django.png.9c7f38515e0df0e47e53b1907bf3b86a.png">
</p>

<ul>
	<li>
		<p>
			<strong>عناوين URL</strong>: يمكن معالجة الطلبات من كل عنوان URL باستخدام دالة واحدة، ولكن تُعَد كتابة دالة عرض منفصلة للتعامل مع كل مورد أمرًا قابلًا للصيانة بصورة أفضل، إذ يُستخدَم رابط Mapper عنوان URL لإعادة توجيه طلبات HTTP إلى العرض المناسب بناءً على عنوان URL الخاص بالطلب، ويمكن لرابط عنوان URL مطابقة أنماط معينة من السلاسل النصية أو الأرقام التي تظهر في عنوان URL وتمريرها إلى دالة عرض بوصفها بيانات.
		</p>
	</li>
	<li>
		<p>
			<strong>العرض View</strong>: العرض هو دالة معالج الطلب والتي تتلقى طلبات HTTP وتعيد استجابات HTTP. تصل العروض إلى البيانات اللازمة لتلبية الطلبات باستخدام النماذج وتكلّف القوالب Templates بتنسيق الاستجابة.
		</p>
	</li>
	<li>
		<p>
			<strong>النموذج Model</strong>: النماذج هي كائنات بايثون تعرّف بنية بيانات التطبيق وتوفّر آليات لإدارة (إضافة وتعديل وحذف) السجلات والاستعلام عنها في قاعدة البيانات.
		</p>
	</li>
	<li>
		<p>
			<strong>القالب Template</strong>: القالب هو ملف نصي يعرّف بنية أو تخطيط ملف، مثل صفحة HTML، مع استخدام العناصر البديلة لتمثيل المحتوى الفعلي. يمكن للعرض أن ينشئ صفحة HTML ديناميكيًا باستخدام قالب HTML وتعبئتها ببيانات من نموذج، ويمكن استخدام القالب لتعريف بنية أيّ نوع من الملفات، فليس بالضرورة أن يكون ملف HTML.
		</p>
	</li>
</ul>

<p>
	<strong>ملاحظة</strong>: يشير جانغو إلى هذا التنظيم بأنه معمارية نموذج-عرض-قالب Model View Template -أو MVT اختصارًا، إذ تمتلك هذه المعمارية العديد من أوجه التشابه مع معمارية نموذج-عرض-مُتحكِّم MVC الأكثر شيوعًا.
</p>

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

<h4>
	إرسال الطلب إلى العرض الصحيح: الملف urls.py
</h4>

<p>
	يُخزَّن رابط عنوان URL في ملف يسمى urls.py، إذ يعرّف الرابط <code>urlpatterns</code> في المثال الآتي قائمةً من الروابط بين الوجهات Routes (وهي أنماط Patterns عنوان URL مُحدَّدة) ودوال العرض المقابلة لها. إذا اُستلِم طلب HTTP يحتوي على عنوان URL يطابق نمطًا محددًا، فستُستدعَى دالة العرض المرتبطة به ويُمرَّر الطلب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5712_25" style=""><span class="pln">urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'book/&lt;int:id&gt;/'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">book_detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'book_detail'</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'catalog/'</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="str">'catalog.urls'</span><span class="pun">)),</span><span class="pln">
    re_path</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^([0-9]+)/$'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">best</span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	كائن <code>urlpatterns</code> هو قائمة من دوال <code>path()‎</code> و/ أو <code>re_path()‎</code>. تُعرَّف قوائم بايثون باستخدام أقواس مربعة، إذ تُفصَل العناصر بفواصل ويمكن أن تحتوي على فاصلة لاحقة اختيارية مثل <code>[item1, item2, item3,‎]</code>.
</p>

<p>
	الوسيط الأول لكلا التابعين هو الوجهة أو النمط الذي ستجري مطابقته. يستخدم التابع <code>path()‎</code> أقواس زاوية لتحديد أجزاء من عنوان URL التي ستُلتقَط وتُمرَّر إلى دالة العرض بوصفها وسائطًا مُسمَّاة، بينما تستخدم الدالة <code>re_path()‎</code> أسلوبًا مرنًا لمطابقة الأنماط يُعرَف بالتعبير النمطي <a href="https://academy.hsoub.com/devops/linux/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-regular-expressions-r63/" rel="">Regular Expression</a> الذي سنتحدث عنه لاحقًا.
</p>

<p>
	الوسيط الثاني هو دالة أخرى تُستدعَى عند مطابقة النمط، إذ تشير الصيغة <code>views.book_detail</code> إلى أن الدالة تسمى <code>book_detail()‎</code> ويمكن العثور عليها في الوحدة <code>views</code>، أي ضمن الملف <code>views.py</code>.
</p>

<h4>
	معالجة الطلب: الملف views.py
</h4>

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

<p>
	يوضّح المثال الآتي أصغر دالة عرض <code>index()‎</code> التي كان من الممكن أن يستدعيها رابط عنوان URL في القسم السابق؛ إذ تتلقى هذه الدالة مثل جميع دوال العرض كائن <code>HttpRequest</code> بوصفه معاملًا <code>request</code> وتعيد كائن <code>HttpResponse</code>، إذ لا نفعل أيّ شيء مع الطلب في هذه الحالة، وتعيد استجابتنا سلسلةً نصيةً ثابتة Hard-coded، وسنعرض لاحقًا طلبًا يفعل شيئًا آخر أكثر إثارة للاهتمام.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5712_28" style=""><span class="com"># اسم الملف‫: views.py (دوال عرض جانغو)</span><span class="pln">

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="com"># الحصول على‫ HttpRequest - معامل الطلب</span><span class="pln">
    </span><span class="com"># إجراء العمليات باستخدام المعلومات الواردة في الطلب‫.</span><span class="pln">
    </span><span class="com"># إعادة‫ HttpResponse</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hello from Django!'</span><span class="pun">)</span></pre>

<p>
	<strong>ملاحظة</strong>: إليك بعض المعلومات عن لغة بايثون:
</p>

<ul>
	<li>
		<p>
			وحدات بايثون هي مكتبات من الدوال مُخزَّنة في ملفات منفصلة، والتي يمكن أن نرغب في استخدامها في شيفرتنا البرمجية. نستورد في مثالنا كائن <code>HttpResponse</code> من الوحدة <code>django.http</code> حتى نتمكّن من استخدامه في عرضنا <code>from django.http import HttpResponse</code>، وهناك طرق أخرى لاستيراد بعض الكائنات أو جميعها من وحدةٍ ما.
		</p>
	</li>
	<li>
		<p>
			يُصرَّح عن <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r752/" rel="">الدوال </a>باستخدام الكلمة المفتاحية <code>def</code> كما هو موضح سابقًا، مع وجود معاملات مُسمَّاة بين قوسين بعد اسم الدالة وينتهي السطر بأكمله بنقطتين. لاحظ وضع مسافة بادئة لجميع الأسطر التالية، إذ تُعَد المسافة البادئة مهمة، لأنها تحدد أن سطور الشيفرة البرمجية موجودة ضمن تلك الكتلة المحددة. تُعَد المسافة البادئة الإلزامية ميزةً رئيسية في لغة بايثون، وهي أحد أسباب سهولة قراءة شيفرة بايثون البرمجية.
		</p>
	</li>
</ul>

<h4>
	تعريف نماذج البيانات: الملف models.py
</h4>

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

<p>
	يُظهِر مقتطف الشيفرة البرمجية الآتي نموذج جانغو بسيط جدًا للكائن <code>Team</code>، فالصنف <code>Team</code> مُشتَق من صنف جانغو <code>models.Model</code>، ويعرّف اسم الفريق ومستوى الفريق بوصفها حقولًا محرفية ويحدد الحد الأقصى لعدد المحارف التي ستُخزَّن لكل سجل. يمكن أن يكون مستوى الفريق <code>team_level</code> قيمةً من عدة قيم، لذلك نحدّده بوصفه حقلًا اختياريًا ونوفّر ربطًا بين الخيارات المراد عرضها والبيانات المراد تخزينها إلى جانب القيمة الافتراضية.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1216_10" style=""><span class="com"># اسم الملف: models.py</span><span class="pln">

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    team_name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">40</span><span class="pun">)</span><span class="pln">

    TEAM_LEVELS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'U09'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Under 09s'</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'U10'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Under 10s'</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'U11'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Under 11s'</span><span class="pun">),</span><span class="pln">
        </span><span class="com"># …</span><span class="pln">
        </span><span class="com"># قائمة مستويات الفريق الأخرى</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
    team_level </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> choices</span><span class="pun">=</span><span class="pln">TEAM_LEVELS</span><span class="pun">,</span><span class="pln"> default</span><span class="pun">=</span><span class="str">'U11'</span><span class="pun">)</span></pre>

<p>
	<strong>ملاحظة</strong>:
</p>

<p>
	إليك بعض المعلومات عن لغة بايثون: تدعم لغة بايثون <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a> التي تُعَد نمطًا من البرمجة، إذ ننظم شيفرتنا البرمجية ضمن كائنات، والتي تتضمن بيانات ودوال متعلقة بها للعمل على تلك البيانات. يمكن للكائنات أن ترث، أو توسّع، أو تُشتَق من كائنات أخرى، مما يسمح بمشاركة السلوك المشترك بين الكائنات المتعلقة ببعضها. نستخدم في لغة بايثون الكلمة المفتاحية <code>class</code> لتعريف المخطط الأولي للكائن. يمكننا إنشاء نسخ متعددة محددة لنوع الكائن بناءً على النموذج في الصنف؛ فلدينا في مثالنا الصنف <code>Team</code> مُشتَق من الصنف <code>Model</code>، وهذا يعني أنه نموذج وسيحتوي على جميع توابعه، ولكن يمكننا منحه ميزات خاصة به أيضًا. نحدد في نموذجنا الحقول التي ستحتاجها قاعدة البيانات لتخزين بياناتنا من خلال منحها أسماءً محددة. يستخدم جانغو هذه التعريفات -بما في ذلك أسماء الحقول- لإنشاء قاعدة البيانات الأساسية.
</p>

<h4>
	الاستعلام عن البيانات: الملف views.py
</h4>

<p>
	يوفر نموذج جانغو واجهة برمجة تطبيقات استعلام بسيطة للبحث في قاعدة البيانات المرتبطة به، ويمكن أن تتطابق هذه الواجهة مع عدد من الحقول في وقت واحد باستخدام معايير مختلفة، مثل التطابق التام exact وغير الحساس لحالة الأحرف case-insensitive وأكبر من وغير ذلك، ويمكن أن يدعم العبارات المعقدة، فمثلًا يمكنك تحديد بحث عن فرق U11 التي يبدأ اسم فريقها بالحرفين "Fr" أو ينتهي بالحرفين "al".
</p>

<p>
	يُظهِر مقتطف الشيفرة البرمجية التالية دالة العرض (معالج المورد) لعرض جميع فرق U09، إذ يوضح السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4779_8" style=""><span class="pln">list_teams </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">team_level__exact</span><span class="pun">=</span><span class="str">"U09"</span><span class="pun">)‎</span></pre>

<p>
	كيف يمكننا استخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهة <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> للاستعلام عن النموذج لترشيح جميع السجلات، إذ يحتوي الحقل <code>team_level</code> على النص "U09" حرفيًا (لاحظ كيف تُمرَّر هذه المعايير إلى الدالة <code>filter()‎</code> بوصفها وسيطًا مع فصل اسم الحقل ونوع المطابقة بشرطة سفلية مزدوجة: <code>team_level__exact</code>).
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1216_12" style=""><span class="com">## اسم الملف: views.py</span><span class="pln">

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Team</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    list_teams </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Team</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">team_level__exact</span><span class="pun">=</span><span class="str">"U09"</span><span class="pun">)</span><span class="pln">
    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'youngest_teams'</span><span class="pun">:</span><span class="pln"> list_teams</span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'/best/index.html'</span><span class="pun">,</span><span class="pln"> context</span><span class="pun">)</span></pre>

<p>
	تستخدم الدالةُ السابقة الدالةَ <code>render()‎</code> لإنشاء الكائن <code>HttpResponse</code> الذي يُرسَل إلى المتصفح، إذ تُعَد هذه الدالة اختصارًا Shortcut ينشئ ملف HTML من خلال الجمع بين قالب HTML محدَّد وبعض البيانات لإدخالها في القالب (تتوفر هذه البيانات في المتغير المُسمَّى "<code>context</code>"). سنوضّح في القسم التالي كيفية إدخال البيانات في القالب لإنشاء ملف HTML.
</p>

<h4>
	عرض البيانات: قوالب HTML
</h4>

<p>
	تسمح لك أنظمة القوالب بتحديد بنية مستند الخرج باستخدام عناصر بديلة للبيانات التي ستُملَأ عند إنشاء الصفحة، إذ تُستخدَم القوالب غالبًا لإنشاء مستندات HTML، ولكن يمكنها إنشاء أنواع أخرى من المستندات أيضًا. يدعم جانغو كلًا من نظام القوالب الأصيل Native ومكتبة بايثون الشهيرة الأخرى التي تسمى <a href="https://academy.hsoub.com/tags/jinja2/" rel="">Jinja2</a>، ويمكن جعله يدعم أنظمة أخرى إن لزم الأمر.
</p>

<p>
	يوضح مقتطف الشيفرة البرمجية التالية الشكل الذي يمكن أن يبدو عليه قالب HTML الذي تستدعيه الدالة <code>render()‎</code> في القسم السابق. كُتِب هذا القالب على أساس الافتراض بأنه يمكنه الوصول إلى متغير قائمة يُسمَّى <code>youngest_teams</code> عند عرضه (يوجد هذا المتغير ضمن المتغير <code>context</code> في الدالة <code>render()‎</code>). يوجد ضمن بنية HTML تعبيرٌ يتحقق أولًا من وجود المتغير <code>youngest_teams</code>، ثم يكرره في حلقة <code>for</code>، إذ يعرض القالب في كل تكرار قيمة <code>team_name</code> لكل فريق في عنصر <a href="https://wiki.hsoub.com/HTML/li" rel="external" target="_blank"><code>&lt;li&gt;</code></a>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1216_16" style=""><span class="pln">## اسم الملف: best/templates/best/index.html

</span><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</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">Home page</span><span class="tag">&lt;/title&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">
</span><span class="tag">&lt;body&gt;</span><span class="pln">
  {% if youngest_teams %}
    </span><span class="tag">&lt;ul&gt;</span><span class="pln">
      {% for team in youngest_teams %}
        </span><span class="tag">&lt;li&gt;</span><span class="pln">{{ team.team_name }}</span><span class="tag">&lt;/li&gt;</span><span class="pln">
      {% endfor %}
    </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
  {% else %}
    </span><span class="tag">&lt;p&gt;</span><span class="pln">No teams are available.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  {% endif %}
</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<h3>
	ميزات جانغو الأخرى
</h3>

<p>
	أظهرت الأقسام السابقة الميزات الرئيسية التي ستستخدمها في كل تطبيق ويب تقريبًا وهي: ربط عناوين URL والعروض والنماذج والقوالب. تشمل بعض الأشياء الأخرى التي يقدمها إطار عمل جانغو الميزاتِ التالية:
</p>

<ul>
	<li>
		<p>
			<strong>الاستمارات Forms</strong>: تُستخدَم استمارات HTML لتجميع بيانات المستخدم لمعالجتها على الخادم. يبسّط جانغو إنشاء الاستمارات والتحقق من صحتها ومعالجتها.
		</p>
	</li>
	<li>
		<p>
			<strong>استيثاق Authentication المستخدم وأذوناته</strong>: يتضمن جانغو نظامًا قويًا لاستيثاق المستخدم وأذوناته، إذ أُنشئ هذا النظام مع وضع الأمان في الحسبان.
		</p>
	</li>
	<li>
		<p>
			<strong>التخزين المؤقت Caching</strong>: يتطلب إنشاء المحتوى ديناميكيًا عمليات حسابية أكثر وأبطأ من تقديم محتوى ساكن، لذا يوفر جانغو تخزينًا مؤقتًا مرنًا بحيث يمكنك تخزين الصفحة المعروضة بالكامل أو جزء منها حتى لا يُعاد عرضها إلّا عند الضرورة.
		</p>
	</li>
	<li>
		<p>
			<strong>موقع المدير Administration site</strong>: يُضمَّن موقع مدير جانغو افتراضيًا عند إنشاء تطبيق باستخدام الهيكل الأساسي، مما يسهّل توفير صفحة مدير لمديري الموقع لإنشاء أي نماذج بيانات في موقعك وتعديلها وعرضها.
		</p>
	</li>
	<li>
		<p>
			<strong>سَلسَلة البيانات Serializing data</strong>: يسهّل جانغو من سَلسَلة بياناتك وتقديمها بتنسيق XML أو JSON، ويمكن أن يكون ذلك مفيدًا عند إنشاء خدمة ويب (موقع ويب يقدّم البيانات فقط لتستهلكها تطبيقات أو مواقع أخرى ولا يعرض أيّ شيء بنفسه)، أو عند إنشاء موقع ويب تعالج فيه الشيفرة البرمجية من طرف العميل كل عملية عرض أو تصيير البيانات.
		</p>
	</li>
</ul>

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

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

<p>
	ترجمة -وبتصرُّف- للمقالين <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django" rel="external nofollow" target="_blank">Django Web Framework (Python)</a> و <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction" rel="external nofollow" target="_blank">Django introduction</a>.
</p>

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

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A8%D9%8A%D8%A6%D8%A9-%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%AC%D8%A7%D9%86%D8%BA%D9%88-django-r2049/" rel="">إعداد بيئة تطوير تطبيقات جانغو</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r2020/" rel="">تعرف على أمان مواقع الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/%D8%A3%D8%B7%D8%B1-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-r784/" rel="">أطر عمل الويب من طرف الخادم</a>
	</li>
	<li>
		<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>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1523/" rel="">برمجة عملاء ويب باستخدام بايثون</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2041</guid><pubDate>Mon, 07 Aug 2023 14:00:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x648;&#x64A;&#x628; &#x644;&#x625;&#x62F;&#x627;&#x631;&#x629; &#x645;&#x639;&#x644;&#x648;&#x645;&#x627;&#x62A; &#x627;&#x644;&#x639;&#x645;&#x644;&#x627;&#x621; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django &#x648;&#x631;&#x64A;&#x622;&#x643;&#x62A; React</title><link>https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D9%85%D8%B9%D9%84%D9%88%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-%D9%88%D8%B1%D9%8A%D8%A2%D9%83%D8%AA-react-r1776/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/63673827976a4_--------.png.e87b0290368553674bcaeb4690328151.png" /></p>
<p>
	يستخدم الناس أنواعًا مختلفة من الأجهزة للاتصال <a href="https://academy.hsoub.com/devops/networking/%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r571/" rel="">بالإنترنت</a> وتصفح الويب، ولهذا تحتاج إلى تمكين المستخدمين من الوصول إلى التطبيقات مهما كان موقعهم؛ ففي حالة المواقع التقليدية، يكفي غالبًا امتلاك واجهة مستخدم متجاوبة؛ بينما تحتاج في حالة التطبيقات الأعقد إلى استخدام تقنيات ومعماريات أخرى، منها امتلاك تطبيقات ريست REST مستقلة للواجهة الأمامية والواجهة الخلفية والتي يمكن تنفيذها مثل تطبيقات ويب من جهة العميل أو <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات ويب تقدّميّة Progressive Web Apps</a> -اختصارًا PWA- أو تطبيقات جوال أصلية.
</p>

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

<ul>
	<li>
		<a href="https://wiki.hsoub.com/React" rel="external">ريآكت</a>، وهو <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">إطار عمل</a> مبني <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">بلغة جافا سكريبت</a> يتيح للمطورين بناء تطبيقات ويب بواجهات أمامية وأصلية للواجهات الخلفية <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">لواجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> ريست.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">جانغو</a>، وهو إطار عمل ويب مبني بلغة بايثون مفتوح المصدر ومجاني يتبع نموذج معمارية البرمجيات <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="external nofollow">نموذج عرض متحكم Model View Controller</a> -أو اختصارًا MVC-.
	</li>
	<li>
		<a href="http://www.django-rest-framework.org/" rel="external nofollow">إطار عمل جانغو ريست</a>، الذي يمثّل أدوات قوية ومرنة لبناء واجهة برمجة تطبيقات ريست APIs بجانغو.
	</li>
</ul>

<p>
	ستبني في هذه المقالة تطبيق ويب حديث مع واجهة REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> خلفية منفصلة وواجهة أمامية مستخدمًا لهذا الغرض <a href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-react-r1072/" rel="">ريآكت</a> و<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو</a> وإطار عمل جانغو ريست، إذ يمكنك باستخدام ريآكت وجانغو معًا الاستفادة من أحدث الترقيات في جافا سكريبت وتطوير الواجهات الأمامية، وبدلًا من بناء تطبيق جانغو يستخدم محرك قوالب داخلي، ستستخدم ريآكت مثل مكتبة واجهة مستخدم UI library مستفيدًا من <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">نموذج كائن الوثيقة Document Object Model الافتراضي -أو اختصارًا DOM-</a>، والطريقة التصريحية declarative والمكونات التي تصيّر render سريعًا التغيرات على البيانات.
</p>

<p>
	يخزن تطبيق الويب الذي ستبنيه سجلات العملاء في قاعدة بيانات، ويمكنك استخدامها بمثابة نقطة بداية لتطبيق <a href="https://academy.hsoub.com/marketing/social-media/%D8%A7%D9%84%D8%AA%D9%83%D9%86%D9%88%D9%84%D9%88%D8%AC%D9%8A%D8%A7-%D9%88%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B9%D9%84%D8%A7%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-r635/" rel="">إدارة علاقات العملاء CRM</a>، وعند انتهائك ستكون قادرًا على إنشاء وقراءة وتحديث وحذف السجلات باستخدام واجهة ريآكت المُنسقة مستخدمًا <a href="https://wiki.hsoub.com/Bootstrap" rel="external">بوتستراب 4</a>.
</p>

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

<p>
	ستحتاج لإتمام هذه المقالة وتطبيق ما فيها إلى ما يلي:
</p>

<ul>
	<li>
		جهاز تطوير مع نظام تشغيل أوبنتو Ubuntu 18.04.
	</li>
	<li>
		تثبيت بايثون 3 و pip و venv على جهازك باتباع الخطوتين الأولى والثانية من مقالة <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="">كيف تثبت بايثون 3 وتعد بيئة برمجية محلية على نظام أبونتو 18.04</a>.
	</li>
	<li>
		تثبيت الإصدار 6 أو ما بعده من <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel="">نود جي إس Node.js</a> و npm 5.2 أو أعلى منه على جهازك، ويمكنك تثبيت كليهما باتباع التعليمات الواردة في مقالة <a href="https://academy.hsoub.com/devops/linux/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nodejs-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%A3%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r419/" rel="">كيف تثبت نود جي إس على نظام أوبنتو 18.04</a> حول التثبيت من مستودعات البرمجيات التي يطلق عليها اسم أرشيف الحزم الشخصية personal package archive -أو اختصارًا PPA.
	</li>
</ul>

<h2>
	الخطوة الأولى - إنشاء بيئة بايثون افتراضية وتثبيت الاعتماديات
</h2>

<p>
	ستنشئ في هذه الخطوة بيئةً افتراضيةً وتثبت الاعتمادات اللازمة لتطبيقك بما فيها جانغو وإطار عمل جانغو ريست وحزمة django-cors-headers.
</p>

<p>
	سيستخدم تطبيقنا خادمي تطوير مختلفين لجانغو و<a href="https://wiki.hsoub.com/React" rel="external">ريآكت</a>، وسيعملان على منفذين مختلفين وبمثابة نطاقين منفصلين، ولهذا نحتاج تفعيل <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AD%D9%85%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B1%D8%AF-%D8%A7%D9%84%D8%AE%D8%A7%D8%B1%D8%AC%D9%8A%D8%A9-%D9%81%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%AA%D8%AA%D8%A8%D8%B9-%D8%AD%D8%A7%D9%84%D8%AA%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1238/" rel="">سياسة تعدد الموارد</a> cross-origin resource sharing -أو اختصارًا CORS- لإرسال طلبات من نوع <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">HTTP</a> من ريآكت إلى جانغو دون التعرض للحظر على يدي المتصفح.
</p>

<p>
	انتقل إلى المجلد الأساسي وأنشئ بيئة افتراضية باستخدام وحدة <code>venv</code> في <a href="https://academy.hsoub.com/programming/python/%d8%a7%d9%84%d8%af%d9%84%d9%8a%d9%84-%d8%a7%d9%84%d8%b3%d8%b1%d9%8a%d8%b9-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-%d8%a8%d8%a7%d9%8a%d8%ab%d9%88%d9%86-python-3-r535/" rel="">بايثون 3</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_19" style=""><span class="pln">$ cd </span><span class="pun">~</span><span class="pln">
$ python3 </span><span class="pun">-</span><span class="pln">m venv </span><span class="pun">./</span><span class="pln">env</span></pre>

<p>
	فعّل البيئة الافتراضية التي أنشأتها مستخدمًا الأمر <code>source</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_21" style=""><span class="pln">$ source env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	ثم ثبّت اعتماديات المشروع مستخدمًا <code>pip</code>، وهذه الاعتمادات هي:
</p>

<ul>
	<li>
		جانغو: وهو إطار عمل ويب المشروع.
	</li>
	<li>
		إطار عمل جانغو ريست: تطبيق جانبي (منشأ من طرف ثالث) يبني واجهات برمجة التطبيقات لريست بواسطة جانغو.
	</li>
	<li>
		حزمة <code>django-cors-headers</code>: وهي حزمة تفعّل سياسة تعدد الموارد CORS.
	</li>
</ul>

<p>
	ثبّت إطار عمل جانغو بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_23" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ pip install django djangorestframework django</span><span class="pun">-</span><span class="pln">cors</span><span class="pun">-</span><span class="pln">headers</span></pre>

<p>
	والآن أصبح بإمكانك بعد أن ثبتّت اعتمادات المشروع أن تنشئ مشروع جانغو وواجهة ريآكت الأمامية.
</p>

<h2>
	الخطوة الثانية - إنشاء مشروع جانغو
</h2>

<p>
	سنولّد في هذه الخطوة مشروع جانغو باستخدام التعليمات والأدوات التالية:
</p>

<ul>
	<li>
		أداة <code>django-admin startproject project-name</code>، إذ تُعد <code>django-admin</code> أداةً تعمل في بيئة سطر الأوامر وتُستخدم لإتمام المهام بواسطة جانغو. ينشئ الأمر<code>startproject</code> مشروع جانغو جديد.
	</li>
	<li>
		أداة سكريبت <code>python manage.py startapp myapp</code>، إذ يُعد manage.py سكريبت برمجي يضاف تلقائيًا لكل مشروع جانغو وهو يؤدي عددًا من المهام الإدارية، مثل إنشاء تطبيقات جديدة وتهجير ملفات قاعدة البيانات وخدمة مشروع جانغو محلي. ينشئ الأمر <code>startapp</code> التابع لهذا السكريبت تطبيق جانغو داخل مشروع جانغو. يُقصد بالمصطلح "تطبيق application" في جانغو حزمة بايثون توفّر بعض المزايا في المشروع.
	</li>
</ul>

<p>
	ولكي تبدأ، أنشئ مشروع جانغو باستخدام الأمر <code>django-admin startproject</code>، وسنطلق على التطبيق اسم "djangoreactproject":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_25" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin startproject djangoreactproject</span></pre>

<p>
	سننظر إلى بنية المجلد لمشروع جانغو الذي نعمل عليه باستخدام الأمر <code>tree</code> قبل المتابعة.
</p>

<p>
	<strong>نصيحة:</strong> الأمر <code>tree</code> هو أمرٌ مفيد لعرض بُنى الملفات والمجلدات من مستوى سطر الأوامر، يمكنك تثبيته مستخدمًا الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_27" style=""><span class="pln">$ sudo apt</span><span class="pun">-</span><span class="pln">get install tree</span></pre>

<p>
	ولكي تستخدمه انتقل إلى المجلد الذي تريد رؤية بنيته واكتب <code>tree</code> أو اكتب المسار كاملًا وصولًا إلى نقطة البداية "tree /home/ali/ali-project".
</p>

<p>
	انتقل إلى المجلد djangoreactproject ضمن جذر مشروعك ونفذ الأمر <code>tree</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_29" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject
</span><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ tree</span></pre>

<p>
	سيظهر لك الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_31" style=""><span class="pun">├──</span><span class="pln"> djangoreactproject
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> urls</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> wsgi</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">└──</span><span class="pln"> manage</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يمثّل المجلد "djangoreactproject/~" جذر المشروع، وتوجد داخله عدة ملفات مهمة لمشروعك، هي:
</p>

<ul>
	<li>
		"manage.py": وهو سكريبت خدمي يؤدي عددًا من المهام الإدارية.
	</li>
	<li>
		"settings.py": هو ملف التهيئة الرئيسي لمشروع جانغو، حيث يمكنك تعديل إعدادات المشروع، إذ تتضمن هذه الإعدادات متحولاتٍ، مثل <code>INSTALLED_APPS</code> الذي يحدد قائمة التطبيقات النشطة في مشروعك. ويوجد في توثيق جانغو معلومات أعمق عن <a href="https://docs.djangoproject.com/en/2.0/ref/settings/" rel="external nofollow">الإعدادات المتاحة</a>.
	</li>
	<li>
		"urls.py": يحتوي هذا الملف على قائمة بنماذج محددات الموارد الموحدة URL والعروض المرتبطة بها، إذ يُنظِّم كل نموذج اتصالًا بين عنوان محدد موارد موحد URL والدالة التي يجب أن تُستدعى لذلك العنوان URL.
	</li>
</ul>

<p>
	أولى خطواتنا للعمل في المشروع هي ضبط الحزم التي ثبتناها في الخطوة السابقة ومن بينها إطار عمل جانغو ريست وحزمة جانغو CORS، وذلك بإضافتهما إلى الملف "settings.py". افتح الملف مستخدمًا الأمر <code>nano</code> أو محرر النصوص المفضل لديك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_33" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	انتقل إلى الإعداد <code>INSTALLED_APPS</code> وأضف التطبيقين "rest_framework" و "corsheaders" أسفل القائمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_35" style=""><span class="pun">...</span><span class="pln">
INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'rest_framework'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'corsheaders'</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	ثم أضف البرمجية الوسيطة <code>corsheaders.middleware.CorsMiddleware</code> من حزمة سياسة تعدد الموارد <code>CORS</code> التي ثبتناها سابقًا إلى الإعداد <code>MIDDLEWARE</code>، الذي يمثّل قائمةً بالبرمجيات الوسيطة middlewares؛ وهو صنف بايثون يحتوي على شيفرة تُعالج في كل مرة يتعامل تطبيق الويب مع طلب أو استجابة:
</p>

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

MIDDLEWARE </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="str">'django.contrib.messages.middleware.MessageMiddleware'</span><span class="pun">,</span><span class="pln">
</span><span class="str">'django.middleware.clickjacking.XFrameOptionsMiddleware'</span><span class="pun">,</span><span class="pln">
</span><span class="str">'corsheaders.middleware.CorsMiddleware'</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	يمكنك بعد ذلك تفعيل CORS، إذ يحدّد الإعداد <code>CORS_ORIGIN_ALLOW_ALL</code> ما إذا كنت ستسمح بسياسة تعدد الموارد لكل النطاقات أم لا، والإعداد <code>CORS_ORIGIN_WHITELIST</code> هو صف بايثون يحتوي على عناوين URL المسموحة.
</p>

<p>
	سيعمل خادم تطوير ريآكت على العنوان "http://localhost:3000"، لذلك سنضيف الإعدادين التاليين إلى ملف الإعدادات "settings.py":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_39" style=""><span class="pln">CORS_ORIGIN_ALLOW_ALL </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="pun">(,</span><span class="str">'CORS_ORIGIN_WHITELIST('</span><span class="pln">localhost</span><span class="pun">:</span><span class="lit">3000</span></pre>

<p>
	حيث يمكنك إضافة هذين الإعدادين في أي مكان تشاء من هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_41" style=""><span class="pun">...</span><span class="pln">
CORS_ORIGIN_ALLOW_ALL </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">

CORS_ORIGIN_WHITELIST </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
       </span><span class="str">'localhost:3000'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
</span><span class="pun">…</span></pre>

<p>
	ويمكنك العثور على المزيد من خيارات التهيئة في وثائق <a href="https://github.com/adamchainz/django-cors-headers#configuration" rel="external nofollow">django-cors-headers</a>.
</p>

<p>
	احفظ الملف واخرج من محرر النصوص عندما تنتهي.
</p>

<p>
	نحتاج إلى إنشاء تطبيق جانغو جديد داخل المجلد "djangoreactproject/~" اسمه "customers":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_43" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py startapp customers</span></pre>

<p>
	سيحتوي هذا التطبيق على النماذج models والعروض views لإدارة العملاء؛ إذ تعرّف النماذجُ الحقولَ والسلوكات لبيانات التطبيق؛ بينما تمكّن العروض تطبيقنا من التعامل مع الطلبات على النحو المناسب وإعادة الاستجابات المطلوبة على النحو المناسب أيضًا.
</p>

<p>
	بعد ذلك، أضف التطبيق إلى قائمة التطبيقات المثبتة في ملف المشروع "settings.py" لكي يتعرف جانغو عليه على أنه جزءٌ من المشروع. افتح الملف "settings.py" مرةً أخرى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_45" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أضف التطبيق "customers":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_47" style=""><span class="pun">...</span><span class="pln">
INSTALLED_APPS </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="str">'rest_framework'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'corsheaders'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'customers'</span><span class="pln">
</span><span class="pun">]</span><span class="pln">
</span><span class="pun">…</span></pre>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_49" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	وشغّل خادم التطوير المحلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_51" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	سترى خرجًا يشابه التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_53" style=""><span class="typ">Performing</span><span class="pln"> system checks</span><span class="pun">...</span><span class="pln">

</span><span class="typ">System</span><span class="pln"> check identified no issues </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> silenced</span><span class="pun">).</span><span class="pln">
</span><span class="typ">October</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2018</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">15</span><span class="pun">:</span><span class="lit">14</span><span class="pun">:</span><span class="lit">50</span><span class="pln">
</span><span class="typ">Django</span><span class="pln"> version </span><span class="lit">2.1</span><span class="pun">.</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> using settings </span><span class="str">'djangoreactproject.settings'</span><span class="pln">
</span><span class="typ">Starting</span><span class="pln"> development server at http</span><span class="pun">://</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">
</span><span class="typ">Quit</span><span class="pln"> the server </span><span class="kwd">with</span><span class="pln"> CONTROL</span><span class="pun">-</span><span class="pln">C</span><span class="pun">.</span></pre>

<p>
	سيعمل تطبيق الويب من خلال العنوان "http://127.0.0.1:8000"، وإذا انتقلت إلى هذا العنوان في متصفحك فيفترض أن ترى الصفحة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111551" href="https://academy.hsoub.com/uploads/monthly_2022_11/636737e58bcab_002-django_home.png.112709370f7d9fa515a4a003e5827f3d.png" rel=""><img alt='نتيجة عمل تطبيق الويب من خلال العنوان "http://127.0.0.1:8000"' class="ipsImage ipsImage_thumbnailed" data-fileid="111551" data-unique="mjfz49x64" style="width: 790px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636737e71341c_002-django_home.thumb.png.c2dcbfe6609509bd021f0f58142168fc.png"></a>
</p>

<p>
	دع التطبيق يعمل وافتح نافذة طرفية جديدة لمتابعة تطوير المشروع.
</p>

<h2>
	الخطوة الثالثة - إنشاء الواجهة الأمامية لريآكت
</h2>

<p>
	سننشئ في هذا القسم تطبيق الواجهة الأمامية لمشروعنا مستخدمين ريآكت؛ إذ يوجد لدى ريآكت برنامج خدمي رسمي يسمح لك بتوليد مشاريع ريآكت بسرعة دون الحاجة إلى ضبط <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-webpack-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-r866/" rel="">مجمع الوحدات Webpack</a>، التي تمثّل مجمع وحدات module bundler يُستخدم لتجميع أصول الويب، مثل شيفرة <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a> و <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> والصور. قبل أن تتمكن من استخدام Webpack، ستحتاج عادةً إلى تحديد خيارات ضبط متعددة، لكن بفضل الأداة <code>create-react-app</code> لن تحتاج للتعامل مع Webpack مباشرةً حتى تقرر أو عندما تكون بحاجةٍ لمزيدٍ من التحكم. يمكنك استخدام أداة <a href="https://github.com/zkat/npx" rel="external nofollow">npx</a> (وهي أداة تنفّذ الملفات الثنائية لحزم <code>npm</code>) لتشغيل <code>create-react-app</code>.
</p>

<p>
	تأكد في نافذة الطرفية الثانية أنك موجود داخل مجلد المشروع:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_62" style=""><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span></pre>

<p>
	أنشئ مشروع ريآكت اسمه "<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-frontend-web-development/" rel="">frontend</a>" باستخدام <code>create-react-app</code> و <code>npx</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_64" style=""><span class="pln">$ npx create</span><span class="pun">-</span><span class="pln">react</span><span class="pun">-</span><span class="pln">app frontend</span></pre>

<p>
	ثم انتقل إلى داخل تطبيق ريآكت وشغّل خادم التطوير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_66" style=""><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">frontend
$ npm start</span></pre>

<p>
	سيعمل تطبيقك باستخدام العنوان "/http://localhost:3000":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111552" href="https://academy.hsoub.com/uploads/monthly_2022_11/636737e82ca31_003-react_home.png.fde086a1b61a2db26cf7f02b391ccb82.png" rel=""><img alt='عمل التطبيق باستخدام العنوان "/http://localhost:3000"' class="ipsImage ipsImage_thumbnailed" data-fileid="111552" data-unique="jutlzhr0l" style="width: 650px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/636737e9b7c9a_003-react_home.thumb.png.6a2ec2db75dc17fa777931b7c2ee2f64.png"></a>
</p>

<p>
	دع خادم تطوير ريآكت يعمل وافتح نافذة طرفية جديدة للمتابعة.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_70" style=""><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject
$ tree</span></pre>

<p>
	سترى بنيةً تشبه التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_72" style=""><span class="pun">├──</span><span class="pln"> customers
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> apps</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> migrations
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> models</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> tests</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">├──</span><span class="pln"> djangoreactproject
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __pycache__
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> urls</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> wsgi</span><span class="pun">.</span><span class="pln">py
</span><span class="pun">├──</span><span class="pln"> frontend
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> package</span><span class="pun">.</span><span class="pln">json
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> public
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> favicon</span><span class="pun">.</span><span class="pln">ico
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">html
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> manifest</span><span class="pun">.</span><span class="pln">json
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> README</span><span class="pun">.</span><span class="pln">md
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> src
</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">App</span><span class="pun">.</span><span class="pln">css
</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">App</span><span class="pun">.</span><span class="pln">js
</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">App</span><span class="pun">.</span><span class="pln">test</span><span class="pun">.</span><span class="pln">js
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">css
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">js
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> logo</span><span class="pun">.</span><span class="pln">svg
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> registerServiceWorker</span><span class="pun">.</span><span class="pln">js
</span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> yarn</span><span class="pun">.</span><span class="pln">lock
</span><span class="pun">└──</span><span class="pln"> manage</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	سيستخدم تطبيقنا بوتستراب 4 لتحيدد تنسيق style واجهة ريآكت، لذلك سنضمّنه في الملف "frontend/src/App.css" الذي يدير إعدادات CSS. افتح الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_74" style=""><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">frontend</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="typ">App</span><span class="pun">.</span><span class="pln">css</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_76" style=""><span class="lit">@import</span><span class="pln">  </span><span class="str">'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css'</span><span class="pun">;</span></pre>

<p>
	تعليمة <code>import@</code> هي تعليمة CSS تُستخدم لاستيراد قواعد التنسيق style rules من صفحات تنسيق أخرى.
</p>

<p>
	الآن بعد أن انتهينا من إنشاء تطبيق الواجهة الأمامية والواجهة الخلفية، دعنا ننشئ نموذج العميل Customer وبعض البيانات التجريبية.
</p>

<h2>
	الخطوة الرابعة - إنشاء نموذج العميل وبيانات التهيئة
</h2>

<p>
	بعد أن انتهينا من إنشاء تطبيق جانغو والواجهة الأمامية لريآكت، ستكون خطوتنا التالية هي إنشاء نموذج العميل Customer، الذي يمثّل جدول قاعدة البيانات الذي سيخزن معلومات العملاء. لن تحتاج إلى أي أوامر <a href="https://wiki.hsoub.com/SQL" rel="external">SQL</a>، إذ سيتولى الرابط العلائقي للكائنات في جانغو Object Relational Mapper -أو اختصارًا ORM- أمر العمليات التي تجري على قاعدة البيانات من خلال إسقاط أصناف بايثون ومتحولاته على جداول SQL وأعمدته، وبهذه الطريقة يكون الرابط العلائقي للكائنات في جانغو قد جرّد تفاعلات SQL مع قاعدة البيانات من خلال واجهة <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a>.
</p>

<p>
	فعّل البيئة الافتراضية من جديد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_80" style=""><span class="pln">$ cd </span><span class="pun">~</span><span class="pln">
$ source env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	انتقل إلى المجلد "customers" وافتح الملف "models.py"، وهو ملف بايثون يخزن كافة نماذج تطبيقك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_82" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">
</span><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano models</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	سيحتوي الملف على المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_84" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models
</span><span class="com"># Create your models here.</span></pre>

<p>
	نشير إلى أنه قد استوردت واجهة <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA/" rel="">برمجة التطبيقات</a> لنموذج العملاء سلفًا ضمن الملف بفضل تعليمة الاستيراد<code>from django.db import models</code>. ستضيف الآن الصنف <code>Customer</code> المشتق من الصنف <code>models.Model</code>. كل نموذج في جانغو هو صنف بايثون مشتق من <a href="https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model" rel="external nofollow">django.db.models.Model</a>.
</p>

<p>
	سيكون في نموذج العميل "Customer" حقول قاعدة البيانات التالية:
</p>

<ul>
	<li>
		first_name: الاسم الأول للعميل.
	</li>
	<li>
		last_name: اسم العائلة للعميل.
	</li>
	<li>
		email: البريد الإلكتروني للعميل.
	</li>
	<li>
		phone: رقم هاتف العميل.
	</li>
	<li>
		address: عنوان العميل.
	</li>
	<li>
		description: وصف العميل.
	</li>
	<li>
		createdAt: تاريخ إضافة العميل.
	</li>
</ul>

<p>
	سنضيف أيضًا الدالة <code>()__str__</code> التي تعرّف طريقة عرض النموذج، والذي سيكون في حالتنا مع الاسم الأول للعميل. ولمزيدٍ من التفاصيل عن إنشاء الأصناف وتعريف الكائنات يرجى الاطلاع على المقالة <a href="https://academy.hsoub.com/programming/python/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D8%A3%D8%B5%D9%86%D8%A7%D9%81-%D9%88%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r754/" rel="">كيف تبني الأصناف وتعرف الكائنات في بايثون 3</a>.
</p>

<p>
	أضف الشيفرة التالية إلى الملف "models.py":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_86" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    first_name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="str">"First name"</span><span class="pun">,</span><span class="pln"> max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    last_name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="str">"Last name"</span><span class="pun">,</span><span class="pln"> max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">EmailField</span><span class="pun">()</span><span class="pln">
    phone </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
    address </span><span class="pun">=</span><span class="pln">  models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">(</span><span class="pln">blank</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> null</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    description </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">(</span><span class="pln">blank</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> null</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    createdAt </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="str">"Created At"</span><span class="pun">,</span><span class="pln"> auto_now_add</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __str__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">first_name</span></pre>

<p>
	ثم هجّر قاعدة البيانات لإنشاء جداول <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a>. ينشئ الأمر <code>makemigrations</code> ملفات التهجير التي تضاف فيها التغييرات على النموذج، في حين يطبّق <code>migrate</code> التغييرات في ملفات التهجير إلى قاعدة البيانات.
</p>

<p>
	عُد الآن إلى المجلد الجذر للمشروع:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_89" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span></pre>

<p>
	ونفذ ما يلي من أجل إنشاء ملفات التهجير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_91" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations</span></pre>

<p>
	ستحصل على خرج يشبه التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_93" style=""><span class="pln">customers</span><span class="pun">/</span><span class="pln">migrations</span><span class="pun">/</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Create</span><span class="pln"> model </span><span class="typ">Customer</span></pre>

<p>
	طبّق هذه التغييرات على قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_101" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	وسترى خرجًا يشير إلى نجاح عملية التهجير:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_664_99" style=""><span class="typ">Operations</span><span class="pln"> to perform</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Apply</span><span class="pln"> all migrations</span><span class="pun">:</span><span class="pln"> admin</span><span class="pun">,</span><span class="pln"> auth</span><span class="pun">,</span><span class="pln"> contenttypes</span><span class="pun">,</span><span class="pln"> customers</span><span class="pun">,</span><span class="pln"> sessions
</span><span class="typ">Running</span><span class="pln"> migrations</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Applying</span><span class="pln"> customers</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK</span></pre>

<p>
	ستستخدم الآن ملف تهجير البيانات لإنشاء بيانات العميل المبدئية،إن أن <a href="https://docs.djangoproject.com/en/2.0/topics/migrations/#data-migrations" rel="external nofollow">ملف تهجير البيانات</a> هو تهجير يضيف البيانات أو يعدّلها في قاعدة البيانات. أنشئ ملف تهجير بيانات فارغ للتطبيق customers:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_103" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations </span><span class="pun">--</span><span class="pln">empty </span><span class="pun">--</span><span class="pln">name customers customers</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_105" style=""><span class="typ">Migrations</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="str">'customers'</span><span class="pun">:</span><span class="pln">
  customers</span><span class="pun">/</span><span class="pln">migrations</span><span class="pun">/</span><span class="lit">0002</span><span class="pln">_customers</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	لاحظ أن اسم ملف التهجير هو "customers.py‏_0002".
</p>

<p>
	انتقل بعد ذلك إلى داخل مجلد التهجيرات للتطبيق customers.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_107" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">migrations</span></pre>

<p>
	افتح ملف التهجير المنشأ للتو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_109" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="lit">0002</span><span class="pln">_customers</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	وهذا هو محتوى التهيئة للملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_111" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> migrations

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Migration</span><span class="pun">(</span><span class="pln">migrations</span><span class="pun">.</span><span class="typ">Migration</span><span class="pun">):</span><span class="pln">
    dependencies </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'customers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0001_initial'</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
    operations </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">]</span></pre>

<p>
	تستورد تعليمة الاستيراد واجهة برمجة التطبيقات للملف "migrations" وواجهة برمجة التطبيقات لجانغو من أجل إنشاء التهجيرات من الملف "django.db" والتي هي حزمة مبنية مسبقًا built-in تحتوي على الأصناف اللازمة للعمل مع قواعد البيانات.
</p>

<p>
	الصنف <code>Migration</code> هو صنف بايثون يصف العمليات التي تُنفذ عند تهجير قواعد البيانات، وهو امتداد للصنف <code>migrations.Migration</code>، ويملك قائمتين:
</p>

<ul>
	<li>
		dependencies: تحتوي على التهجيرات المعتمدة.
	</li>
	<li>
		operations: تحتوي على العمليات التي ستُنفذ عندما نطبّق التهجير.
	</li>
</ul>

<p>
	الآن، أضف <a href="https://academy.hsoub.com/programming/python/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r292/" rel="">تابعًا</a> لإنشاء بيانات تجريبية للعملاء قبل تعريف الصنف <code>Migration</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_113" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> create_data</span><span class="pun">(</span><span class="pln">apps</span><span class="pun">,</span><span class="pln"> schema_editor</span><span class="pun">):</span><span class="pln">
    </span><span class="typ">Customer</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> apps</span><span class="pun">.</span><span class="pln">get_model</span><span class="pun">(</span><span class="str">'customers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Customer'</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Customer</span><span class="pun">(</span><span class="pln">first_name</span><span class="pun">=</span><span class="str">"Customer 001"</span><span class="pun">,</span><span class="pln"> last_name</span><span class="pun">=</span><span class="str">"Customer 001"</span><span class="pun">,</span><span class="pln"> email</span><span class="pun">=</span><span class="str">"customer001@email.com"</span><span class="pun">,</span><span class="pln"> phone</span><span class="pun">=</span><span class="str">"00000000"</span><span class="pun">,</span><span class="pln"> address</span><span class="pun">=</span><span class="str">"Customer 000 Address"</span><span class="pun">,</span><span class="pln"> description</span><span class="pun">=</span><span class="pln"> </span><span class="str">"Customer 001 description"</span><span class="pun">).</span><span class="pln">save</span><span class="pun">()</span><span class="pln">

</span><span class="pun">...</span></pre>

<p>
	أمسكنا grab في هذا التابع الصنف <code>Customer</code> التابع للتطبيق <code>customers</code> وأنشأنا عميلًا تجريبيًّا لإدخاله إلى قاعدة البيانات.
</p>

<p>
	للحصول على الصنف <code>Customer</code>، الذي سيمكّن من إنشاء عملاء جدد، نستخدم التابع <code>()get_model</code> للكائن <code>apps</code>، الذي يمثّل <a href="https://docs.djangoproject.com/en/2.1/ref/applications/#django.apps.apps" rel="external nofollow">مسجلًا registry</a> للتطبيقات المثبتة ونماذج قواعد البيانات الخاصة بها.
</p>

<p>
	سيمرّر الكائن apps من التابع <code>()RunPython</code> عندما نستخدمه لتشغيل <code>()create_data</code>. أضف التابع <code>()migrations.RunPython</code> إلى القائمة الفارغة <code>operations</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_116" style=""><span class="pun">...</span><span class="pln">
    operations </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        migrations</span><span class="pun">.</span><span class="typ">RunPython</span><span class="pun">(</span><span class="pln">create_data</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">]</span></pre>

<p>
	يُعد التابع <code>()RunPython</code> جزءًا من واجهة برمجة التطبيقات للتهجيرات التي تسمح لك بتشغيل شيفرة بايثون معينة في تهجير ما. تحدد القائمة <code>operations</code> أن هذا التابع سيُنفّذ عندما نطبق التهجير.
</p>

<p>
	وفيما يلي الملف كاملًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_118" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> migrations

</span><span class="kwd">def</span><span class="pln"> create_data</span><span class="pun">(</span><span class="pln">apps</span><span class="pun">,</span><span class="pln"> schema_editor</span><span class="pun">):</span><span class="pln">
    </span><span class="typ">Customer</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> apps</span><span class="pun">.</span><span class="pln">get_model</span><span class="pun">(</span><span class="str">'customers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Customer'</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Customer</span><span class="pun">(</span><span class="pln">first_name</span><span class="pun">=</span><span class="str">"Customer 001"</span><span class="pun">,</span><span class="pln"> last_name</span><span class="pun">=</span><span class="str">"Customer 001"</span><span class="pun">,</span><span class="pln"> email</span><span class="pun">=</span><span class="str">"customer001@email.com"</span><span class="pun">,</span><span class="pln"> phone</span><span class="pun">=</span><span class="str">"00000000"</span><span class="pun">,</span><span class="pln"> address</span><span class="pun">=</span><span class="str">"Customer 000 Address"</span><span class="pun">,</span><span class="pln"> description</span><span class="pun">=</span><span class="pln"> </span><span class="str">"Customer 001 description"</span><span class="pun">).</span><span class="pln">save</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Migration</span><span class="pun">(</span><span class="pln">migrations</span><span class="pun">.</span><span class="typ">Migration</span><span class="pun">):</span><span class="pln">
    dependencies </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'customers'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'0001_initial'</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
    operations </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        migrations</span><span class="pun">.</span><span class="typ">RunPython</span><span class="pun">(</span><span class="pln">create_data</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">]</span></pre>

<p>
	ولمزيدٍ من المعلومات عن تهجيرات البيانات، راجع التوثيق <a href="https://docs.djangoproject.com/en/2.0/topics/migrations/#data-migrations" rel="external nofollow">تهجير البيانات في جانغو</a>.
</p>

<p>
	الآن لتهجير قاعدة بياناتك، عُد أولًا إلى مجلد الجذر لمشروعك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_120" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span></pre>

<p>
	هجّر قاعدة بياناتك لتنشئ البيانات التجريبية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_122" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	سنرى خرجًا يؤكد على نجاح عملية التهجير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_125" style=""><span class="typ">Operations</span><span class="pln"> to perform</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Apply</span><span class="pln"> all migrations</span><span class="pun">:</span><span class="pln"> admin</span><span class="pun">,</span><span class="pln"> auth</span><span class="pun">,</span><span class="pln"> contenttypes</span><span class="pun">,</span><span class="pln"> customers</span><span class="pun">,</span><span class="pln"> sessions
</span><span class="typ">Running</span><span class="pln"> migrations</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Applying</span><span class="pln"> customers</span><span class="pun">.</span><span class="lit">0002</span><span class="pln">_customers</span><span class="pun">...</span><span class="pln"> OK</span></pre>

<p>
	ولمزيدٍ من المعلومات عن العملية، راجع مقالة <a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85-%D8%B9%D9%86-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-django-r405/" rel="">كيف تنشئ نماذج جانغو</a>.
</p>

<p>
	وهكذا بعد إنشاء نموذج العميل والبيانات التوضيحية، يمكننا المتابعة إلى بناء واجهة برمجة التطبيقات لريست REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>.
</p>

<h2>
	الخطوة الخامسة - إنشاء واجهة برمجة التطبيقات لريست REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	سننشئ في هذه الخطوة واجهة برمجة التطبيقات لريست باستخدام إطار عمل جانغو ريست، إذ سننشئ عدة عروض مختلفة لواجهة برمجة التطبيقات؛ إذ يُقصد بعرض واجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> view دالة تعالج طلب واجهة برمجة تطبيقات أو استدعاء واجهة برمجة التطبيقات؛ في حين أن نقطة نهاية واجهة برمجة التطبيقات هي عنوان URL متفرد يمثّل نقطة تماس مع نظام ريست. على سبيل المثال، عندما يرسل المستخدم طلب من نوع GET إلى نقطة نهاية واجهة برمجة التطبيقات، يستدعي جانغو الدالة المقابلة، أو عرض واجهة برمجة التطبيقات لمعالجة الطلب وإعادة أي نتائج محتملة.
</p>

<p>
	سنستفيد أيضًا من <a href="https://www.django-rest-framework.org/api-guide/serializers/" rel="external nofollow">المسلسِلات Serializers</a>؛ إذ يسمح المسلسِل في إطار عمل جانغو بأن تُحوّل نسخ النماذج المعقدة ومجموعات الاستعلام QuerySets إلى صيغة محتوى JSON من أجل استهلاك واجهة برمجة التطبيقات، ويمكن أن يعمل صنف المسلسِل في الاتجاه الآخر أيضًا، إذ يزوِّد بآليات لتحليل وإلغاء سَلسَلة البيانات إلى نماذج جانغو ومجموعات استعلامه.
</p>

<p>
	ستتضمن نقاط نهاية واجهة برمجة التطبيقات ما يلي:
</p>

<ul>
	<li>
		"api/customers": تُستخدم نقطة النهاية هذه لإنشاء عملاء وإعادة مجموعات العملاء المرقمة.
	</li>
	<li>
		"&lt;api/customers/&lt;pk": تُستخدم نقطة النهاية هذه للحصول على عملاء منفردين وتحديثهم وحذفهم بالاستعانة بمفتاح أساسي أو معرّف id.
	</li>
</ul>

<p>
	سننشئ أيضًا عناوين URL في الملف "urls.py" التابع للمشروع من أجل نقاط النهاية المقابلة، أي "api/customers" و "&lt;api/customers/&lt;pk".
</p>

<p>
	دعنا نبدأ بإنشاء الصنف <code>serializer</code> من أجل نموذجنا <code>Customer</code>.
</p>

<h3>
	إضافة صنف المسسلسل Serializer
</h3>

<p>
	يُعد إنشاء صنف مسلسِل لنموذج "Customer" ضروري لتحويل نسخ العملاء ومجموعات الاستعلام QuerySets من وإلى <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a>، ولإنشاء الصنف المسلسِل، أنشئ أولًا الملف "serializers.py" داخل التطبيق "customers":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_128" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">
</span><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano serializers</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أضف الشيفرة التالية لاستيراد واجهة برمجة التطيبقات للمسلسِلات ونموذج العميل <code>Customer</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_130" style=""><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> serializers
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Customer</span></pre>

<p>
	ثم أنشئ صنف مسلسِل مُمتد عن الصنف <code>serializers.ModelSerializer</code> ويحدد الحقول التي ستُسلسَل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_132" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">serializers</span><span class="pun">.</span><span class="typ">ModelSerializer</span><span class="pun">):</span><span class="pln">

    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pln"> 
        fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'pk'</span><span class="pun">,</span><span class="str">'first_name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'last_name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'email'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'phone'</span><span class="pun">,</span><span class="str">'address'</span><span class="pun">,</span><span class="str">'description'</span><span class="pun">)</span></pre>

<p>
	يحدد الصنف <code>Meta</code> النموذج والحقول التي ستُسلسَل، وهي:
</p>

<ul>
	<li>
		<code>pk</code>
	</li>
	<li>
		<code>first_name</code>
	</li>
	<li>
		<code>last_name</code>
	</li>
	<li>
		<code>email</code>
	</li>
	<li>
		<code>phone</code>
	</li>
	<li>
		<code>address</code>
	</li>
	<li>
		<code>description</code>
	</li>
</ul>

<p>
	وهذا هو المحتوى الكامل لملف serializers.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_134" style=""><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> serializers
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Customer</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">serializers</span><span class="pun">.</span><span class="typ">ModelSerializer</span><span class="pun">):</span><span class="pln">

    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pln"> 
        fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'pk'</span><span class="pun">,</span><span class="str">'first_name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'last_name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'email'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'phone'</span><span class="pun">,</span><span class="str">'address'</span><span class="pun">,</span><span class="str">'description'</span><span class="pun">)</span></pre>

<p>
	الآن وبعد أن انتهينا من إنشاء صنف المسلسِل، يمكننا إضافة عروض واجهة برمجة التطبيقات.
</p>

<h3>
	إضافة عروض واجهة برمجة التطبيقات
</h3>

<p>
	سننشئ في هذا القسم عروض <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> لتطبيقنا الذي سيستدعيه جانغو عندما يزور المستخدمُ نقطةَ النهاية المقابلة لدالة العرض.
</p>

<p>
	افتح الملف التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_136" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">views</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	احذف محتوى الملف وأضف أوامر الاستيراد التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_138" style=""><span class="kwd">from</span><span class="pln"> rest_framework</span><span class="pun">.</span><span class="pln">response </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Response</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> rest_framework</span><span class="pun">.</span><span class="pln">decorators </span><span class="kwd">import</span><span class="pln"> api_view
</span><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> status

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">paginator </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Paginator</span><span class="pun">,</span><span class="pln"> </span><span class="typ">EmptyPage</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PageNotAnInteger</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Customer</span><span class="pln"> 
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">serializers </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span></pre>

<p>
	نحن نستورد المسلسِل الذي أنشأناه إلى جانب نموذج العميل <code>Customer</code> وجانغو وواجهات برمجة التطبيقات لجانغو ريست.
</p>

<p>
	بعد ذلك، أضف العرض الذي سيتولى معالجة طلبات من نوع POST و GET HTTP:
</p>

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

</span><span class="lit">@api_view</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">
</span><span class="kwd">def</span><span class="pln"> customers_list</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="str">"""
 List  customers, or create a new customer.
 """</span><span class="pln">
    </span><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">'GET'</span><span class="pun">:</span><span class="pln">
        data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        nextPage </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        previousPage </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        customers </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
        page </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">GET</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'page'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        paginator </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Paginator</span><span class="pun">(</span><span class="pln">customers</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="pln">page</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">PageNotAnInteger</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">EmptyPage</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="pln">paginator</span><span class="pun">.</span><span class="pln">num_pages</span><span class="pun">)</span><span class="pln">

        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">}</span><span class="pln"> </span><span class="pun">,</span><span class="pln">many</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">has_next</span><span class="pun">():</span><span class="pln">
            nextPage </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">next_page_number</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">has_previous</span><span class="pun">():</span><span class="pln">
            previousPage </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">previous_page_number</span><span class="pun">()</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">({</span><span class="str">'data'</span><span class="pun">:</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">data </span><span class="pun">,</span><span class="pln"> </span><span class="str">'count'</span><span class="pun">:</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> </span><span class="str">'numpages'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">num_pages</span><span class="pun">,</span><span class="pln"> </span><span class="str">'nextlink'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/api/customers/?page='</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">nextPage</span><span class="pun">),</span><span class="pln"> </span><span class="str">'prevlink'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/api/customers/?page='</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">previousPage</span><span class="pun">)})</span><span class="pln">

    </span><span class="kwd">elif</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">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">data</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">is_valid</span><span class="pun">():</span><span class="pln">
            serializer</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_201_CREATED</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_400_BAD_REQUEST</span><span class="pun">)</span></pre>

<p>
	نستخدم أولًا المزخرِف <code>(['api_view(['GET', 'POST@</code> لإنشاء عرض واجهة برمجة تطبيقات يمكنه قبول طلبات <code>GET</code> و <code>POST</code>، إذ يُعد <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B2%D8%AE%D8%B1%D9%81%D8%A7%D8%AA-decorators-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r303/" rel="">المزخرِف decorator</a> دالة تأخذ دالةً أخرى وتمدّدها extend تلقائيًا.
</p>

<p>
	نستخدم المتغيّر <code>request.method</code> داخل متن التابع لفحص تابع HTTP الحالي وتنفيذ المنطق المقابل اعتمادًا على نوع الطلب:
</p>

<ul>
	<li>
		إذا كان الطلب من النوع GET، يرقّم التابع البيانات باستخدام <a href="https://docs.djangoproject.com/en/2.0/topics/pagination" rel="external nofollow">مرقّم جانغو Django Paginator</a> ويعيد الصفحة الأولى من البيانات بعد السَّلسَلَة، وعدد العملاء المتوفرين وعدد الصفحات المتوفرة والروابط إلى الصفحات السابقة واللاحقة. المرقّم paginator هو صنف جانغو داخلي يقسّم قوائم البيانات في عدة صفحات ويزوّد بتوابع للوصول إلى عناصر كل صفحة.
	</li>
	<li>
		إذا كان الطلب من النوع POST، يسلسِل التابع بيانات العميل المستلمة ثم يستدعي التابع <code>()save</code> لكائن المسلسِل، ثم يعيد كائن استجابة Response وهو نسخة عن <a href="https://docs.djangoproject.com/en/2.0/ref/request-response/#httpresponse-objects" rel="external nofollow">استجابة http أو HttpResponse</a> مع رمز الحالة 201. كل عرض تنشؤه مسؤول عن إعادة كائن <code>HttpResponse</code>. يحفظ التابع <code>()save</code> البيانات المسلسَلة في قاعدة البيانات.
	</li>
</ul>

<p>
	أضف الآن عرض واجهة برمجة التطبيقات الذي سيكون مسؤولًا عن معالجة طلبات GET و PUT و DELETE من أجل جلب وتحديث وحذف العملاء اعتمادًا على المفتاح الأساسي <code>pk</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_142" style=""><span class="pun">...</span><span class="pln">
</span><span class="lit">@api_view</span><span class="pun">([</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'PUT'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'DELETE'</span><span class="pun">])</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> customers_detail</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">):</span><span class="pln">
 </span><span class="str">"""
 Retrieve, update or delete a customer by id/pk.
 """</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        customer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">=</span><span class="pln">pk</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="typ">DoesNotExist</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_404_NOT_FOUND</span><span class="pun">)</span><span class="pln">

    </span><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">'GET'</span><span class="pun">:</span><span class="pln">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">})</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">elif</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">'PUT'</span><span class="pun">:</span><span class="pln">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">})</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">is_valid</span><span class="pun">():</span><span class="pln">
            serializer</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_400_BAD_REQUEST</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">elif</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">'DELETE'</span><span class="pun">:</span><span class="pln">
        customer</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_204_NO_CONTENT</span><span class="pun">)</span></pre>

<p>
	زُخرِف التابعُ باستخدام <code>(['api_view(['GET', 'PUT', 'DELETE@</code> للإشارة إلى أنه عرض واجهة برمجة تطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> view يمكنه قبول طلبات من النوع GET و PUT و DELETE.
</p>

<p>
	التحقق الموجود في الحقل <code>request.method</code> يتحقق من تابع الطلب واعتمادًا على قيمته يستدعي المنطق المناسب:
</p>

<ul>
	<li>
		إذا كان الطلب من النوع GET، تُسَلسَلُ بياناتُ العميل وترسلُ باستخدام كائن استجابة <code>Response</code>.
	</li>
	<li>
		إذا كان الطلب من النوع PUT، ينشئ التابع مسلسِلًا لبيانات العميل الجديد، ثم يستدعي التابع <code>()save</code> لكائن المسلسَل المُنشأ، وأخيرًا يرسل كائن الاستجابة <code>Response</code> مع العميل المحدّث.
	</li>
	<li>
		إذا كان الطلب من النوع DELETE، يستدعي التابعُ التابعَ <code>()delete</code> لكائن العميل لحذفه، ثم يعيد كائن استجابة دون بيانات.
	</li>
</ul>

<p>
	يبدو ملف "views.py" المكتمل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_144" style=""><span class="kwd">from</span><span class="pln"> rest_framework</span><span class="pun">.</span><span class="pln">response </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Response</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> rest_framework</span><span class="pun">.</span><span class="pln">decorators </span><span class="kwd">import</span><span class="pln"> api_view
</span><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> status

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">paginator </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Paginator</span><span class="pun">,</span><span class="pln"> </span><span class="typ">EmptyPage</span><span class="pun">,</span><span class="pln"> </span><span class="typ">PageNotAnInteger</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Customer</span><span class="pln"> 
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">serializers </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">


</span><span class="lit">@api_view</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">
</span><span class="kwd">def</span><span class="pln"> customers_list</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="str">"""
 List  customers, or create a new customer.
 """</span><span class="pln">
    </span><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">'GET'</span><span class="pun">:</span><span class="pln">
        data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
        nextPage </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        previousPage </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        customers </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln">
        page </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">GET</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">'page'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        paginator </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Paginator</span><span class="pun">(</span><span class="pln">customers</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="pln">page</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">PageNotAnInteger</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">EmptyPage</span><span class="pun">:</span><span class="pln">
            data </span><span class="pun">=</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">page</span><span class="pun">(</span><span class="pln">paginator</span><span class="pun">.</span><span class="pln">num_pages</span><span class="pun">)</span><span class="pln">

        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">}</span><span class="pln"> </span><span class="pun">,</span><span class="pln">many</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">has_next</span><span class="pun">():</span><span class="pln">
            nextPage </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">next_page_number</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">has_previous</span><span class="pun">():</span><span class="pln">
            previousPage </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">previous_page_number</span><span class="pun">()</span><span class="pln">

        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">({</span><span class="str">'data'</span><span class="pun">:</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">data </span><span class="pun">,</span><span class="pln"> </span><span class="str">'count'</span><span class="pun">:</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">count</span><span class="pun">,</span><span class="pln"> </span><span class="str">'numpages'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> paginator</span><span class="pun">.</span><span class="pln">num_pages</span><span class="pun">,</span><span class="pln"> </span><span class="str">'nextlink'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/api/customers/?page='</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">nextPage</span><span class="pun">),</span><span class="pln"> </span><span class="str">'prevlink'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/api/customers/?page='</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> str</span><span class="pun">(</span><span class="pln">previousPage</span><span class="pun">)})</span><span class="pln">

    </span><span class="kwd">elif</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">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">data</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">is_valid</span><span class="pun">():</span><span class="pln">
            serializer</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_201_CREATED</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_400_BAD_REQUEST</span><span class="pun">)</span><span class="pln">

</span><span class="lit">@api_view</span><span class="pun">([</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'PUT'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'DELETE'</span><span class="pun">])</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> customers_detail</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">):</span><span class="pln">
    </span><span class="str">"""
 Retrieve, update or delete a customer by id/pk.
 """</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        customer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">=</span><span class="pln">pk</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">Customer</span><span class="pun">.</span><span class="typ">DoesNotExist</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_404_NOT_FOUND</span><span class="pun">)</span><span class="pln">

    </span><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">'GET'</span><span class="pun">:</span><span class="pln">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">})</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">elif</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">'PUT'</span><span class="pun">:</span><span class="pln">
        serializer </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CustomerSerializer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln">context</span><span class="pun">={</span><span class="str">'request'</span><span class="pun">:</span><span class="pln"> request</span><span class="pun">})</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> serializer</span><span class="pun">.</span><span class="pln">is_valid</span><span class="pun">():</span><span class="pln">
            serializer</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">serializer</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">,</span><span class="pln"> status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_400_BAD_REQUEST</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">elif</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">'DELETE'</span><span class="pun">:</span><span class="pln">
        customer</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">()</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Response</span><span class="pun">(</span><span class="pln">status</span><span class="pun">=</span><span class="pln">status</span><span class="pun">.</span><span class="pln">HTTP_204_NO_CONTENT</span><span class="pun">)</span></pre>

<p>
	يمكننا الآن المتابعة إلى إنشاء نقاط النهاية.
</p>

<h3>
	إضافة نقاط النهاية لواجهة برمجة التطبيقات
</h3>

<p>
	سننشئ الآن نقطتي النهاية لواجهة برمجة التطبيقات، الأولى <code>/‎api/customers</code> من أجل الاستعلام عن العملاء وإنشائهم، والثانية <code>&lt;api/customers/&lt;pk</code> من أجل جلب وتحديث وحذف العملاء المنفردين اعتمادًا على المفاتيح الأساسية لكل منهم.
</p>

<p>
	افتح الملف التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_146" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">urls</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	دع المحتويات كما هي ولكن أضف الاستيراد إلى عروض <code>customers</code> في أعلى الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_148" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path
</span><span class="kwd">from</span><span class="pln"> customers </span><span class="kwd">import</span><span class="pln"> views
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> url</span></pre>

<p>
	ثم أضف عنواني URL لكلٍ من <code>/api/customers</code> و <code>&lt;api/customers/&lt;pk</code> إلى قائمة نماذج عناوين URL urlpatterns التي تحتوي على عناوين URLs للتطبيق:
</p>

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

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^api/customers/$'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">customers_list</span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^api/customers/(?P&lt;pk&gt;[0-9]+)$'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">customers_detail</span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	الآن بعد أن انتهينا من إنشاء نقاط النهاية لريست، لنرى كيف نستهلكها.
</p>

<h2>
	الخطوة السادسة - استهلاك واجهة برمجة التطبيقات لريست باستخدام اكسيوس Axios
</h2>

<p>
	سنثبت في هذه الخطوة <a href="https://github.com/axios/axios" rel="external nofollow">Axios</a>، عميل HTTP الذي سنستخدمه لإنشاء استدعاءات واجهة برمجة التطبيقات. سننشئ أيضًا صنفًا لاستهلاك نقاط النهاية لواجهة برمجة التطبيقات التي أنشأناها.
</p>

<p>
	نبدأ بإيقاف تنشيط البيئة الافتراضية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_152" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ deactivate</span></pre>

<p>
	ثم ننتقل إلى مجلد الواجهة الأمامية "frontend":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_154" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">djangoreactproject</span><span class="pun">/</span><span class="pln">frontend</span></pre>

<p>
	ثبت اكسيوس <code>axios</code> من <code>npm</code> باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_156" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> ali@ubuntu</span><span class="pun">:</span><span class="pln">$ npm install axios </span><span class="pun">--</span><span class="pln">save</span></pre>

<p>
	يضيف الخيار <code>save–</code> اعتمادية <code>axios</code> إلى ملف التطبيق "package.json".
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_158" style=""><span class="pln">$ cd src
$ nano </span><span class="typ">CustomersService</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	أضف الشيفرة التالية التي تحتوي على توابع ستتصل بواجهات برمجة التطبيقات لجانغو ريست:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_160" style=""><span class="kwd">import</span><span class="pln"> axios </span><span class="kwd">from</span><span class="pln"> </span><span class="str">'axios'</span><span class="pun">;</span><span class="pln">
const API_URL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:8000'</span><span class="pun">;</span><span class="pln">

export default </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomersService</span><span class="pun">{</span><span class="pln">

    constructor</span><span class="pun">(){}</span><span class="pln">


    getCustomers</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">  
    getCustomersByURL</span><span class="pun">(</span><span class="pln">link</span><span class="pun">){</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}</span><span class="pln">$</span><span class="pun">{</span><span class="pln">link</span><span class="pun">}`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    getCustomer</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">pk</span><span class="pun">}`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    deleteCustomer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">){</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">customer</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">}`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    createCustomer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">){</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln">customer</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    updateCustomer</span><span class="pun">(</span><span class="pln">customer</span><span class="pun">){</span><span class="pln">
        const url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">API_URL</span><span class="pun">}/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">customers</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">customer</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">}`;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln">customer</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيستدعي الصنف <code>CustomersService</code> توابع اكسيوس Axios التالية:
</p>

<ul>
	<li>
		<code>()getCustomers</code>: يحصل على الصفحة الأولى من العملاء.
	</li>
	<li>
		<code>()getCustomersByURL</code>: يحصل على العملاء بواسطة عنوان URL، ويتيح هذا بدوره الحصول على الصفحات التالية من العملاء بتمرير روابط، مثل "api/customers/?page=2/".
	</li>
	<li>
		<code>()getCustomer</code>: يحصل على عميل بواسطة مفتاحه الأساسي.
	</li>
	<li>
		<code>()createCustomer</code>: ينشئ عميلًا.
	</li>
	<li>
		<code>()updateCustomer</code>: يحدّث عميلًا.
	</li>
	<li>
		<code>()deleteCustomer</code>: يحذف عميلًا.
	</li>
</ul>

<p>
	نستطيع الآن عرض البيانات من واجهة برمجة التطبيقات الخاصة بنا في واجهة المستخدم لريآكت بإنشاء مكوّن <code>CustomersList</code>.
</p>

<h2>
	الخطوة السابعة - عرض البيانات من واجهة برمجة التطبيقات في تطبيق ريآكت
</h2>

<p>
	سننشئ في هذه الخطوة مكون ريآكت اسمه: <code>CustomersList</code>، الذي يمثّل جزءًا من <a href="https://academy.hsoub.com/design/user-interface/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-ui-r652/" rel="">واجهة المستخدم</a>، ويمكنك أيضًا من تقسيم واجهة المستخدم إلى أقسام منفصلة وقابلة للاستخدام مجددًا.
</p>

<p>
	أنشئ أولًا الملف "CustomersList.js" في المجلد "frontend/src":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_163" style=""><span class="pln">$ nano </span><span class="pun">~</span><span class="str">/djangoreactproject/</span><span class="pln">frontend</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="typ">CustomersList</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	ثم ابدأ في استيراد <code>React</code> و <code>Component</code> لإنشاء مكون ريآكت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_165" style=""><span class="kwd">import</span><span class="pln">  </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react'</span><span class="pun">;</span></pre>

<p>
	ثم استورد واستنسخ الوحدة <code>CustomersService</code> التي أنشأتها في الخطوة السابقة، والتي توفر توابع تُربط مع الواجهة الخلفية لواجهة برمجة تطبيقات ريست REST <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_167" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pln">  from  </span><span class="str">'./CustomersService'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln">  customersService  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">new</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pun">();</span></pre>

<p>
	ثم أنشئ المكون <code>CustomersList</code> المُمتد عن الصنف <code>Component</code>، الذي سيستدعي واجهة برمجة التطبيقات لريست، إذ يجب أن يمتد مكون ريآكت عن الصنف <code>Component</code> أو أن يكون صنفًا فرعيًا عنه.
</p>

<p>
	أضف الشيفرة التالية إلى الملف "CustomersList.js" لإنشاء مكون ريآكت الذي يمتدّ عن المكوّن <code>react.Component</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_169" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pln">  extends  </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state  </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            customers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
            nextPageURL</span><span class="pun">:</span><span class="pln">  </span><span class="str">''</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextPage  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextPage</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln">  </span><span class="kwd">default</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pun">;</span></pre>

<p>
	هيأنا في الشيفرة كائن الحالة <a href="https://wiki.hsoub.com/React/react_component#state" rel="external">state</a> داخل <a href="https://wiki.hsoub.com/React/react_component#constructor.28.29" rel="external">الباني constructor</a>؛ إذ يحتفظ هذا الكائن بحالة متغيرات مكوّننا باستخدام مصفوفة عملاء فارغة. ستحتفظ هذه المصفوفة بالعملاء والمتغير <code>nextPageURL</code> الذي يحتفظ بعنوان URL للصفحة التالية التي ستستعيدها من واجهة برمجة تطبيقات الواجهة الخلفية.
</p>

<p>
	ربطنا أيضًا التابعين <code>()nextPage</code> و <code>()handleDelete</code> بالمؤشر <code>this</code> بحيث يستطاع الوصول إليهما من شيفرة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>، ثم أضفنا التابع <code>()componentDidMount</code> واستدعاءً للتابع <code>()getCustomers</code> ضمن الصنف <code>CustomersList</code> قبل قوس الإغلاق.
</p>

<p>
	يُعد التابع <code>()componentDidMount</code> تابع دورة حياة المكوّن ويُستدعى عند إنشاء المكوّن وإدخاله إلى نموذج كائن الوثيقة DOM. يستدعي التابع <code>()getCustomers</code> كائن خدمة العملاء Customers Service للحصول على صفحة البيانات الأولى ورابط الصفحة التالية من الواجهة الخلفية لجانغو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_174" style=""><span class="pun">...</span><span class="pln">
componentDidMount</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    var  self  </span><span class="pun">=</span><span class="pln">  this</span><span class="pun">;</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">getCustomers</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">function </span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> customers</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> nextPageURL</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">nextlink</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضف تحت التابع <code>()componentDidMount</code> بالضبط التابع <code>()handleDelete</code>، الذي يتولى مهمة حذف عميل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_176" style=""><span class="pun">...</span><span class="pln">
handleDelete</span><span class="pun">(</span><span class="pln">e</span><span class="pun">,</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
    var  self  </span><span class="pun">=</span><span class="pln">  this</span><span class="pun">;</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">deleteCustomer</span><span class="pun">({</span><span class="pln">pk </span><span class="pun">:</span><span class="pln">  pk</span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(()=&gt;{</span><span class="pln">
        var  newArr  </span><span class="pun">=</span><span class="pln">  self</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">customers</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">function</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln">  obj</span><span class="pun">.</span><span class="pln">pk  </span><span class="pun">!==</span><span class="pln">  pk</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln">customers</span><span class="pun">:</span><span class="pln">  newArr</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستدعي التابعُ <code>()handleDelete</code> التابعَ <code>()deleteCustomer</code> لحذف عميل باستخدام مفتاحه الأساسي، وإذا كانت العملية ناجحة، ستُرشّح filtered المصفوفة لتعكس آخر حالة بعد حذف ذلك العميل.
</p>

<p>
	بعد ذلك، أضف التابع <code>()nextPage</code> لتحصل على بيانات الصفحة التالية وحدّث رابط الصفحة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_178" style=""><span class="pun">...</span><span class="pln">
nextPage</span><span class="pun">(){</span><span class="pln">
    var  self  </span><span class="pun">=</span><span class="pln">  this</span><span class="pun">;</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">getCustomersByURL</span><span class="pun">(</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">nextPageURL</span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> customers</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> nextPageURL</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">nextlink</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستدعي التابعُ <code>()nextPage</code> التابعَ <code>()getCustomersByURL</code>، الذي يأخذ عنوان URL للصفحة التالية من كائن الحالة <code>this.state.nextPageURL</code> ويحدّث مصفوفة العملاء <code>customers</code> بالبيانات المعادة.
</p>

<p>
	وأخيرًا، أضف التابع <code>()render</code>، الذي يصيّر جدولًا للعملاء من حالة المكوّن:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_664_182" style=""><span class="pln">...
render() {

    return (
    </span><span class="tag">&lt;div</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"customers--list"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;table</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"table"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;thead</span><span class="pln">  </span><span class="atn">key</span><span class="pun">=</span><span class="atv">"thead"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;tr&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">#</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">First Name</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Last Name</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Phone</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Email</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Address</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Description</span><span class="tag">&lt;/th&gt;</span><span class="pln">
                </span><span class="tag">&lt;th&gt;</span><span class="pln">Actions</span><span class="tag">&lt;/th&gt;</span><span class="pln">
            </span><span class="tag">&lt;/tr&gt;</span><span class="pln">
            </span><span class="tag">&lt;/thead&gt;</span><span class="pln">
            </span><span class="tag">&lt;tbody&gt;</span><span class="pln">
                {this.state.customers.map( c  =&gt;
                </span><span class="tag">&lt;tr</span><span class="pln">  </span><span class="atn">key</span><span class="pun">=</span><span class="atv">{c.pk}</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.pk}  </span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.first_name}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.last_name}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.phone}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.email}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.address}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">{c.description}</span><span class="tag">&lt;/td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;td&gt;</span><span class="pln">
                    </span><span class="tag">&lt;button</span><span class="pln">  </span><span class="atn">onClick</span><span class="pun">={(</span><span class="pln">e</span><span class="pun">)=</span><span class="tag">&gt;</span><span class="pln">  this.handleDelete(e,c.pk) }&gt; Delete</span><span class="tag">&lt;/button&gt;</span><span class="pln">
                    </span><span class="tag">&lt;a</span><span class="pln">  </span><span class="atn">href</span><span class="pun">=</span><span class="atv">{"/customer/"</span><span class="pln"> + </span><span class="atn">c</span><span class="pln">.</span><span class="atn">pk</span><span class="pln">}</span><span class="tag">&gt;</span><span class="pln"> Update</span><span class="tag">&lt;/a&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/td&gt;</span><span class="pln">
                </span><span class="tag">&lt;/tr&gt;</span><span class="pln">)}
            </span><span class="tag">&lt;/tbody&gt;</span><span class="pln">
        </span><span class="tag">&lt;/table&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln">  </span><span class="atn">onClick</span><span class="pun">=</span><span class="pln">  </span><span class="pun">{</span><span class="pln">  </span><span class="atn">this</span><span class="pln">.</span><span class="atn">nextPage</span><span class="pln">  }</span><span class="tag">&gt;</span><span class="pln">Next</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    );
}</span></pre>

<p>
	وفيما يلي يظهر المحتوى الكامل للملف "CustomersList.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_184" style=""><span class="kwd">import</span><span class="pln">  </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pln">  from  </span><span class="str">'./CustomersService'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln">  customersService  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">new</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">class</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pln">  extends  </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state  </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        customers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
        nextPageURL</span><span class="pun">:</span><span class="pln">  </span><span class="str">''</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextPage  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextPage</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

componentDidMount</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln">  self  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">getCustomers</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> customers</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> nextPageURL</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">nextlink</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
handleDelete</span><span class="pun">(</span><span class="pln">e</span><span class="pun">,</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln">  self  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">deleteCustomer</span><span class="pun">({</span><span class="pln">pk </span><span class="pun">:</span><span class="pln">  pk</span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(()=&gt;{</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln">  newArr  </span><span class="pun">=</span><span class="pln">  self</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">customers</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln">  obj</span><span class="pun">.</span><span class="pln">pk  </span><span class="pun">!==</span><span class="pln">  pk</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">

        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln">customers</span><span class="pun">:</span><span class="pln">  newArr</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

nextPage</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln">  self  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">nextPageURL</span><span class="pun">);</span><span class="pln">        
    customersService</span><span class="pun">.</span><span class="pln">getCustomersByURL</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">nextPageURL</span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> customers</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> nextPageURL</span><span class="pun">:</span><span class="pln">  result</span><span class="pun">.</span><span class="pln">nextlink</span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div  className</span><span class="pun">=</span><span class="str">"customers--list"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">table  className</span><span class="pun">=</span><span class="str">"table"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">thead  key</span><span class="pun">=</span><span class="str">"thead"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;#&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">First</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Last</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Phone</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Email</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Address</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Description</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">th</span><span class="pun">&gt;</span><span class="typ">Actions</span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">thead</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">customers</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln"> c  </span><span class="pun">=&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">tr  key</span><span class="pun">={</span><span class="pln">c</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">}&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">}</span><span class="pln">  </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">first_name</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">email</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">address</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;{</span><span class="pln">c</span><span class="pun">.</span><span class="pln">description</span><span class="pun">}&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">button  onClick</span><span class="pun">={(</span><span class="pln">e</span><span class="pun">)=&gt;</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete</span><span class="pun">(</span><span class="pln">e</span><span class="pun">,</span><span class="pln">c</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}&gt;</span><span class="pln"> </span><span class="typ">Delete</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">a  href</span><span class="pun">={</span><span class="str">"/customer/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">}&gt;</span><span class="pln"> </span><span class="typ">Update</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;)}</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">table</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">button  className</span><span class="pun">=</span><span class="str">"btn btn-primary"</span><span class="pln">  onClick</span><span class="pun">=</span><span class="pln">  </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">nextPage  </span><span class="pun">}&gt;</span><span class="typ">Next</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln">  </span><span class="kwd">default</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pun">;</span></pre>

<p>
	الآن وبعد أنشأنا المكون <code>CustomersList</code> المسؤول عن عرض قائمة العملاء يمكننا الآن إضافة المكون الذي يتولى مهمة إنشاء العملاء وتحديثهم.
</p>

<h2>
	الخطوة الثامنة - إضافة مكون ريآكت لإنشاء العملاء وتحديثهم
</h2>

<p>
	سننشئ في هذه الخطوة المكون <code>CustomerCreateUpdate</code> الذي سيتولى مهمة إنشاء وتحديث العملاء، وذلك بإتاحة نموذج تعبئة form للمستخدمين لملئها ببيانات عميل جديد أو تحديث بيانات عميل موجود.
</p>

<p>
	أنشئ الملف "CustomerCreateUpdate.js" داخل المجلد "frontend/src":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_188" style=""><span class="pln">$ nano </span><span class="pun">~</span><span class="str">/djangoreactproject/</span><span class="pln">frontend</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="typ">CustomerCreateUpdate</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	أضف الشيفرة التالية لإنشاء مكون ريآكت الذي يستورد <code>React</code> و <code>Component</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_190" style=""><span class="kwd">import</span><span class="pln">  </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react'</span><span class="pun">;</span></pre>

<p>
	يمكنك أيضًا استيراد واستنساخ الصنف <code>CustomersService</code> الذي أنشأناه في الخطوة السابقة والذي يزود بتوابع توصل مع الواجهة الخلفية لواجهة برمجة تطبيقات ريست:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_192" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pln">  from  </span><span class="str">'./CustomersService'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln">  customersService  </span><span class="pun">=</span><span class="pln">  </span><span class="kwd">new</span><span class="pln">  </span><span class="typ">CustomersService</span><span class="pun">();</span></pre>

<p>
	ثم أنشئ المكون <code>CustomerCreateUpdate</code> المُمتدّ عن <code>Component</code> لإنشاء العملاء وتحديثهم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_196" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln">  </span><span class="typ">CustomerCreateUpdate</span><span class="pln">  extends  </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

</span><span class="pun">}</span><span class="pln">
export default </span><span class="typ">CustomerCreateUpdate</span><span class="pun">;</span></pre>

<p>
	أضف ضمن تعريف الصنف تابعَ المكوّن <code>()render</code> الذي يصيّر نموذج HTML الذي يجمع معلومات عن العميل.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_664_198" style=""><span class="pln">...
render() {
        return (
          </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">onSubmit</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">}</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              First Name:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</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">ref</span><span class="pun">=</span><span class="atv">'firstName'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              Last Name:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</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">ref</span><span class="pun">=</span><span class="atv">'lastName'</span><span class="tag">/&gt;</span><span class="pln">

            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              Phone:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</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">ref</span><span class="pun">=</span><span class="atv">'phone'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              Email:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</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">ref</span><span class="pun">=</span><span class="atv">'email'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              Address:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</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">ref</span><span class="pun">=</span><span class="atv">'address'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

            </span><span class="tag">&lt;label&gt;</span><span class="pln">
              Description:</span><span class="tag">&lt;/label&gt;</span><span class="pln">
              </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">ref</span><span class="pun">=</span><span class="atv">'description'</span><span class="pln"> </span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">


            </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Submit"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;/form&gt;</span><span class="pln">
        );
  }</span></pre>

<p>
	يضيف هذا التابع الخاصية <code>ref</code> للوصول إلى عنصر النموذج التعبئة ووضع قيمة له وذلك من أجل كل عنصر إدخال ضمن نموذج التعبئة.
</p>

<p>
	الآن، عرّف التابعَ <code>(handleSubmit(event</code> فوق التابع <code>()render</code> لكي تمتلك الوظائف المناسبة عندما ينقر عميل على زر الإرسال submit:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_204" style=""><span class="pun">...</span><span class="pln">
handleSubmit</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    const </span><span class="pun">{</span><span class="pln"> match</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> params </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">params  </span><span class="pun">&amp;&amp;</span><span class="pln">  params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
        this</span><span class="pun">.</span><span class="pln">handleUpdate</span><span class="pun">(</span><span class="pln">params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">else</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        this</span><span class="pun">.</span><span class="pln">handleCreate</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">…</span></pre>

<p>
	يعالج التابع <code>(handleSubmit(event</code> إرسال النموذج ويستدعي -اعتمادًا على المسار- إما التابع <code>(handleUpdate(pk</code> لتحديث العميل بالمفتاح الأساسي الممرر، أو التابع <code>()handleCreate</code> لإنشاء عميل جديد. سنعرّف هذين التابعين باختصار.
</p>

<p>
	عد إلى باني المكون، واربط التابع <code>()handleSubmit</code> بالمؤشر <code>this</code> لكي تتمكن من الوصول إليه في نموذجك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_206" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomerCreateUpdate</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">handleSubmit </span><span class="pun">=</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">this</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	ثم عرّف التابع <code>()handleCreate</code> لإنشاء عميل من بيانات نموذج التعبئة، وأضف الشيفرة التالية فوق التابع <code>(handleSubmit(event</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_208" style=""><span class="pun">...</span><span class="pln">
handleCreate</span><span class="pun">(){</span><span class="pln">
    customersService</span><span class="pun">.</span><span class="pln">createCustomer</span><span class="pun">(</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"first_name"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"last_name"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"email"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"phone"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"address"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"description"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value
        </span><span class="pun">}).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)=&gt;{</span><span class="pln">
                alert</span><span class="pun">(</span><span class="str">"Customer created!"</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}).</span><span class="pln">catch</span><span class="pun">(()=&gt;{</span><span class="pln">
                alert</span><span class="pun">(</span><span class="str">'There was an error! Please re-check your form.'</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></pre>

<p>
	سوف يُستخدَم التابع <code>()handleCreate</code> من أجل إنشاء عميل من البيانات المُدخلة، إذ يستدعي التابع المقابل <code>()CustomersService.createCustomer</code> الذي يجري استدعاءً لواجهة برمجة التطبيقات الفعلية للواجهة الخلفية لينشئ عميلًا جديدًا.
</p>

<p>
	بعد ذلك عرّف التابع <code>(handleUpdate(pk</code> الذي يجري التحديثات أسفل التابع <code>()handleCreate</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_210" style=""><span class="pun">...</span><span class="pln">
handleUpdate</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
customersService</span><span class="pun">.</span><span class="pln">updateCustomer</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"pk"</span><span class="pun">:</span><span class="pln">  pk</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"first_name"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"last_name"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"email"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"phone"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"address"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"description"</span><span class="pun">:</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value
    </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)=&gt;{</span><span class="pln">

        alert</span><span class="pun">(</span><span class="str">"Customer updated!"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}).</span><span class="pln">catch</span><span class="pun">(()=&gt;{</span><span class="pln">
        alert</span><span class="pun">(</span><span class="str">'There was an error! Please re-check your form.'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيحدّث التابع <code>()updateCustomer</code> العميل ذا المفتاح الأساسي <code>pk</code> بالمعلومات الجديدة التي جلبها من نموذج معلومات العميل، ويستدعي التابع <code>()customersService.updateCustomer</code>.
</p>

<p>
	الآن، أضف التابع <code>()componentDidMount</code>، وبالتالي إذا زار المستخدم الوجهة "customer/:pk"، فإننا نريد تعبئة النموذج بمعلومات مرتبطة بالعميل باستخدام المفتاح الأساسي من عنوان URL، ولفعل ذلك يمكننا إضافة التابع <code>(getCustomer(pk</code> بعد أن يُثبّت المكون في حدث دورة الحياة للتابع <code>()componentDidMount</code>. أضف الشيفرة التالية أسفل باني المكون لإضافة هذا التابع:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_664_212" style=""><span class="pun">...</span><span class="pln">
componentDidMount</span><span class="pun">(){</span><span class="pln">
    const </span><span class="pun">{</span><span class="pln"> match</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> params </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln">  this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">params  </span><span class="pun">&amp;&amp;</span><span class="pln">  params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        customersService</span><span class="pun">.</span><span class="pln">getCustomer</span><span class="pun">(</span><span class="pln">params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">c</span><span class="pun">)=&gt;{</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">first_name</span><span class="pun">;</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">;</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">email</span><span class="pun">;</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">;</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">address</span><span class="pun">;</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value  </span><span class="pun">=</span><span class="pln">  c</span><span class="pun">.</span><span class="pln">description</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></pre>

<p>
	وفيما يلي المحتوى الكامل للملف "CustomerCreateUpdate.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_214" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">CustomersService</span><span class="pln"> from </span><span class="str">'./CustomersService'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> customersService </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomersService</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomerCreateUpdate</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">

      componentDidMount</span><span class="pun">(){</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> match</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> params </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">params </span><span class="pun">&amp;&amp;</span><span class="pln"> params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          customersService</span><span class="pun">.</span><span class="pln">getCustomer</span><span class="pun">(</span><span class="pln">params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">c</span><span class="pun">)=&gt;{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">first_name</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">last_name</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">email</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">address</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> c</span><span class="pun">.</span><span class="pln">description</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">

      handleCreate</span><span class="pun">(){</span><span class="pln">
        customersService</span><span class="pun">.</span><span class="pln">createCustomer</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"first_name"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"last_name"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"email"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"phone"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"address"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value
        </span><span class="pun">}</span><span class="pln">          
        </span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)=&gt;{</span><span class="pln">
          alert</span><span class="pun">(</span><span class="str">"Customer created!"</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}).</span><span class="kwd">catch</span><span class="pun">(()=&gt;{</span><span class="pln">
          alert</span><span class="pun">(</span><span class="str">'There was an error! Please re-check your form.'</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      handleUpdate</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
        customersService</span><span class="pun">.</span><span class="pln">updateCustomer</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"pk"</span><span class="pun">:</span><span class="pln"> pk</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"first_name"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">firstName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"last_name"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">lastName</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"email"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">email</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"phone"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">phone</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"address"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">address</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">refs</span><span class="pun">.</span><span class="pln">description</span><span class="pun">.</span><span class="pln">value
        </span><span class="pun">}</span><span class="pln">          
        </span><span class="pun">).</span><span class="pln">then</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)=&gt;{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
          alert</span><span class="pun">(</span><span class="str">"Customer updated!"</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}).</span><span class="kwd">catch</span><span class="pun">(()=&gt;{</span><span class="pln">
          alert</span><span class="pun">(</span><span class="str">'There was an error! Please re-check your form.'</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      handleSubmit</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> match</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> params </span><span class="pun">}</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">params </span><span class="pun">&amp;&amp;</span><span class="pln"> params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">){</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleUpdate</span><span class="pun">(</span><span class="pln">params</span><span class="pun">.</span><span class="pln">pk</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleCreate</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">

      render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"form-group"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">First</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'firstName'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">Last</span><span class="pln"> </span><span class="typ">Name</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'lastName'</span><span class="pun">/&gt;</span><span class="pln">

            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">Phone</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'phone'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">Email</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'email'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">Address</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'address'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

            </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="typ">Description</span><span class="pun">:&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">textarea className</span><span class="pun">=</span><span class="str">"form-control"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'description'</span><span class="pln"> </span><span class="pun">&gt;&lt;/</span><span class="pln">textarea</span><span class="pun">&gt;</span><span class="pln">


            </span><span class="pun">&lt;</span><span class="pln">input className</span><span class="pun">=</span><span class="str">"btn btn-primary"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> value</span><span class="pun">=</span><span class="str">"Submit"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">  
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">CustomerCreateUpdate</span><span class="pun">;</span></pre>

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

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

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

<p>
	نفذ الأمر التالي من المجلد "frontend"، لتثبيت <a href="https://www.npmjs.com/package/react-router-dom" rel="external nofollow">موجه ريآكت</a> الذي يمكّنك من إضافة المسارات والتنقلات بين مكونات ريآكت المتعددة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_216" style=""><span class="pln">$ cd </span><span class="pun">~</span><span class="str">/djangoreactproject/</span><span class="pln">frontend
$ npm install </span><span class="pun">--</span><span class="pln">save react</span><span class="pun">-</span><span class="pln">router</span><span class="pun">-</span><span class="pln">dom</span></pre>

<p>
	والآن افتح الملف "djangoreactproject/frontend/src/App.js/~":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_218" style=""><span class="pln">$ nano </span><span class="pun">~</span><span class="str">/djangoreactproject/</span><span class="pln">frontend</span><span class="pun">/</span><span class="pln">src</span><span class="pun">/</span><span class="typ">App</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	احذف كل شيء هناك وأضف الشيفرة التالية لاستيراد الأصناف اللازمة لإضافة التوجيه، إذ تتضمن هذه الأصناف الصنفَ <code>BrowserRouter</code> الذي ينشئ مكوّن الموجّه والصنفَ <code>Route</code> الذي ينشئ مكوّن الوُجهة route:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_220" style=""><span class="kwd">import</span><span class="pln">  </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">BrowserRouter</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react-router-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Route</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Link</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from  </span><span class="str">'react-router-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pln">  from  </span><span class="str">'./CustomersList'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomerCreateUpdate</span><span class="pln">  from  </span><span class="str">'./CustomerCreateUpdate'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="str">'./App.css'</span><span class="pun">;</span></pre>

<p>
	<strong>ملاحظة:</strong> يحافظ <code>BrowserRouter</code> على التزامن بين واجهة المستخدم وعنوان URL باستخدام <a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API" rel="external nofollow">واجهة برمجة تطبيقات تاريخ HTML5</a>.
</p>

<p>
	أنشئ نمطًا أساسيًّا ليزودنا بالمكون الأساسي الذي سيُغلِّفُه المكون <code>BrowserRouter</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_664_222" style=""><span class="pln">...

const  BaseLayout  = () =&gt; (
</span><span class="tag">&lt;div</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"container-fluid"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;nav</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"navbar navbar-expand-lg navbar-light bg-light"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;a</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"navbar-brand"</span><span class="pln">  </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="tag">&gt;</span><span class="pln">Django React Demo</span><span class="tag">&lt;/a&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"navbar-toggler"</span><span class="pln">  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln">  </span><span class="atn">data-toggle</span><span class="pun">=</span><span class="atv">"collapse"</span><span class="pln">  </span><span class="atn">data-target</span><span class="pun">=</span><span class="atv">"#navbarNavAltMarkup"</span><span class="pln">  </span><span class="atn">aria-controls</span><span class="pun">=</span><span class="atv">"navbarNavAltMarkup"</span><span class="pln">  </span><span class="atn">aria-expanded</span><span class="pun">=</span><span class="atv">"false"</span><span class="pln">  </span><span class="atn">aria-label</span><span class="pun">=</span><span class="atv">"Toggle navigation"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;span</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"navbar-toggler-icon"</span><span class="tag">&gt;&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"collapse navbar-collapse"</span><span class="pln">  </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"navbarNavAltMarkup"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"navbar-nav"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;a</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"nav-item nav-link"</span><span class="pln">  </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">CUSTOMERS</span><span class="tag">&lt;/a&gt;</span><span class="pln">
            </span><span class="tag">&lt;a</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"nav-item nav-link"</span><span class="pln">  </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/customer"</span><span class="tag">&gt;</span><span class="pln">CREATE CUSTOMER</span><span class="tag">&lt;/a&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/nav&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln">  </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Route</span><span class="pln">  </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/"</span><span class="pln">  </span><span class="atn">exact</span><span class="pln">  </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{CustomersList}</span><span class="pln">  </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;Route</span><span class="pln">  </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/customer/:pk"</span><span class="pln">  </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{CustomerCreateUpdate}</span><span class="pln">  </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;Route</span><span class="pln">  </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/customer/"</span><span class="pln">  </span><span class="atn">exact</span><span class="pln">  </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{CustomerCreateUpdate}</span><span class="pln">  </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
)</span></pre>

<p>
	استخدمنا بالشيفرة أعلاه المكون <code>Route</code> لتعريف وجهات تطبيقنا، وهو المكون الذي يتعيّن على الموجّه تحميله عندما يجد تطابقًا. تحتاج كل وجهة إلى مسار <code>path</code> لتحديد المسار الذي سيجري مطابَقته، وإلى مكوّن <code>component</code> لتحديد المكون الذي سيحمّله. تخبر الخاصّيّة <code>exact</code> الموجّه أن يطابق المسار الصحيح.
</p>

<p>
	وأخيرًا أنشئ المكون <code>App</code> المكوّن الجذر أو مكوّن مستوى القمة في تطبيق ريآكت:
</p>

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

</span><span class="kwd">class</span><span class="pln">  </span><span class="typ">App</span><span class="pln">  extends  </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">BrowserRouter</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">BaseLayout</span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">BrowserRouter</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln">  </span><span class="kwd">default</span><span class="pln">  </span><span class="typ">App</span><span class="pun">;</span></pre>

<p>
	وبما أننا نريد أن يعمل التطبيق في المتصفح، فقد غلّفنا المكوّن <code>BaseLayout</code> بالمكوّن <code>BrowserRouter</code>.
</p>

<p>
	الآن يبدو ملف "App.js" المكتمل شبيهًا بما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_664_227" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">BrowserRouter</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-router-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Route</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Link</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-router-dom'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomersList</span><span class="pln"> from </span><span class="str">'./CustomersList'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln">  </span><span class="typ">CustomerCreateUpdate</span><span class="pln">  from </span><span class="str">'./CustomerCreateUpdate'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'./App.css'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">BaseLayout</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"container-fluid"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">nav className</span><span class="pun">=</span><span class="str">"navbar navbar-expand-lg navbar-light bg-light"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">a className</span><span class="pun">=</span><span class="str">"navbar-brand"</span><span class="pln"> href</span><span class="pun">=</span><span class="str">"#"</span><span class="pun">&gt;</span><span class="typ">Django</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> </span><span class="typ">Demo</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button className</span><span class="pun">=</span><span class="str">"navbar-toggler"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> data</span><span class="pun">-</span><span class="pln">toggle</span><span class="pun">=</span><span class="str">"collapse"</span><span class="pln"> data</span><span class="pun">-</span><span class="pln">target</span><span class="pun">=</span><span class="str">"#navbarNavAltMarkup"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">controls</span><span class="pun">=</span><span class="str">"navbarNavAltMarkup"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">expanded</span><span class="pun">=</span><span class="str">"false"</span><span class="pln"> aria</span><span class="pun">-</span><span class="pln">label</span><span class="pun">=</span><span class="str">"Toggle navigation"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">span className</span><span class="pun">=</span><span class="str">"navbar-toggler-icon"</span><span class="pun">&gt;&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"collapse navbar-collapse"</span><span class="pln"> id</span><span class="pun">=</span><span class="str">"navbarNavAltMarkup"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"navbar-nav"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a className</span><span class="pun">=</span><span class="str">"nav-item nav-link"</span><span class="pln"> href</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">CUSTOMERS</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">a className</span><span class="pun">=</span><span class="str">"nav-item nav-link"</span><span class="pln"> href</span><span class="pun">=</span><span class="str">"/customer"</span><span class="pun">&gt;</span><span class="pln">CREATE CUSTOMER</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">nav</span><span class="pun">&gt;</span><span class="pln">  

    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"content"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/"</span><span class="pln"> exact component</span><span class="pun">={</span><span class="typ">CustomersList</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/customer/:pk"</span><span class="pln">  component</span><span class="pun">={</span><span class="typ">CustomerCreateUpdate</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/customer/"</span><span class="pln"> exact component</span><span class="pun">={</span><span class="typ">CustomerCreateUpdate</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">BrowserRouter</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">BaseLayout</span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">BrowserRouter</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span><span class="pun">;</span></pre>

<p>
	بعد إضافة التوجيه إلى تطبيقنا، أصبحنا الآن جاهزين لاختبار التطبيق. انتقل إلى العنوان "http://localhost:3000"، ويفترض أن ترى الصفحة الأولى من التطبيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111553" href="https://academy.hsoub.com/uploads/monthly_2022_11/django_react_app.png.7432fc6404988f34bdeeadf9e94499d1.png" rel=""><img alt='الصفحة الأولى للتطبيق بعد إدخال العنوان "http://localhost:3000"' class="ipsImage ipsImage_thumbnailed" data-fileid="111553" data-unique="uk3hnsvbw" style="width: 780px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/django_react_app.thumb.png.c14644641461c24a133a05e05f73a7dd.png"></a>
</p>

<p>
	وبهذا يكتمل التطبيق، وأصبح لديك الآن الأساس لتطبيق إدارة علاقات العملاء CRM.
</p>

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

<p>
	أنشأت في هذا المقال تطبيقًا تجريبيًّا باستخدام جانغو وريآكت، واستخدمت إطار عمل جانغو ريست لبناء واجهة برمجة التطبيقات لريست REST واكسيوس Axios لاستهلاك واجهة برمجة التطبيقات وبوتستراب 4 لتنسيق <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a>.
</p>

<p>
	يمكنك العثور على <a href="https://github.com/techiediaries/django-react" rel="external nofollow">الشيفرة المصدرية لهذا المشروع في مستودع غيت هب GitHub</a>.
</p>

<p>
	ترجمة - وبتصرف - للمقالة <a href="https://www.digitalocean.com/community/tutorials/how-to-build-a-modern-web-application-to-manage-customer-information-with-django-and-react-on-ubuntu-18-04" rel="external nofollow">How To Build a Modern Web Application to Manage Customer Information with Django and React on Ubuntu 18.04</a> لصاحبها Ahmed Bouchefra.
</p>

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-%D9%88%D8%B1%D9%8A%D8%A2%D9%83%D8%AA-react-r1773/" rel="">بناء تطبيق مهام باستخدام جانغو Django وريآكت React</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nuxtjs-%D9%88%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r1774/" rel="">بناء تطبيق ويب من طرف الخادم باستخدام Nuxt.js وجانغو Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%8A%D8%B9%D8%B1%D8%B6-%D8%A3%D8%AD%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B7%D9%82%D8%B3-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r1775/" rel="">بناء تطبيق يعرض أحوال الطقس باستخدام جانغو Django</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1776</guid><pubDate>Sun, 27 Nov 2022 16:09:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x64A;&#x639;&#x631;&#x636; &#x623;&#x62D;&#x648;&#x627;&#x644; &#x627;&#x644;&#x637;&#x642;&#x633; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%8A%D8%B9%D8%B1%D8%B6-%D8%A3%D8%AD%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B7%D9%82%D8%B3-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r1775/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636734e53c2bb_-------Django.png.3e8a64fb7d1bfc8e4dd8a64e969a1526.png" /></p>

<p>
	سننشئ في هذه المقالة تطبيق <a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو</a> مهمته عرض أحوال الطقس الحالية لعدّة مدن.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111518" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d12197c1_002-finalcityadded.png.068468e6390ac3a48516028527656769.png" rel=""><img alt="002-final city added.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111518" data-unique="cr2te5tel" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d12e74d6_002-finalcityadded.thumb.png.eba5f2eb0ec34739eb0b5b6840f4a65b.png" style="width: 780px; height: auto;"></a>
</p>

<p>
	ستتولى واجهة برمجة التطبيقات لخرائط الطقس المفتوحة <a href="https://openweathermap.org/api" rel="external nofollow">Open Weather Map <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> مسؤولية توفير بيانات الطقس الحالية. سنستخدم في عملنا قاعدة بيانات وننشئ نموذجًا، بحيث يمكن تطبيق ما سنتعلمه هنا لاحقًا في المشاريع الأعقد.
</p>

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

<p>
	يلزم لهذا المشروع تثبيت بايثون Python على جهازك، وأن تتمكن من الرجوع إلى <a href="https://academy.hsoub.com/tags/%D8%AF%D9%84%D9%8A%D9%84%20%D8%AA%D8%B9%D9%84%D9%85%20%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">هذه السلسلة من المقالات التعليمية</a> إذا احتجت إلى معلومات أكثر.
</p>

<p>
	كُتبت الشيفرة المكتوبة في مقالنا هذا <a href="https://academy.hsoub.com/programming/python/%d8%a7%d9%84%d8%af%d9%84%d9%8a%d9%84-%d8%a7%d9%84%d8%b3%d8%b1%d9%8a%d8%b9-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-%d8%a8%d8%a7%d9%8a%d8%ab%d9%88%d9%86-python-3-r535/" rel="">ببايثون 3</a> وجانغو 3.0، ولذلك لا بُد أن تكون ملمًا بهما جيدًا.
</p>

<h2>
	الخطوة الأولى - تجهيز المشروع
</h2>

<p>
	من السهل تثبيت جانغو كما هو حال أي مكتبة من مكتبات بايثون، بأحد الطريقتين التاليتين:
</p>

<ul>
<li>
		فتح بيئة افتراضية وتنفيذ الأمر <code>pip</code> لتثبيت جانغو.
	</li>
	<li>
		إنشاء مجلد مشروع وتشغيل أداة <code>pipenv</code>، ثم تفعيل صدفة <code>pipenv</code>.
	</li>
</ul>
<p>
	وتؤدي كلتا الطريقتين الغرض، لكننا سنستخدم في مقالتنا هذه أداة <code>pipenv</code>.
</p>

<p>
	<strong>ملاحظة:</strong> يجب أن تكون قادرًا على الرجوع إلى هذه السلسلة من <a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/" rel="">المقالات التعليمية</a> إذا أردت استخدام طرق تثبيت جانغو الأخرى.
</p>

<p>
	يحتوي <a href="https://pipenv.pypa.io/en/latest/install/#installing-pipenv%5D" rel="external nofollow">التوثيق الرسمي لجانغو</a> على تعليمات تثبيت <code>pipenv</code>، إما باستخدام <a href="https://brew.sh/" rel="external nofollow">Homebrew</a>، أو Linuxbrew. يمكنك أيضًا تثبيت <code>pipenv</code> باستخدام <code>pip</code>.
</p>

<p>
	أنشئ باستخدام نافذة الطرفية مجلدًا للبيئة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_11" style="">
<span class="pln">$ mkdir the_weather_env</span></pre>

<p>
	ثم انتقل إلى داخله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_13" style="">
<span class="pln">$ cd the_weather_env</span></pre>

<p>
	ثم استخدم <code>pipenv</code> لتثبيت جانغو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_15" style="">
<span class="pln">$ pipenv install django</span></pre>

<p>
	سيؤدي هذا إلى تثبيت آخر إصدار من جانغو على جهازك، وفي حالتنا كان آخر إصدار هو 3.0.5.
</p>

<p>
	استخدم أيضًا <code>pipenv</code> لتثبيت مكتبة الطلبات <a href="https://pypi.org/project/requests" rel="external nofollow">Request</a> التي ستستخدمها فيما بعد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_17" style="">
<span class="pln">$ pipenv install requests</span></pre>

<p>
	فعّل البيئة الافتراضية <code>virtualenv</code> للمشروع بتنفيذ الأمر التالي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_19" style="">
<span class="pln">$ pipenv shell</span></pre>

<p>
	سيولد هذا عمليةً فرعيةً جديدةً للصدفة.
</p>

<h2>
	الخطوة الثانية - افتتاح مشروع جانغو
</h2>

<p>
	بعد أن تنتهي من تثبيت جانغو أنشئ مجلدًا لهذا المشروع وانتقل إليه (إذا لم تكن قد فعلت ذلك).
</p>

<p>
	يمكنك تنفيذ الأمر <code>startproject</code> الذي يوفره جانغو لتولّد المشروع.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_22" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> django</span><span class="pun">-</span><span class="pln">admin startproject the_weather</span></pre>

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

<p>
	لنجرب الآن تشغيل خادم التطوير، انتقل إلى المجلد الجديد في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_24" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> cd the_weather </span></pre>

<p>
	والآن استخدم manage.py لتنفيذ الأمر <code>unserver</code> في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_27" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	سترى إذا دققت في الطرفية عنوان محدد الموارد <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">الموحد URL</a> لتطبيقك الذي يجب أن تكون قيمته الافتراضية هي "127.0.0.1:8000"، كما هو موضح في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111519" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d142f07b_003-firststartofserver.png.14df5d08c0534a36da11b49025ff6148.png" rel=""><img alt="القيمة الافتراضية للتطبيق" class="ipsImage ipsImage_thumbnailed" data-fileid="111519" data-unique="xytxnwjl6" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1469af2_003-firststartofserver.thumb.png.08dcba98d8bb338004e849e8f826daeb.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	افتح الآن متصفح الويب الذي تستخدمه واذهب إلى ذلك العنوان:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111520" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d16e11cd_004-congratspage.png.5231d751dbaa1ee9b5c0942a27457109.png" rel=""><img alt="004 - congrats page.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111520" data-unique="bnu7vwpsc" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1757247_004-congratspage.thumb.png.206c646ebbec1d69763b8ee2474c643e.png" style="width: 780px; height: auto;"></a>
</p>

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

<h2>
	الخطوة الثالثة - تسجيل الدخول إلى لوحة تحكم الإدارة
</h2>

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

<p>
	نحتاج أولًا لإيقاف تشغيل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> بالضغط إما على المفتاحين "CONTROL+C"، أو "CTRL+C" بحسب البيئة المُستخدمة، ثم ننفذ الأمر <code>migrate</code> في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_34" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	سينشئ جانغو عندئذٍ قاعدة بيانات SQLite وهي الافتراضية في الإعدادات، وسيضيف عدة جداول إليها. إذا رأيت في مجلد المشروع ملفًا جديدًا اسمه "db.sqlite3" فاعلم أن قاعدة البيانات قد أنشئت.
</p>

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

<p>
	وعلى هذا، لننشئ مستخدم المدير بتنفيذ الأمر <code>createsuperuser</code> في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_36" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

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

<pre class="ipsCode">
(the_weather_env) python manage.py runserver
</pre>

<p>
	اذهب من شاشة المتصفح إلى العنوان "127.0.0.1:8000‎/admin" الذي هو عنوان لوحة تحكم المدير، وننوه هنا إلى أن إعداد المستخدم admin ضمن الملف "urls.py" هو الذي مكّنك من الذهاب إلى تلك الصفحة.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111521" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d186a97c_005-admindashboard.png.36d6f80b3ccccc1535c86c90937a6c29.png" rel=""><img alt="005- admin dashboard.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111521" data-unique="m5ofmzxex" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d18eca4b_005-admindashboard.thumb.png.85cc8a858ea3d6319fb966e8027dd9bb.png" style="width: 780px; height: auto;"></a>
</p>

<p>
	يظهر في الصورة السابقة نموذجان يتيح لك جانغو الوصول إليهما، وهما: Groups و Users؛ إذ أن النماذج في حقيقتها ما هي إلا تمثيلات لجداول <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a>. لذلك، هذان النموذجان انعكاسًا لجدولي قاعدة البيانات المقابلين، ومع أن جانغو قد أنشأ جداول أخرى غيرهما، إلا أنه لا حاجة بنا للوصول إليها مباشرةً لذا لم تُنشأ نماذج تقابلها.
</p>

<p>
	إذا نقرت على Users ستظهر لك تفاصيل أوسع عن جدول المستخدمين وسترى المستخدم الذي أنشاته. اقض بعض الوقت في استكشاف لوحة الإدارة بالنقر على الروابط المختلفة لرؤية ما هو موجود، لكن حذارِ أن تحذف المستخدم لكي لا تضطر إلى تنفيذ الأمر <code>createsuperuser</code> مجددًا.
</p>

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

<h2>
	الخطوة الرابعة - إنشاء التطبيق
</h2>

<p>
	يمكّننا جانغو من فصل الوظائف البرمجية عن بعضها بعضًا في المشروع الواحد باستخدام التطبيقات، فكل تطبيق يؤدي وظيفة معينة مُكلفٌ بها ضمن المشروع الواحد؛ فإذا نظرنا إلى الملف "settings.py" على سبيل المثال، فسنرى قائمة التطبيقات المثبتة "INSTALLED_APPS". وأول التطبيقات المثبتة هو "django.contrib.admin" الذي استخدمته للتو، إذ يتولى هذا التطبيق مسؤولية وظائف الإدارة فقط ولا شيء غير ذلك. مثال آخر على تطبيق موجود في المشروع افتراضيًّا، هو التطبيق "django.contrib.auth" الذي سمح لنا بتسجيل الدخول إلى لوحة الإدارة.
</p>

<p>
	نحتاج في حالتنا إلى إنشاء تطبيق جديد يتولى مهمة إظهار حالة الطقس.
</p>

<p>
	أوقف تشغيل الخادم أولًا، ثم نفذ الأمر <code>startapp</code> في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_40" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py startapp weather</span></pre>

<p>
	سيضيف جانغو عند تنفيذ هذا الأمر مجلدًا جديدًا وبعض الملفات إلى المشروع.
</p>

<p>
	دعنا ننشئ مع الملفات التي وُلِّدت للتو ملفًا جديدًا اسمه "urls.py" في مجلد التطبيق weather:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_43" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	هذا الملف مماثل للملف "urls.py" في مجلد "the_weather"، ويتمثّل الفرق بينهما هو أن هذا الملف "urls.py" يحتوي على جميع عناوين URL المرتبطة بالتطبيق نفسه.
</p>

<p>
	لم تحدِّد أي عناوين URL بعد، لكن يمكنك إعداد المشروع لكي يتعرف على تطبيقك ويوجه أي <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عناوين URL</a> معينة لتطبيقك إلى ملف التطبيق "urls.py".
</p>

<p>
	اذهب إلى قائمة التطبيقات المثبتة <code>INSTALLED_APPS</code> في الملف settings.py وأضف اسم التطبيق <code>weather</code> إلى القائمة:
</p>

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

INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'weather'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="pun">...</span></pre>

<p>
	وبهذا تخبر جانغو أنك تريد استخدام التطبيق "weather" في مشروعك، وعندئذ سيعلم جانغو أين سيبحث عن ملفات التهجير وعناوين URL.
</p>

<p>
	ستحتاج الآن إلى تعديل الملف الأصلي urls.py بحيث يشير إلى ملف urls.py الذي في التطبيق، ولذلك أضف سطرًا تحت المسار الموجود للوحة الإدارة، كما ستحتاج أيضًا إلى استيراد المكتبة <code>include</code> لتتمكن من الإشارة إلى ملف urls.py للتطبيق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_48" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path</span><span class="pun">,</span><span class="pln"> include

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">''</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="str">'weather.urls'</span><span class="pun">)),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	تعني السلسلة الفارغة أنك لن تحتاج لاستخدام نقطة نهاية من أجل نقطة الدخول إلى تطبيقنا، بل سنترك للتطبيق مهمة معالجة أي نقاط نهاية محددة، وبالرفم من أنه كان بإمكاننا وضع شيء على نحو <code>(...,'/path('weather</code>، والذي كان سيُلزِمنا بكتابة /127.0.0.1:8000‎/weather للحصول على أي شيء مرافق لتطبيق الطقس، لكن لأن مشروعنا بسيط أصلًا فلن نفعل هذا هنا.
</p>

<h2>
	الخطوة الخامسة - إضافة القالب والعرض
</h2>

<p>
	سنحتاج الآن لإضافة القالب إلى المشروع الذي نعمل عليه؛ والقالب في جانغو ما هو إلا ملف <a href="https://academy.hsoub.com/programming/html/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-html-r1702/" rel="">HTML</a> يتيح لنا تعليمات أوسع في شيفرته، الأمر الذي يجعل القالب ديناميكيًا، إذ سنتمكن فيه من معالجة وظائف، مثل إضافة المتغيرات والتعليمات الشرطية if والحلقات.
</p>

<p>
	نذهب في الطرفية إلى مجلد التطبيق "weather":
</p>

<pre class="ipsCode">
(the_weather_env) cd weather
</pre>

<p>
	ثم ننشئ المجلد "templates":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_51" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> mkdir templates</span></pre>

<p>
	ثم ننتقل إلى داخله:
</p>

<pre class="ipsCode">
(the_weather_env) cd templates
</pre>

<p>
	أنشئ مجلدًا آخر يحمل نفس اسم التطبيق، لأن جانغو يدمج جميع مجلدات القوالب من التطبيقات الموجودة سابقًا لدينا معًا، وللحيلولة دون تكرار أسماء الملفات، يمكنك استخدام اسم التطبيق:
</p>

<pre class="ipsCode">
(the_weather_env) mkdir weather
</pre>

<p>
	من داخل مجلد weather هذا، أنشئ ملفًا جديدًا اسمه index.html الذي سيكون القالب الأساسي.
</p>

<p>
	وفيما يلي شيفرة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> التي ستستخدمها للقالب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7232_53" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"UTF-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">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.0"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"X-UA-Compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"ie=edge"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">What's the weather like?</span><span class="tag">&lt;/title&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">"https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.css"</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;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;section</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"hero is-primary"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"hero-body"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">
                    What's the weather like?
                </span><span class="tag">&lt;/h1&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/section&gt;</span><span class="pln">
    </span><span class="tag">&lt;section</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"section"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"columns"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"column is-offset-4 is-4"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">method</span><span class="pun">=</span><span class="atv">"POST"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"field has-addons"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"control is-expanded"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"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">placeholder</span><span class="pun">=</span><span class="atv">"City Name"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"control"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button is-info"</span><span class="tag">&gt;</span><span class="pln">
                                    Add City
                                </span><span class="tag">&lt;/button&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/form&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/section&gt;</span><span class="pln">
    </span><span class="tag">&lt;section</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"section"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"columns"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"column is-offset-4 is-4"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;article</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-left"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;figure</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"image is-50x50"</span><span class="tag">&gt;</span><span class="pln">
                                    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"http://openweathermap.org/img/w/10d.png"</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"Image"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;/figure&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-content"</span><span class="tag">&gt;</span><span class="pln">
                                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
                                    </span><span class="tag">&lt;p&gt;</span><span class="pln">
                                        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">Las Vegas</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                                        </span><span class="tag">&lt;br&gt;</span><span class="pln">
                                        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"subtitle"</span><span class="tag">&gt;</span><span class="pln">29° F</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                                        </span><span class="tag">&lt;br&gt;</span><span class="pln"> thunderstorm with heavy rain
                                    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
                                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                        </span><span class="tag">&lt;/article&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/section&gt;</span><span class="pln">
    </span><span class="tag">&lt;footer</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"footer"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/footer&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>
	<strong>ملاحظة</strong>: استخدمنا مكتبة بولما <a href="https://bulma.io/" rel="external nofollow">Bulma</a> خلف الكواليس لمعالجة التنسيقات styling والتخطيطات layout.
</p>

<p>
	بعد أن فرغت من إنشاء القالب ستنشئ مزيجًا يضم عرضًا view وعنوان URL معًا، لتتمكن من رؤية هذا فعليًا في التطبيق؛ والعروض في جانغو هي إما دوال أو أصناف، وفي حالتنا هذه ونظرًا لأنك تنشئ عرضًا بسيطًا فستنشئ دالةً، ثم تضيف هذه الدالة إلى ملف views.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_56" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

<p>
	سُمّي العرض باسم "index" لأنه سيكون في فهرس التطبيق الذي هو عنوان URL الجذر. لا بُد من إعادة <code>request</code> لتصيير القالب، لأنه ضروري لدالة <code>render</code> واسم ملف القالب الذي تريد تصييره، والذي هو في حالتنا weather/index.html.
</p>

<p>
	دعنا الآن نضيف عنوان URL الذي سيرسل الطلب إلى هذا العرض. لذلك، حدِّث القائمة <code>urlpatterns</code> في ملف urls.py للتطبيق كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_58" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> views

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">''</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">index</span><span class="pun">),</span><span class="pln">  </span><span class="com">#the path for our index view</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	يتيح لك هذا فهرسة العرض الذي أنشأته للتو.
</p>

<p>
	سيطابق جانغو أي عنوان URL ليس لديه نقطة نهاية ويوجهه إلى تابع العرض الذي أنشأته.
</p>

<p>
	الآن، اذهب إلى نافذة الطرفية وعد فيها إلى جذر المشروع (the_weather)، ثم شغّل الخادم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_60" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	ثم افتح متصفح الويب واذهب للعنوان 127.0.0.1:8000 مرةً أخرى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111522" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1b1b0a3_006-templatereturned.png.8d77176af9016609847c3db4ce585570.png" rel=""><img alt="006- template returned.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111522" data-unique="k68p0n6s7" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1b9cdef_006-templatereturned.thumb.png.9be0d5d852b491240ddd01674e7357a4.png" style="width: 750px; height: auto;"></a>
</p>

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

<h2>
	الخطوة السادسة - استخدام واجهة برمجة تطبيقات الطقس Weather <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
</h2>

<p>
	يجب عليك أولًا إنشاء حساب في موقع <a href="https://openweathermap.org/api" rel="external nofollow">واجهة برمجة تطبيقات الطقس</a>. وهو التطبيق الذي سيوفر لك معلومات الطقس في الزمن الحقيقي لأي مدن تختار إضافتها إلى التطبيق.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111523" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1d0ab78_007-apidashboard.png.a25df4d0c10fa561af3f417579c3f8f5.png" rel=""><img alt="007 - api dashboard.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111523" data-unique="57ktmrkga" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1da72a2_007-apidashboard.thumb.png.75a667592aa5c5dec43b8988f4ab690d.png" style="width: 800px; height: auto;"></a>
</p>

<p>
	<strong>ملاحظة</strong>: من المهم الحفاظ على سرية مفاتيح واجهة برمجة التطبيقات الطقس لمنع الأطراف الخارجية من استخدامها. تخيل ماذا سيحدث لو رُبِط مفتاح <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهة برمجة التطبيقات</a> بمستودع بعيد مثل مستودعات Github. لا أعتقد أن أحدًا منا يرغب في أن يحدث هذا معه.
</p>

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

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7232_66" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//api.openweathermap.org/data/2.5/weather?q=las%20vegas&amp;units=imperial&amp;appid=YOUR_APP_KEY</span></pre>

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

<p>
	من المتوقع الحصول على استجابة بصيغة <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a> تحتوي على الإحداثيات ودرجات الحرارة وأحوال الطقس.
</p>

<p>
	دعنا الآن نضيف طلبًا للحصول على البيانات وإخراجها إلى التطبيق، ونعدّل العرض <code>index</code> لإرسال طلب إلى <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> الذي لديك.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_72" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">import</span><span class="pln"> requests

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://api.openweathermap.org/data/2.5/weather?q={}&amp;units=imperial&amp;appid=YOUR_APP_KEY'</span><span class="pln">

    city </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Las Vegas'</span><span class="pln">

    city_weather </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)).</span><span class="pln">json</span><span class="pun">()</span><span class="pln"> </span><span class="com">#request the <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> data and convert the JSON to Python data types</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

<p>
	أضف الآن <code>import requests</code> و <code>url</code> و <code>city</code> و <code>city_weather</code>.
</p>

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

<p>
	سنعطي في الوقت الحالي القيمة الثابتة "Las Vegas" للمدينة <code>city</code>، لكن في المستقبل ستحدّد بقيم المدن الموجودة في قاعدة البيانات. أخيرًا، سترسل الطلب إلى عنوان URL باستخدام المدينة وتحصل على تمثيل JSON لتلك المدينة.
</p>

<p>
	إذا جربت طباعة <code>print</code> النتيجة إلى الطرفية، ستتمكن من رؤية نفس البيانات التي حصلت عليها عندما وضعت عنوان URL في شريط العنوان:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_74" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln">city_weather</span><span class="pun">)</span><span class="pln"> </span><span class="com">#temporarily view output</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

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

<h2>
	الخطوة السابعة - عرض البيانات في القالب
</h2>

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

<p>
	لننشئ قاموسًا يخزن كافة البيانات التي تحتاجها. ستحتاج من بين البيانات المعادة <code>temp</code> و <code>description</code> و <code>icon</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_76" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    weather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'city'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'temperature'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'main'</span><span class="pun">][</span><span class="str">'temp'</span><span class="pun">],</span><span class="pln">
        </span><span class="str">'description'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'weather'</span><span class="pun">][</span><span class="lit">0</span><span class="pun">][</span><span class="str">'description'</span><span class="pun">],</span><span class="pln">
        </span><span class="str">'icon'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'weather'</span><span class="pun">][</span><span class="lit">0</span><span class="pun">][</span><span class="str">'icon'</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

<p>
	الآن وقد بات لديك كل المعلومات التي تريدها، يمكنك أن تمررها إلى القالب، ولذلك ستنشئ متغيرًا اسمه <code>context</code> سيكون قاموسًا يسمح لك باستخدام قيَمِهِ داخل القالب، ثم ستضيف في الدالة <code>render</code> وسيطًا ثالثًا هو <code>context</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7232_78" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'weather'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> weather</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">,</span><span class="pln"> context</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

<p>
	وهكذا بعد أن أصبحت بيانات الطقس داخل الـمتغير <code>context</code>، دعنا نذهب إلى القالب لنضيف هذه البيانات؛ فكل ما تحتاج فعله داخل القالب index.html هو تعديل شيفرة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> لتستخدم المتغيرات بدلًا من استخدام القيم المسبقة الضمنية، إذ ستستخدِم هذه المتغيّرات الوسوم {{ }}، وستسنِد reference كل شيء داخل قاموس <code>context</code>.
</p>

<p>
	نلاحظ أن جانغو يحوّل قيم القاموس، بحيث لا يمكن الوصول إليها إلا باستخدام صيغة الاستدعاء النقطية dot notation، إذ سنحصل مثلًا عند استخدام <code>weather.city</code> على اسم المدينة. لا تستخدم <code>['weather['city</code> كما هو مُستخدم في بايثون.
</p>

<p>
	ابحث عن الصندوق <code><a href="https://wiki.hsoub.com/HTML/div" rel="external">&lt;div&gt;</a></code> وعدّله ليستخدم المتغيرات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7232_84" style="">
<span class="pln">...
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;article</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-left"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;figure</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"image is-50x50"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"http://openweathermap.org/img/w/{{ weather.icon }}.png"</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"Image"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;/figure&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-content"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;p&gt;</span><span class="pln">
                    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">{{ weather.city }}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                    </span><span class="tag">&lt;br&gt;</span><span class="pln">
                    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"subtitle"</span><span class="tag">&gt;</span><span class="pln">{{ weather.temperature }}° F</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                    </span><span class="tag">&lt;br&gt;</span><span class="pln"> {{ weather.description }}
                </span><span class="tag">&lt;/p&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/article&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
...</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111524" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1f4f4ea_008-actualweatherdata.png.644941cba8bc7bdb6decb374aa272d31.png" rel=""><img alt="الحصول على قيم الطقس الحالية للمدينة المحددة." class="ipsImage ipsImage_thumbnailed" data-fileid="111524" data-unique="i85bjl8bp" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d1fc3251_008-actualweatherdata.thumb.png.029e88bcd6cba59f786891bff2e11a40.png" style="width: 790px; height: auto;"></a>
</p>

<p>
	لكن ما تزال المدينة تظهر قيمتها ضمنية المسبقة، لذا فما ستفعله الآن هو سحب القيم من قاعدة البيانات وعرض بيانات المدن الموجودة فيها.
</p>

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

<p>
	اذهب إلى الملف "models.py" في التطبيق "weather" وأضف الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_7" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">City</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">25</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __str__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln"> </span><span class="com">#show the actual city name on the dashboard</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">name

    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln"> </span><span class="com">#show the plural of city as cities instead of citys</span><span class="pln">
        verbose_name_plural </span><span class="pun">=</span><span class="pln"> </span><span class="str">'cities'</span></pre>

<p>
	سينشئ هذه الشيفرة جدولًا في قاعدة البيانات بعمود اسمه <code>name</code> يدل على اسم المدينة، وسيكون نوع المدينة هو <code>charfield</code> أي سلسلة عاديّة. ولقبول هذه التغيرات وتطبيقها على قاعدة البيانات، ستحتاج لتنفيذ الأمر <code>makemigrations</code> الذي سيولد الشيفرة التي ستحدِّث قاعدة البيانات وتجري عمليات التهجير إليها.
</p>

<p>
	دعنا نوقف تشغيل الخادم وننفذ تلك التهجيرات في نافذة الطرفية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_9" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py makemigrations</span></pre>

<p>
	ثم نهجّر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_11" style="">
<span class="pun">(</span><span class="pln">the_weather_env</span><span class="pun">)</span><span class="pln"> python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	نحتاج لتمكين رؤية النموذج في لوحة الإدارة، ولهذا لا بُد من تسجيله في الملف "admin.py" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_13" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">City</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="typ">City</span><span class="pun">)</span></pre>

<p>
	الآن نعيد تشغيل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> وننظر في لوحة الإدارة في المتصفح:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111525" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d22354a0_009-dashboardwithcities.png.76d234eab8321b5bf930c82c52d55d4c.png" rel=""><img alt="لوحة إدارة المتصفح" class="ipsImage ipsImage_thumbnailed" data-fileid="111525" data-unique="y7czzf86i" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d22a8429_009-dashboardwithcities.thumb.png.aaa3ee53242cb6c43e8767f0e0aa39de.png" style="width: 790px; height: auto;"></a>
</p>

<p>
	كما نرى فقد أصبحت City الآن أحد الخيارات.
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111526" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d242734d_010-threecities.png.776028637a6a5ae1dfa3428a81546649.png" rel=""><img alt="إضافة المدن من لوحة التحكم" class="ipsImage ipsImage_thumbnailed" data-fileid="111526" data-unique="gpa2pltmz" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d249fdc1_010-threecities.thumb.png.74bf7df342a451ca702aecc3cd3ed9ef.png" style="width: 790px; height: auto;"></a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_18" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">import</span><span class="pln"> requests
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">City</span></pre>

<p>
	ثم نحدّث الطلب <code>request</code> بالمدن <code>cities</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_20" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://api.openweathermap.org/data/2.5/weather?q={}&amp;units=imperial&amp;appid=YOUR_APP_KEY'</span><span class="pln">

    cities </span><span class="pun">=</span><span class="pln"> </span><span class="typ">City</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln"> </span><span class="com">#return all the cities in the database</span><span class="pln">
    </span><span class="pun">...</span></pre>

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

<p>
	ستنشئ أولًا قائمة بيانات الطقس <code>weather_data</code> التي ستحتفظ بقيمة الطقس <code>weather</code> لكل مدينة <code>city</code>، ثم نستبدل متغيّر المدينة <code>city</code> الأصلي بحلقة تمر بكل المدن <code>cities</code>. بعد ذلك، يجب إلحاق كل استجابة <code>weather</code> لكل مدينة<code>city</code> ببيانات الطقس <code>weather_data</code>. سنحتاج أيضًا إلى تحديث السياق <code>context</code> لتمرير هذه القائمة بدلًا من تمرير قاموس وحيد.
</p>

<p>
	في هذه اللحظة يُفترض أن يكون الملف views.py شبيهًا بالتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_22" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    cities </span><span class="pun">=</span><span class="pln"> </span><span class="typ">City</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln"> </span><span class="com">#return all the cities in the database</span><span class="pln">

    weather_data </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"> city </span><span class="kwd">in</span><span class="pln"> cities</span><span class="pun">:</span><span class="pln">

        city_weather </span><span class="pun">=</span><span class="pln"> requests</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">city</span><span class="pun">)).</span><span class="pln">json</span><span class="pun">()</span><span class="pln"> </span><span class="com">#request the <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> data and convert the JSON to Python data types</span><span class="pln">

        weather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">'city'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city</span><span class="pun">,</span><span class="pln">
            </span><span class="str">'temperature'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'main'</span><span class="pun">][</span><span class="str">'temp'</span><span class="pun">],</span><span class="pln">
            </span><span class="str">'description'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'weather'</span><span class="pun">][</span><span class="lit">0</span><span class="pun">][</span><span class="str">'description'</span><span class="pun">],</span><span class="pln">
            </span><span class="str">'icon'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> city_weather</span><span class="pun">[</span><span class="str">'weather'</span><span class="pun">][</span><span class="lit">0</span><span class="pun">][</span><span class="str">'icon'</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        weather_data</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">weather</span><span class="pun">)</span><span class="pln"> </span><span class="com">#add the data for the current city into our list</span><span class="pln">

    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'weather_data'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> weather_data</span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'weather/index.html'</span><span class="pun">,</span><span class="pln"> context</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns the index.html template</span></pre>

<p>
	ثم ستحتاج داخل قالب index.html للمرور في هذه القائمة مستخدمًا حلقة، وتوليد شيفرة HTML لكل مدينة <code>city</code> من القائمة. يمكنك لتحقيق ذلك وضع حلقة <code>for</code> حول شيفرة HTML التي تولد صندوقًا وحيدًا <code>&lt;div&gt;</code> للمدينة <code>city</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2612_24" style="">
<span class="pln">...
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"column is-offset-4 is-4"</span><span class="tag">&gt;</span><span class="pln">
    {% for weather in weather_data %}
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"box"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;article</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-left"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;figure</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"image is-50x50"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"http://openweathermap.org/img/w/{{ weather.icon }}.png"</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"Image"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;/figure&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"media-content"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;p&gt;</span><span class="pln">
                        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">{{ weather.city }}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                        </span><span class="tag">&lt;br&gt;</span><span class="pln">
                        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"subtitle"</span><span class="tag">&gt;</span><span class="pln">{{ weather.temperature }}° F</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                        </span><span class="tag">&lt;br&gt;</span><span class="pln"> {{ weather.description }}
                    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/article&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    {% endfor %}
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
…</span></pre>

<p>
	يمكنك الآن معاينة بيانات كافة المدن التي لديك في قاعدة البيانات.
</p>

<h2>
	الخطوة الثامنة - إنشاء نموذج التعبئة
</h2>

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

<p>
	أنشئ ملفًا جديدًا باسم "forms.py" في تطبيق "weather":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_26" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">forms </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ModelForm</span><span class="pun">,</span><span class="pln"> </span><span class="typ">TextInput</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">City</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CityForm</span><span class="pun">(</span><span class="typ">ModelForm</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">City</span><span class="pln">
        fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'name'</span><span class="pun">]</span><span class="pln">
        widgets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">'name'</span><span class="pun">:</span><span class="pln"> </span><span class="typ">TextInput</span><span class="pun">(</span><span class="pln">attrs</span><span class="pun">={</span><span class="str">'class'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'input'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'placeholder'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'City Name'</span><span class="pun">}),</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="com">#updates the input class to have the correct Bulma class and placeholder</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_28" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">forms </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">CityForm</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</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"> </span><span class="typ">CityForm</span><span class="pun">()</span><span class="pln">

    weather_data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'weather_data'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> weather_data</span><span class="pun">,</span><span class="pln"> </span><span class="str">'form'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> form</span><span class="pun">}</span></pre>

<p>
	والآن لنحدّث قسم نموذج التعبئة ضمن القالب index.html ليستخدِم النموذج من العرض ومفتاح التشفير المساعد المُعد من أجل هجمات تزوير الطلب عبر المواقع <code>csrf_token</code>، وهو ضروري لطلبات من نوع POST في جانغو.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2612_32" style="">
<span class="pln">...
</span><span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">method</span><span class="pun">=</span><span class="atv">"POST"</span><span class="tag">&gt;</span><span class="pln">
    {% csrf_token %}
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"field has-addons"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"control is-expanded"</span><span class="tag">&gt;</span><span class="pln">
            {{ form.name }}
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"control"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"button is-info"</span><span class="tag">&gt;</span><span class="pln">
                Add City
            </span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span><span class="pln">
...</span></pre>

<p>
	<strong>ملاحظة:</strong> تشير CSRF إلى هجمات تزوير الطلب عبر المواقع Cross-Site Request Forgery، وهي مقياس أمني لضمان إرسال بيانات نموذج التعبئة من مصدر متوقع وموثوق.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2612_34" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    url </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://api.openweathermap.org/data/2.5/weather?q={}&amp;units=imperial&amp;appid=YOUR_APP_KEY'</span><span class="pln">

    cities </span><span class="pun">=</span><span class="pln"> </span><span class="typ">City</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span><span class="pln"> </span><span class="com">#return all the cities in the database</span><span class="pln">

    </span><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"> </span><span class="com"># only true if form is submitted</span><span class="pln">
        form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CityForm</span><span class="pun">(</span><span class="pln">request</span><span class="pun">.</span><span class="pln">POST</span><span class="pun">)</span><span class="pln"> </span><span class="com"># add actual request data to form for processing</span><span class="pln">
        form</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln"> </span><span class="com"># will validate and save if validate</span><span class="pln">

    form </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CityForm</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">…</span></pre>

<p>
	وهكذا بتمرير <code>request.POST</code> ستتمكن من التحقق من صلاحية بيانات النموذج.
</p>

<p>
	يُفترض الآن في هذه النقطة أن تتمكن من كتابة اسم المدينة ثم النقر على إضافة "Add" ورؤيتها وهي تظهر.
</p>

<p>
	أضف على سبيل المثال "Miami" اسمًا للمدينة التالية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111527" href="https://academy.hsoub.com/uploads/monthly_2022_11/63664d254b2cd_011-finalcityadded.png.608c4aa0e707aa6920821caf84052af0.png" rel=""><img alt="إضافة اسم المدينة من لوحة التحكم" class="ipsImage ipsImage_thumbnailed" data-fileid="111527" data-unique="tzmkzgi93" src="https://academy.hsoub.com/uploads/monthly_2022_11/63664d26182ea_011-finalcityadded.thumb.png.90af7dbf4e669d7b5d48375f7e03c9e4.png" style="width: 790px; height: auto;"></a>
</p>

<p>
	عندما تخرج من كتلة <code>if</code>، سيُعاد إنشاء نموذج التعبئة مما يمكنك من إضافة مدينة جديدة إن شئت، وستسلك بقية الشيفرة نفس الطريقة.
</p>

<p>
	وبهذا بات لدينا طريقة نتابع بها حالة الطقس لعدة مدن ضمن التطبيق.
</p>

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

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

<p>
	ترجمة - وبتصرف - للمقالة <a href="https://www.digitalocean.com/community/tutorials/how-to-build-a-weather-app-in-django" rel="external nofollow">How To Build a Weather App in Django</a> لصاحبها Anthony Herbert.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-%D9%88%D8%B1%D9%8A%D8%A2%D9%83%D8%AA-react-r1773/" rel="">بناء تطبيق مهام باستخدام جانغو Django وريآكت React </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nuxtjs-%D9%88%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r1774/" rel="">بناء تطبيق ويب من طرف الخادم باستخدام Nuxt.js وجانغو Django </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1775</guid><pubDate>Sun, 06 Nov 2022 04:23:13 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x648;&#x64A;&#x628; &#x645;&#x646; &#x637;&#x631;&#x641; &#x627;&#x644;&#x62E;&#x627;&#x62F;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Nuxt.js &#x648;&#x62C;&#x627;&#x646;&#x63A;&#x648; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nuxtjs-%D9%88%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-r1774/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/636640a228156_--------Nuxt--js--Django.png.d73e1aec7a6cb4ef8bd5db5df5cb285c.png" /></p>

<p>
	غيَّر التحسُّن الذي أُجري على مكتبات <a href="https://academy.hsoub.com/programming/javascript/%d9%85%d8%a7-%d9%87%d9%8a-%d8%ac%d8%a7%d9%81%d8%a7-%d8%b3%d9%83%d8%b1%d9%8a%d8%a8%d8%aa-%d8%9f-r524/" rel="">جافا سكريبت</a> الحديثة مثل مكتبة ريآكت React.js ومكتبة <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-vuejs-r989/" rel="">فيو جي إس Vue.js</a> من تطوير واجهات الويب الأمامية نحو الأفضل، إذ وفًّرت لنا هذه المكتبات بعض الميزات، مثل دعم تطبيقات الصفحة الواحدة Single-Page Application -أو اختصارًا SPA-؛ وهي تقنيةٌ تحمّل محتوى صفحات الويب ديناميكيًّا دون اضطرار إلى جلبها مرة أخرى من موقع الخادم إلى المتصفح على جهاز العميل.
</p>

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

<p>
	يُعد مفهوم التكوين في طرف العميل حديثًا نسبيًا، ورغم تميزُّه ففيه قصور، إذ يؤدي عدم تصيير محتوى الصفحة حتى تحديث الصفحة باستخدام جافا سكريبت إلى عرقلة عملية تحسين محرك البحث Search Engine Optimization -أو اختصارًا SEO- على الموقع، إذ يحتاج <a href="https://academy.hsoub.com/files/28-%d8%af%d9%84%d9%8a%d9%84%d9%83-%d8%a5%d9%84%d9%89-%d8%aa%d8%ad%d8%b3%d9%8a%d9%86-%d9%85%d8%ad%d8%b1%d9%83%d8%a7%d8%aa-%d8%a7%d9%84%d8%a8%d8%ad%d8%ab-seo/" rel="">SEO</a> إلى بيانات لتتبع الارتباطات، ولن يكون هناك أي بيانات في هذه التقنية لتتبع الارتباطات فيها.
</p>

<p>
	وعلى الطرف الآخر هناك مفهوم التصيير في طرف الخادم server-side، الذي يُعد الطريقة التقليدية لتصيير صفحات <a href="https://academy.hsoub.com/programming/html/%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-html-r1702/" rel="">HTML</a> على المتصفح؛ إذ يُبنى تطبيق الويب في هذا النوع من التطبيقات بلغة تعمل في طرف <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> مثل <a href="https://academy.hsoub.com/programming/php/%D8%AA%D9%85%D9%87%D9%8A%D8%AF-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-php-r235/" rel="">PHP</a>، وعندما يطلب المتصفح <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D9%88%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-r572/" rel="">صفحة ويب</a>، يضيف الخادمُ البعيدُ كاملَ المحتوى الديناميكي، ثم يرسل صفحة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> مملوءة بالمحتوى إلى طرف العميل.
</p>

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

<p>
	وهناك نوعٌ ثالث من أطر العمل، مبنيٌّ بجافا سكريبت يعتمد على مبدأ تحميل صفحة الويب ابتداءً بطريقة التصيير في طرف الخادم، ثم يستخدم إطار عمل آخر لمعالجة التوجيه الديناميكي الإضافي والاقتصار على إحضار البيانات المهمة، ويطلق على التطبيقات الناتجة اسم <strong>التطبيقات العمومية Universal Applications</strong> كونها تشمل مزيجًا من الحلّين: التصيير عند الخادم وعند العميل. يُستخدمُ مصطلح "التطبيق العمومي" لوصف شيفرة <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافا سكريبت</a> التي يمكن أن تنفّذَ عند كلا الطرفين: العميل والخادم.
</p>

<p>
	سنبني في هذه المقالة تطبيقًا عموميًّا موضوعه "وصفات الطبخ"، مستعينين بإطار عمل نُكست Nuxt.js؛ وهو إطار عمل من مستوى أعلى لتطوير تطبيقات فيو Vue.js عمومية، واستُلهمت فكرته من نِكست Next.js الذي تقدمه ريآكت وهو يساعد على تجريد التعقيدات التي تظهر لدى إعداد تطبيقات فيو جي إس التي تُصيَّر في طرف الخادم، مثل إعدادات الخادم، وتوزيع شيفرة العميل، ويأتي مع إطار العمل نُكست عدة مزايا تسهل عمليات التطوير بين جهتي العميل والخادم، مثل مزامنة البيانات async data والبرمجيات الوسيطة middleware والأنساق layouts ونحو ذلك.
</p>

<p>
	<strong>ملاحظة</strong>: رغم إمكانية إدراج التطبيق الذي نبنيه تحت تصنيف التطبيقات التي تُصيَّر في طرف الخادم Server-Side Rendering - أو اختصارًا SSR -،لأن فيو Vue يتولى بطبيعة الحال مهمة التصيير عند العميل عندما ننشئ تطبيق صفحة واحدة، ومع ذلك فالتطبيق الذي نعمل عليه هو في حقيقته يندرج تحت التطبيقات العمومية.
</p>

<p>
	سننشئ في هذه المقالة تطبيقًا عموميًّا مستخدمين لتحقيق ذلك جانغو ونُكست، إذ سيتولى جانغو مسؤولية معالجة العمليات في طرف الخادم ويوفر <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهات برمجة التطبيقات</a> التي تستخدِم إطار عمل جانغو ريست Django REST، بينما ينشئ نُكست الواجهة الأمامية.
</p>

<p>
	تبين الصورة التالية لقطةً توضيحيةً للتطبيق النهائي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111506" href="https://academy.hsoub.com/uploads/monthly_2022_11/002.gif.825ed50d674264d19870b07b11213a89.gif" rel=""><img alt="002.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="111506" data-unique="cbwxftfzm" src="https://academy.hsoub.com/uploads/monthly_2022_11/002.thumb.gif.aa2dc0d7fc269a0bf27915b045061de2.gif"></a>
</p>

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

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

<p>
	ستحتاج للمضيّ في هذه المقالة إلى ما يلي:
</p>

<ul>
<li>
		تثبيت نود جي إس <a href="https://wiki.hsoub.com/Node.js" rel="external">Node.js</a> محلي على جهازك، وإذا لم تكن تعرف ذلك، يمكنك مراجعة مقالة <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel="">مقدمة إلى Node.js</a>.
	</li>
	<li>
		تثبيت بايثون على جهازك أيضًا والطريقة <a href="https://academy.hsoub.com/programming/python/%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%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r714/" rel="">هنا</a>.
	</li>
	<li>
		سيستخدم هذا المشروع <a href="https://pypi.org/project/pipenv" rel="external nofollow">Pipenv</a>. وهي أداة معدة للاستخدام المهني توفر لنا أفضل طرق التحزيم Packaging في عالم بايثون. فهي تحزم Pipfile و pip و virtualenv في أمرٍ واحد فقط.
	</li>
</ul>
<p>
	وسنفترض أيضًا معرفة القارئ بما يلي:
</p>

<ol>
<li>
		العملية الأساسية بكل من <a href="https://academy.hsoub.com/programming/python/django/" rel="">جانغو</a> و<a href="https://www.django-rest-framework.org/" rel="external nofollow">إطار عمل جانغو ريست </a>
	</li>
	<li>
		<a href="https://www.django-rest-framework.org/" rel="external nofollow">Django REST Framework</a>.العملية الأساسية بمكتبة ـ<a href="https://academy.hsoub.com/programming/javascript/vuejs/" rel="">فيو جي إس Vue.js</a>.
	</li>
</ol>
<p>
	وقد تحققنا من عمل التطبيق في هذه المقالة باستخدام الاعتماديات التالية:
</p>

<ul>
<li>
		Python v3.7.7
	</li>
	<li>
		Django v3.0.7
	</li>
	<li>
		Node v14.4.0
	</li>
	<li>
		npm v6.14.5
	</li>
	<li>
		nuxt v2.13.0
	</li>
</ul>
<h2>
	الخطوة الأولى - إعداد الواجهة الخلفية
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_19" style="">
<span class="pln">$ mkdir recipes_app</span></pre>

<p>
	ثم انتقل إلى داخل المجلد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_21" style="">
<span class="pln">$ cd recipes_app</span></pre>

<p>
	الآن سنثبت أداة Pipenv باستخدام الأمر <code>pip</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_24" style="">
<span class="pln">$ pip install pipenv</span></pre>

<p>
	ونفعّل بيئة افتراضية جديدة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_26" style="">
<span class="pln">$ pipenv shell</span></pre>

<p>
	<strong>ملاحظة</strong>: تجاوز الأمر الأول إذا كانت Pipenv مثبتةً على حاسوبك.
</p>

<p>
	الآن، نثبت جانغو وبقية الاعتمادات باستخدام الأداة Pipenv:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_29" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ pipenv install django django</span><span class="pun">-</span><span class="pln">rest</span><span class="pun">-</span><span class="pln">framework django</span><span class="pun">-</span><span class="pln">cors</span><span class="pun">-</span><span class="pln">headers</span></pre>

<p>
	<strong>ملاحظة:</strong> بعد تفعيل بيئة افتراضية جديدة باستخدام Pipenv، سيُسبق كل سطر أوامر في الطرفية باسم مجلد العمل الحالي، وهو في حالتنا هذه (recipes_app).
</p>

<p>
	سننشئ الآن مشروع جانغو جديدًا ونسميه api:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_31" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin startproject api</span></pre>

<p>
	انتقل إلى مجلد المشروع:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_33" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ cd api</span></pre>

<p>
	أنشئ تطبيق جانغو وسمِّه core:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_35" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py startapp core</span></pre>

<p>
	دعنا الآن نسجّل التطبيق "core" مع "rest_framework" و "cors-headers" ليتمكن مشروع جانغو من التعرُّف عليه. افتح الملف "api/settings.py" وعدّله كما يلي:
</p>

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

</span><span class="com"># Application definition</span><span class="pln">
INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'rest_framework'</span><span class="pun">,</span><span class="pln"> </span><span class="com"># add this</span><span class="pln">
    </span><span class="str">'corsheaders'</span><span class="pun">,</span><span class="pln"> </span><span class="com"># add this</span><span class="pln">
    </span><span class="str">'core'</span><span class="pln"> </span><span class="com"># add this</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">

MIDDLEWARE </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'corsheaders.middleware.CorsMiddleware'</span><span class="pun">,</span><span class="pln"> </span><span class="com"># add this</span><span class="pln">
    </span><span class="str">'django.middleware.security.SecurityMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions.middleware.SessionMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.common.CommonMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.csrf.CsrfViewMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth.middleware.AuthenticationMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages.middleware.MessageMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.clickjacking.XFrameOptionsMiddleware'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="com"># add this block below MIDDLEWARE</span><span class="pln">
CORS_ORIGIN_WHITELIST </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="str">'http://localhost:3000'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="com"># ...</span><span class="pln">

</span><span class="com"># add the following just below STATIC_URL</span><span class="pln">
MEDIA_URL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/media/'</span><span class="pln"> </span><span class="com"># add this</span><span class="pln">
MEDIA_ROOT </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'media'</span><span class="pun">)</span><span class="pln"> </span><span class="com"># add this</span></pre>

<p>
	أضفنا هنا العنوان <code><a href="http://localhost:3000" ipsnoembed="false" rel="external nofollow">http://localhost:3000</a></code> إلى القائمة البيضاء لأن تطبيق العميل سيُخدَّم من هذا المنفذ ونريد منع حدوث أي خطأ من أخطاء <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%AD%D9%85%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D8%B1%D8%AF-%D8%A7%D9%84%D8%AE%D8%A7%D8%B1%D8%AC%D9%8A%D8%A9-%D9%81%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%AA%D8%AA%D8%A8%D8%B9-%D8%AD%D8%A7%D9%84%D8%AA%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1238/" rel="">سياسة تعدد الموارد</a> Cross-Origin Resource Sharing - أو اختصارًا CORS-؛ كما أضفنا أيضًا <code>MEDIA_URL</code> و <code>MEDIA_ROOT</code> لأننا سنحتاج إليهما من أجل خدمة الصور في التطبيق.
</p>

<h3>
	تعريف نموذج وصفات تحضير الأطباق
</h3>

<p>
	لننشئ الآن النموذج Recipe الذي سيعرّف طريقة تخزين عناصر وصفات التحضير في قاعدة البيانات. افتح الملف "core/models.py" وبدّل محتواه بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_39" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models
</span><span class="com"># Create your models here.</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    DIFFICULTY_LEVELS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'Easy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Easy'</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'Medium'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Medium'</span><span class="pun">),</span><span class="pln">
        </span><span class="pun">(</span><span class="str">'Hard'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hard'</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">120</span><span class="pun">)</span><span class="pln">
    ingredients </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">400</span><span class="pun">)</span><span class="pln">
    picture </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">FileField</span><span class="pun">()</span><span class="pln">
    difficulty </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">choices</span><span class="pun">=</span><span class="pln">DIFFICULTY_LEVELS</span><span class="pun">,</span><span class="pln"> max_length</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
    prep_time </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">PositiveIntegerField</span><span class="pun">()</span><span class="pln">
    prep_guide </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> __str_</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Recipe for {}"</span><span class="pun">.</span><span class="pln">format</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span></pre>

<p>
	تصف الشيفرة السابقة ست خاصّيات في نموذج Recipe، هي:
</p>

<ul>
<li>
		<code>name</code>
	</li>
	<li>
		<code>ingredients</code>
	</li>
	<li>
		<code>picture</code>
	</li>
	<li>
		<code>difficulty</code>
	</li>
	<li>
		<code>prep_time</code>
	</li>
	<li>
		<code>prep_guide</code>
	</li>
</ul>
<h3>
	إنشاء المسلسلات لنموذج وصفات تحضير الأطباق
</h3>

<p>
	نحتاج إلى المسلسِلات لتحويل نسخ النموذج إلى نوع المحتوى <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a> لتمكين الواجهة الأمامية من العمل مع البيانات التي ستستقبلها. سننشئ الملف "core/serializers.py" ونضيف إليه السطور التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_42" style="">
<span class="pln">from rest_framework </span><span class="kwd">import</span><span class="pln"> serializers
from </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RecipeSerializer</span><span class="pun">(</span><span class="pln">serializers</span><span class="pun">.</span><span class="typ">ModelSerializer</span><span class="pun">):</span><span class="pln">

    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pln">
        fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">"id"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"name"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ingredients"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"picture"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"difficulty"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"prep_time"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"prep_guide"</span><span class="pun">)</span></pre>

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

<h3>
	تجهيز لوحة الإدارة
</h3>

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

<p>
	افتح الملف "core/admin.py" وبدّل محتواه كليًّا بالأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_44" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pln">  </span><span class="com"># add this</span><span class="pln">
</span><span class="com"># Register your models here.</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="typ">Recipe</span><span class="pun">)</span><span class="pln"> </span><span class="com"># add this</span></pre>

<h3>
	إنشاء العروض
</h3>

<p>
	لننشئ الصنف <code>RecipeViewSet</code> في الملف core/views.py. بدّل محتواه كليًا بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_47" style="">
<span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> viewsets
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">serializers </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">RecipeSerializer</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">RecipeViewSet</span><span class="pun">(</span><span class="pln">viewsets</span><span class="pun">.</span><span class="typ">ModelViewSet</span><span class="pun">):</span><span class="pln">
    serializer_class </span><span class="pun">=</span><span class="pln"> </span><span class="typ">RecipeSerializer</span><span class="pln">
    queryset </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Recipe</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	يوفّر الصنف <code>viewsets.ModelViewSet</code> توابع لمعالجة عمليات CRUD افتراضيًا، ولا نحتاج سوى تحديد صنف المسلسل ومجموعة الاستعلام <code>queryset</code>.
</p>

<h3>
	تجهيز عناوين محدد الموارد الموحد URL
</h3>

<p>
	اذهب إلى الملف "api/urls.py"، وبدّل محتواه كليًا بالسطور التالية التي تحدد مسار عنوان <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهة برمجة التطبيقات</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_53" style="">
<span class="pln">from django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
from django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path</span><span class="pun">,</span><span class="pln"> include        </span><span class="pun">#</span><span class="pln"> add </span><span class="kwd">this</span><span class="pln">
from django</span><span class="pun">.</span><span class="pln">conf </span><span class="kwd">import</span><span class="pln"> settings             </span><span class="pun">#</span><span class="pln"> add </span><span class="kwd">this</span><span class="pln">
from django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">.</span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="kwd">static</span><span class="pln">   </span><span class="pun">#</span><span class="pln"> add </span><span class="kwd">this</span><span class="pln">

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">"api/"</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="str">'core.urls'</span><span class="pun">))</span><span class="pln">       </span><span class="pun">#</span><span class="pln"> add </span><span class="kwd">this</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="kwd">if</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">DEBUG</span><span class="pun">:</span><span class="pln">
    urlpatterns </span><span class="pun">+=</span><span class="pln"> </span><span class="kwd">static</span><span class="pun">(</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">MEDIA_URL</span><span class="pun">,</span><span class="pln"> document_root</span><span class="pun">=</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">MEDIA_ROOT</span><span class="pun">)</span></pre>

<p>
	والآن أنشئ الملف "urls.py" في المجلد "core" وانسخ إليه السطور التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_55" style="">
<span class="pln">from django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path</span><span class="pun">,</span><span class="pln"> include
from rest_framework</span><span class="pun">.</span><span class="pln">routers </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">DefaultRouter</span><span class="pln">
from </span><span class="pun">.</span><span class="pln">views </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">RecipeViewSet</span><span class="pln">

router </span><span class="pun">=</span><span class="pln"> </span><span class="typ">DefaultRouter</span><span class="pun">()</span><span class="pln">
router</span><span class="pun">.</span><span class="kwd">register</span><span class="pun">(</span><span class="pln">r</span><span class="str">'recipes'</span><span class="pun">,</span><span class="pln"> </span><span class="typ">RecipeViewSet</span><span class="pun">)</span><span class="pln">

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">""</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="pln">router</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">))</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	يولد الصنف <code>router</code> في الشيفرة السابقة أنماط <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عناوين URL</a> التالية:
</p>

<ul>
<li>
		"/recipes/": يمكن أن تُنفذ عمليتي الإنشاء CREATE والقراءة READ على هذا الاتجاه route.
	</li>
	<li>
		"{recipes/{id/": يمكن أن تُنفذ عمليات القراءة READ والتحديث UPDATE والحذف DELETE على هذا الاتجاه.
	</li>
</ul>
<h3>
	تنفيذ عمليات التهجير
</h3>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_58" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations
</span><span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate   </span></pre>

<p>
	ننشئ الآن حساب مستخدم مميّز superuser للوصول إلى واجهة الإدارة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_60" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

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

<p>
	وبهذا نكون انتهينا من التهيئة اللازمة للواجهة الخلفية. نستطيع الآن اختبار واجهات برمجة التطبيقات APIs التي أنشاناها، لذلك نبدأ بتشغيل خادم جانغو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_62" style="">
<span class="pun">(</span><span class="pln">recipes_app</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	بعد أن يعمل الخادم، تستطيع التحقق من عمله بالذهاب إلى العنوان "/localhost:8000/api/recipes".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111507" href="https://academy.hsoub.com/uploads/monthly_2022_11/003.png.1a5b48c56853e997b71189cb20ca0cba.png" rel=""><img alt="التحقق من عمل الخادم" class="ipsImage ipsImage_thumbnailed" data-fileid="111507" data-unique="ha9g11n01" src="https://academy.hsoub.com/uploads/monthly_2022_11/003.thumb.png.7e8f8ff62ed7054ad753334d6ec4bcb9.png" style="width: 620px; height: auto;"></a>
</p>

<p>
	نستطيع إنشاء عنصر وصفة تحضير جديدة بهذه الواجهة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111508" href="https://academy.hsoub.com/uploads/monthly_2022_11/004.png.9f608ec605bdb92058d36a2144a1159b.png" rel=""><img alt="004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111508" data-unique="x428mjdcs" src="https://academy.hsoub.com/uploads/monthly_2022_11/004.thumb.png.7ec424037d40c56781dbba9ca4e0d61c.png" style="width: 620px; height: auto;"></a>
</p>

<p>
	نستطيع أيضًا إجراء عمليات DELETE و PUT و PATCH على بضعة عناصر من عناصر وصفات التحضير وذلك من خلال استخدام مفاتيحها الأساسية id؛ ولفعل ذلك نكتب في المتصفح عناوينًا تأخذ الشكل العام التالي: "{api/recipe/{id/".
</p>

<p>
	لنجرب الآن العنوان "localhost:8000/api/recipes/1":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111509" href="https://academy.hsoub.com/uploads/monthly_2022_11/005.png.dda5505851a97af7945177ee5f7b9a34.png" rel=""><img alt='استخدام العنوان "localhost:8000/api/recipes/1"' class="ipsImage ipsImage_thumbnailed" data-fileid="111509" data-unique="f349acgc3" src="https://academy.hsoub.com/uploads/monthly_2022_11/005.thumb.png.6dd2db0dfc8fd9eff23a15e495b90b2f.png" style="width: 680px; height: auto;"></a>
</p>

<p>
	وبهذا يكتمل إعداد الواجهة الخلفية للتطبيق وحان الآن وقت الواجهة الأمامية.
</p>

<h2>
	الخطوة الثانية- تحضير الواجهة الأمامية
</h2>

<p>
	سنبني الآن الواجهة الأمامية للتطبيق. نريد وضع مجلد شيفرة الواجهة الأمامية في جذر المجلد "recipes_app"، لذا اخرج أولًا من المجلد "api"، أو شغّل نافذة طرفية جديدة تعمل جنبًا إلى جنب مع نافذة الطرفية الأولى قبل تنفيذ الأوامر التي ستأتي في هذا الجزء من المقالة.
</p>

<p>
	لننشئ تطبيق nuxt ونطلق عليه اسم "client" مستخدمين الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_70" style="">
<span class="pln">$ npx create</span><span class="pun">-</span><span class="pln">nuxt</span><span class="pun">-</span><span class="pln">app client</span></pre>

<p>
	<strong>ملاحظة</strong>: سيؤدي وضع <code>npx</code> قبل <code>create-nuxt-app</code> في التعليمة إلى تثبيت الحزمة إذا لم تكن مثبّتة للعموم من قبل على جهازك.
</p>

<p>
	بعد اكتمال التثبيت سيسألك "create-nuxt-app" بضعة أسئلة حول بعض الأدوات التي ستضاف، وقد اخترنا منها ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_72" style="">
<span class="pun">?</span><span class="pln"> </span><span class="typ">Project</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> client
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Programming</span><span class="pln"> language</span><span class="pun">:</span><span class="pln"> </span><span class="typ">JavaScript</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Package</span><span class="pln"> manager</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Npm</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> UI framework</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Bootstrap</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Nuxt</span><span class="pun">.</span><span class="pln">js modules</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Axios</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Linting</span><span class="pln"> tools</span><span class="pun">:</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Testing</span><span class="pln"> framework</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Rendering</span><span class="pln"> mode</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Universal</span><span class="pln"> </span><span class="pun">(</span><span class="pln">SSR </span><span class="pun">/</span><span class="pln"> SSG</span><span class="pun">)</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Deployment</span><span class="pln"> target</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Server</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pun">.</span><span class="pln">js hosting</span><span class="pun">)</span><span class="pln">
</span><span class="pun">?</span><span class="pln"> </span><span class="typ">Development</span><span class="pln"> tools</span><span class="pun">:</span></pre>

<p>
	سيعطي هذا إشارةً لمدير الحزم لكي يبدأ في تثبيت الاعتمادات.
</p>

<p>
	انتقل الآن إلى المجلد client:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_74" style="">
<span class="pln">$ cd client</span></pre>

<p>
	لننفذ الآن الأمر التالي لتشغيل التطبيق في وضع التطوير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_76" style="">
<span class="pln">npm run dev</span></pre>

<p>
	بعد أن يقلع خادم التطوير، توجّه إلى العنوان "localhost:3000" لرؤية التطبيق، إذ يفترض أن يكون كما في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111510" href="https://academy.hsoub.com/uploads/monthly_2022_11/006.png.eefe48c4f0230626475aa446416557fa.png" rel=""><img alt="شكل التطبيق " class="ipsImage ipsImage_thumbnailed" data-fileid="111510" data-unique="btn9qtqxy" src="https://academy.hsoub.com/uploads/monthly_2022_11/006.thumb.png.9c70f7bcd294d146ec54e60be108112e.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	الآن، لنلقِ نظرةً على بنية المجلد client:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_80" style="">
<span class="pun">├──</span><span class="pln"> client
  </span><span class="pun">├──</span><span class="pln"> assets</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> components</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> layouts</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> middleware</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> node_modules</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> pages</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> plugins</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">├──</span><span class="pln"> static</span><span class="pun">/</span><span class="pln">
  </span><span class="pun">└──</span><span class="pln"> store</span><span class="pun">/</span></pre>

<p>
	نلاحظ احتواءه على بضعة مجلدات نشرحها فيما يلي:
</p>

<ul>
<li>
		Assets: يحتوي على ملفات غير مصرّفة uncompiled، مثل ملفات الصور و <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> و <a href="https://academy.hsoub.com/programming/css/sass/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-sass-r8/" rel="">Sass</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكريبت Javascript</a>.
	</li>
	<li>
		Components: يحتوي على مكونات فيو جي إس Vue.js.
	</li>
	<li>
		Layouts: يحتوي على أنساق التطبيق، المُستخدمة لتغيير مظهر الصفحة وقد تُستخدم لعدة صفحات معًا.
	</li>
	<li>
		Middleware: يحتوي على البرمجيات الوسيطة للتطبيق، وهي دوال مخصصة تُشغّل قبل تصيير الصفحة على المتصفح.
	</li>
	<li>
		Pages: تحتوي على عروض ومسارات التطبيق. يقرأ نُكست كل الملفات ذات الامتداد "vue." في هذا المجلد ويستخدم المعلومات التي يحصل عليها لإنشاء موجّه التطبيق.
	</li>
	<li>
		Plugins: يحتوي على إضافات جافا سكريبت البرمجية التي ستُشغّل قبل استنساخ تطبيق فيو جي إس الجذر.
	</li>
	<li>
		Static: يحتوي على الملفات الساكنة (التي غالبًا لن تتغير) وكل الملفات المرتبطة بجذر التطبيق "/".
	</li>
	<li>
		Store: يحتوي على ملفات المتجر إذا كنا سنستخدم فيو إكس Vuex مع نُكست.
	</li>
</ul>
<p>
	وهناك أيضًا الملف nuxt.config.js ضمن المجلد client، إذ يحتوي هذا الملف على تهيئة مخصصة لتطبيق نُكست.
</p>

<p>
	وقبل المتابعة نزّل <a href="http://res.cloudinary.com/hotels-ng/raw/upload/v1547983600/images_fmquow.zip" rel="external nofollow">الملف</a>، وفك ضغطه وضع مجلد images داخل المجلد static.
</p>

<h3>
	بنية الصفحات
</h3>

<p>
	سنضيف الآن بعض ملفات ذات الامتداد "vue." إلى المجلد pages لكي يحتوي تطبيقنا على خمس صفحات:
</p>

<ul>
<li>
		Homepage
	</li>
	<li>
		All Recipes list page
	</li>
	<li>
		Single Recipe view page
	</li>
	<li>
		Single Recipe edit page
	</li>
	<li>
		Add Recipe page
	</li>
</ul>
<p>
	لنضف الآن ملفات ومجلدات "vue." التالية إلى المجلد pages ليكون لدينا نفس البنية التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_85" style="">
<span class="pun">├──</span><span class="pln"> pages</span><span class="pun">/</span><span class="pln">
   </span><span class="pun">├──</span><span class="pln"> recipes</span><span class="pun">/</span><span class="pln">
     </span><span class="pun">├──</span><span class="pln"> _id</span><span class="pun">/</span><span class="pln">
       </span><span class="pun">└──</span><span class="pln"> edit</span><span class="pun">.</span><span class="pln">vue
       </span><span class="pun">└──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">vue
     </span><span class="pun">└──</span><span class="pln"> add</span><span class="pun">.</span><span class="pln">vue
     </span><span class="pun">└──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">vue
  </span><span class="pun">└──</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">vue</span></pre>

<p>
	ستولد بنية الملفات السابقة الوجهات routes التالية:
</p>

<ul>
<li>
		"/" الذي يُعالج بواسطة "pages/index.vue".
	</li>
	<li>
		"recipes/add/" الذي يُعالج بواسطة "pages/recipes/add.vue".
	</li>
	<li>
		"/recipes/" الذي يُعالج بواسطة "pages/recipes/index.vue".
	</li>
	<li>
		"/{recipes/{id/" الذي يُعالج بواسطة pages/recipes/_id/index.vue.
	</li>
	<li>
		"recipes/{id}/edit/" الذي يُعالج بواسطة "pages/recipes/_id/edit.vue".
	</li>
</ul>
<p>
	ينشئ أي ملف أو مجلد "vue." يبدأ اسمه بشرطة سفلية underscore مسارًا ديناميكيًا، وهذا مفيدٌ في تطبيقنا لأنه سيسهل عرض وصفات الطبخ المختلفة وذلك بناءً على معرّفاتها IDs. على سبيل المثال: "/recipes/1" و "/recipes/2" وهكذا.
</p>

<h3>
	إنشاء الصفحة الرئيسية Homepage
</h3>

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

<p>
	افتح الملف layouts/default.vue وبدّل محتواه بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_89" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;nuxt/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

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

<p>
	دعنا نحدّث الملف pages/index.vue بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_92" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;header&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-box"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;h1&gt;</span><span class="pln">La Recipes ?</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
      </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mt-3"</span><span class="tag">&gt;</span><span class="pln">Recipes for the meals we love ❤️</span><span class="tag">&lt;/p&gt;</span><span class="pln">
      </span><span class="tag">&lt;nuxt-link</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-outline btn-large btn-info"</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/recipes"</span><span class="tag">&gt;</span><span class="pln">
        View Recipes </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"ml-2"</span><span class="tag">&gt;</span><span class="pln">→</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;/nuxt-link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/header&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home page"</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="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
header </span><span class="pun">{</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100vh</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">image</span><span class="pun">:</span><span class="pln"> linear</span><span class="pun">-</span><span class="pln">gradient</span><span class="pun">(</span><span class="pln">
      to right</span><span class="pun">,</span><span class="pln">
      rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">),</span><span class="pln">
      rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.4</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="str">"/images/banner.jpg"</span><span class="pun">);</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> cover</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">text</span><span class="pun">-</span><span class="pln">box </span><span class="pun">{</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">%;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">%;</span><span class="pln">
  transform</span><span class="pun">:</span><span class="pln"> translateY</span><span class="pun">(-</span><span class="lit">50</span><span class="pun">%);</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">text</span><span class="pun">-</span><span class="pln">box h1 </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> cursive</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">text</span><span class="pun">-</span><span class="pln">box p </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> lighter</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	لدينا في الشيفرة السابقة <code>&lt;nuxt-link&gt;</code>، وهو مكون نُكست يُستخدم للتنقل بين الصفحات، وهو مشابهٌ كثيرًا للمكون <code>&lt;router-link&gt;</code> من <a href="https://router.vuejs.org/api/" rel="external nofollow">Vue Router</a>
</p>

<p>
	لنشغّل خادم التطوير للواجهة الأمامية، إذا لم يكن في وضع التشغيل فعليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_94" style="">
<span class="pln">$ npm run dev</span></pre>

<p>
	اذهب إلى العنوان localhost:3000 وتأمل الصفحة الرئيسية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111511" href="https://academy.hsoub.com/uploads/monthly_2022_11/007.png.0ecf1e8e0140ef8b5807be0ae92b2759.png" rel=""><img alt="الصفحة الرئيسية للعنوان localhost:3000" class="ipsImage ipsImage_thumbnailed" data-fileid="111511" data-unique="973jvhxbq" src="https://academy.hsoub.com/uploads/monthly_2022_11/007.thumb.png.055c21c1a2848862a6230f931a306ed6.png" style="width: 650px; height: auto;"></a>
</p>

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

<p>
	ستكون كل صفحة في هذا التطبيق مكونًا من مكونات فيو، ويزود نُكست بسمات ودوال خاصة لتسهيل تطوير التطبيقات. يمكنك العثور على كل تلك <a href="https://nuxtjs.org/docs/concepts/views/#pages" rel="external nofollow">السمات الخاصة في التوثيق الرسمي</a>.
</p>

<p>
	سنستعمل لأغراض هذه المقالة دالتين من هذه الدوال، هما:
</p>

<ul>
<li>
		<code>()head</code>: يُستخدم هذا التابع لوضع وسوم وصفية محددة <code>&lt;meta&gt;</code> للصفحة الحالية.
	</li>
	<li>
		<code>()asyncData</code>: يُستخدم هذا التابع لجلب البيانات قبل أن يُحمّل مكون الصفحة. بعد ذلك، يُدمج الكائن المعاد مع بيانات مكون الصفحة، وسنستفيد من هذا لاحقًا في هذه المقالة.
	</li>
</ul>
<h3>
	إنشاء صفحة قائمة وصفات التحضير
</h3>

<p>
	دعنا ننشئ مكون فيو اسمه "RecipeCard.vue" داخل المجلد components ونحدّثه بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_101" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card recipe-card"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> :</span><span class="atn">src</span><span class="pun">=</span><span class="atv">"recipe.picture"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-img-top"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-body"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;h5</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-title"</span><span class="tag">&gt;</span><span class="pln">{{ recipe.name }}</span><span class="tag">&lt;/h5&gt;</span><span class="pln">
      </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-text"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;strong&gt;</span><span class="pln">Ingredients:</span><span class="tag">&lt;/strong&gt;</span><span class="pln"> {{ recipe.ingredients }}
      </span><span class="tag">&lt;/p&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"action-buttons"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;nuxt-link</span><span class="pln"> :</span><span class="atn">to</span><span class="pun">=</span><span class="atv">"`/recipes/${recipe.id}/`"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-sm btn-success"</span><span class="tag">&gt;</span><span class="pln">View</span><span class="tag">&lt;/nuxt-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;nuxt-link</span><span class="pln"> :</span><span class="atn">to</span><span class="pun">=</span><span class="atv">"`/recipes/${recipe.id}/edit/`"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-sm btn-primary"</span><span class="tag">&gt;</span><span class="pln">Edit</span><span class="tag">&lt;/nuxt-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"onDelete(recipe.id)"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-sm btn-danger"</span><span class="tag">&gt;</span><span class="pln">Delete</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"recipe"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"onDelete"</span><span class="pun">]</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">recipe</span><span class="pun">-</span><span class="pln">card </span><span class="pun">{</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">6</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	يقبل المكون الظاهر أعلاه خاصّيتين، هما:
</p>

<ul>
<li>
		كائن <code>recipe</code> يحتوي على معلومات عن وصفة تحضير معينة.
	</li>
	<li>
		التابع <code>onDelete</code> الذي سيعمل عندما يضغط مستخدم التطبيق على زر حذف وصفة تحضير.
	</li>
</ul>
<p>
	افتح الآن الوجهة "pages/recipes/index.vue" وحدثها بأسطر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_103" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container mt-5"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12 text-right mb-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"d-flex justify-content-between"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;h3&gt;</span><span class="pln">La Recipes</span><span class="tag">&lt;/h3&gt;</span><span class="pln">
          </span><span class="tag">&lt;nuxt-link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/recipes/add"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-info"</span><span class="tag">&gt;</span><span class="pln">Add Recipe</span><span class="tag">&lt;/nuxt-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;template</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"recipe in recipes"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"recipe.id"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-lg-3 col-md-4 col-sm-6 mb-4"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;recipe-card</span><span class="pln"> :</span><span class="atn">onDelete</span><span class="pun">=</span><span class="atv">"</span><span class="pln">deleteRecipe</span><span class="atv">"</span><span class="pln"> :</span><span class="atn">recipe</span><span class="pun">=</span><span class="atv">"recipe"</span><span class="tag">&gt;&lt;/recipe-card&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/template&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/main&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">RecipeCard</span><span class="pln"> from </span><span class="str">"~/components/RecipeCard.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> sampleData </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Jollof Rice"</span><span class="pun">,</span><span class="pln">
    picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/food-1.jpeg"</span><span class="pun">,</span><span class="pln">
    ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Beef, Tomato, Spinach"</span><span class="pun">,</span><span class="pln">
    difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">"easy"</span><span class="pun">,</span><span class="pln">
    prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln">
    prep_guide</span><span class="pun">:</span><span class="pln">
      </span><span class="str">"Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Macaroni"</span><span class="pun">,</span><span class="pln">
    picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/food-2.jpeg"</span><span class="pun">,</span><span class="pln">
    ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Beef, Tomato, Spinach"</span><span class="pun">,</span><span class="pln">
    difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">"easy"</span><span class="pun">,</span><span class="pln">
    prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln">
    prep_guide</span><span class="pun">:</span><span class="pln">
      </span><span class="str">"Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fried Rice"</span><span class="pun">,</span><span class="pln">
    picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/images/banner.jpg"</span><span class="pun">,</span><span class="pln">
    ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Beef, Tomato, Spinach"</span><span class="pun">,</span><span class="pln">
    difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">"easy"</span><span class="pun">,</span><span class="pln">
    prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln">
    prep_guide</span><span class="pun">:</span><span class="pln">
      </span><span class="str">"Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Recipes list"</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">RecipeCard</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  asyncData</span><span class="pun">(</span><span class="pln">context</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let data </span><span class="pun">=</span><span class="pln"> sampleData</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipes</span><span class="pun">:</span><span class="pln"> data
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipes</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">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    deleteRecipe</span><span class="pun">(</span><span class="pln">recipe_id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">deleted </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">recipe</span><span class="pun">.</span><span class="pln">id</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="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	شغّل الآن خادم التطوير للواجهة الأمامية إذا لم يكن يعمل فعلًا:
</p>

<pre class="ipsCode">
$ npm run dev
</pre>

<p>
	ثم اذهب إلى العنوان localhost:3000/recipes وتأمل في صفحة قائمة وصفات الطبخ:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111512" href="https://academy.hsoub.com/uploads/monthly_2022_11/008.png.4851e0a9a1f2a88ef04c0540dc561815.png" rel=""><img alt="صفحة قائمة وصفات الطبخ" class="ipsImage ipsImage_thumbnailed" data-fileid="111512" data-unique="9fujflofm" src="https://academy.hsoub.com/uploads/monthly_2022_11/008.thumb.png.fc9e18ac73bb2006df369e3f5f34eea9.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	نلاحظ في الصورة السابقة ظهور ثلاث بطاقات وصفات تحضير رغم أننا حددنا قيمة recipes بمصفوفة فارغة في قسم البيانات من المكون، وتفسير هذا هو أن التابع <code>asyncData</code> يُنفّذ قبل أن تُحمّل الصفحة ويعيد كائنًا يحدّث بيانات المكون.
</p>

<p>
	كل ما نحتاجه الآن هو أن نعدل التابع <code>asyncData</code> لينشئ طلب api إلى الواجهة الخلفية لجانغو ويحدّث بيانات المكون بالنتيجة.
</p>

<p>
	ولكن يجب علينا تجهيز آكسيوس Axios قبل تفعيل ذلك، لذا افتح الملف nuxt.config.js وحدثه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_108" style="">
<span class="com">// أضف كائن أكسيوس التالي</span><span class="pln">
axios</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  baseURL</span><span class="pun">:</span><span class="pln"> </span><span class="str">"http://localhost:8000/api"</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	<strong>ملاحظة:</strong> يفترِض هذا أنك اخترت "Axios" عند استخدام "create-nuxt-app"، فإذا لم تكن قد اخترته فعلًا، فستحتاج إلى تثبيت وتهيئة المصفوفة <code>modules</code> يدويًا.
</p>

<p>
	افتح الآن الملف "pages/recipes/index.vue" وبدّل القسم <code>&lt;script&gt;</code> بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_110" style="">
<span class="pun">[...]</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">RecipeCard</span><span class="pln"> from </span><span class="str">"~/components/RecipeCard.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Recipes list"</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">RecipeCard</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  async asyncData</span><span class="pun">({</span><span class="pln"> $axios</span><span class="pun">,</span><span class="pln"> params </span><span class="pun">})</span><span class="pln"> </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">
      let recipes </span><span class="pun">=</span><span class="pln"> await $axios</span><span class="pun">.</span><span class="pln">$get</span><span class="pun">(`/</span><span class="pln">recipes</span><span class="pun">/`);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipes </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipes</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">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipes</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">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    async deleteRecipe</span><span class="pun">(</span><span class="pln">recipe_id</span><span class="pun">)</span><span class="pln"> </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">
        await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$axios</span><span class="pun">.</span><span class="pln">$delete</span><span class="pun">(`/</span><span class="pln">recipes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">recipe_id</span><span class="pun">}/`);</span><span class="pln"> </span><span class="com">// delete recipe</span><span class="pln">
        let newRecipes </span><span class="pun">=</span><span class="pln"> await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$axios</span><span class="pun">.</span><span class="pln">$get</span><span class="pun">(</span><span class="str">"/recipes/"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// get new list of recipes</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipes </span><span class="pun">=</span><span class="pln"> newRecipes</span><span class="pun">;</span><span class="pln"> </span><span class="com">// update list of recipes</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">e</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">[...]</span></pre>

<p>
	يستقبل التابع <code>()asyncData</code>في الشيفرة السابقة كائنًا اسمه <code>context</code>، الذي نفكّكه للحصول على <code>axios$</code>. ولمعرفة المزيد عن بقية سمات الكائن <code>context</code> يرجى مراجعة <a href="https://nuxtjs.org/docs/internals-glossary/context/" rel="external nofollow">توثيقه الرسمي</a>.
</p>

<p>
	أضفنا <code>()asyncData</code> داخل كتلة <code>try...catch</code> لأننا نريد منع ظهور الخطأ الذي يظهر عندما لا يكون خادم الواجهة الخلفية في حالة عمل ويفشل آكسيوس في استعادة البيانات. وهكذا، مع هذه الإضافة فإنه في كل مرة يحدث هذا الخطأ، توضع قيمة <code>recipes</code> بمصفوفة فارغة بدلًا من ذلك.
</p>

<p>
	هذا السطر من الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_112" style="">
<span class="pln">let recipes </span><span class="pun">=</span><span class="pln"> await $axios</span><span class="pun">.</span><span class="pln">$get</span><span class="pun">(</span><span class="str">"/recipes/"</span><span class="pun">)</span></pre>

<p>
	هو نسخةٌ أقصر من السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1913_114" style="">
<span class="pln">let response </span><span class="pun">=</span><span class="pln"> await $axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">"/recipes"</span><span class="pun">)</span><span class="pln">
let recipes </span><span class="pun">=</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span></pre>

<p>
	يحذف التابع <code>()deleteRecipe</code> وصفة تحضير معينة ويحضر أحدث قائمة لوصفات التحضير من الواجهة الخلفية لجانغو، ثم يحدّث أخيرًا بيانات المكوّن.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1913_116" style="">
<span class="pln">$ npm run dev</span></pre>

<p>
	لنذهب الآن إلى الصفحة localhost:3000/recipes:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2022_11/009.png.0c90949f41b258308fe5a18c8872412e.png" data-fileid="111515" rel=""><img alt="صفحة قوائم الطعام" class="ipsImage ipsImage_thumbnailed" data-fileid="111515" data-unique="nb3422u3c" src="https://academy.hsoub.com/uploads/monthly_2022_11/009.thumb.png.3e372b888c12fc4b6665a9df50cc973c.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	جرب حذف عناصر الوصفات وانظر ما سيحدث.
</p>

<h3>
	إضافة وصفات طبخ جديدة
</h3>

<p>
	نريد أن نتمكن كما ذكرنا من قبل من إضافة وصفات جديدة من الواجهة الأمامية للتطبيق، لذا افتح الملف "‎/pages/recipes/add" وحدّثه بمقطع الشيفرة التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_118" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container my-5"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12 text-center my-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mb-3 display-4 text-uppercase"</span><span class="tag">&gt;</span><span class="pln">{{ recipe.name }}</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6 mb-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln">
          </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"preview"</span><span class="pln">
          </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"img-fluid"</span><span class="pln">
          </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">7</span><span class="pun">);</span><span class="atv">"</span><span class="pln">
          :</span><span class="atn">src</span><span class="pun">=</span><span class="atv">"preview"</span><span class="pln">
          </span><span class="atn">alt</span><span class="pln">
        </span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln">
          </span><span class="atn">v-else</span><span class="pln">
          </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"img-fluid"</span><span class="pln">
          </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">7</span><span class="pun">);</span><span class="atv">"</span><span class="pln">
          </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"@/static/images/placeholder.png"</span><span class="pln">
        </span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;form</span><span class="pln"> @</span><span class="atn">submit</span><span class="pln">.</span><span class="atn">prevent</span><span class="pun">=</span><span class="atv">"submitRecipe"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Recipe Name</span><span class="tag">&lt;/label&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">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.name"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Ingredients</span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.ingredients"</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">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Food picture</span><span class="tag">&lt;/label&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">"file"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"file"</span><span class="pln"> @</span><span class="atn">change</span><span class="pun">=</span><span class="atv">"onFileChange"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Difficulty</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.difficulty"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="tag">&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Easy"</span><span class="tag">&gt;</span><span class="pln">Easy</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Medium"</span><span class="tag">&gt;</span><span class="pln">Medium</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Hard"</span><span class="tag">&gt;</span><span class="pln">Hard</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                </span><span class="tag">&lt;/select&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">
                  Prep time
                  </span><span class="tag">&lt;small&gt;</span><span class="pln">(minutes)</span><span class="tag">&lt;/small&gt;</span><span class="pln">
                </span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.prep_time"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group mb-3"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Preparation guide</span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.prep_guide"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"8"</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="tag">&gt;</span><span class="pln">Submit</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/form&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/main&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Add Recipe"</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipe</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        prep_guide</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      preview</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    onFileChange</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let files </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">files </span><span class="pun">||</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">dataTransfer</span><span class="pun">.</span><span class="pln">files</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">files</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">return</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipe</span><span class="pun">.</span><span class="pln">picture </span><span class="pun">=</span><span class="pln"> files</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createImage</span><span class="pun">(</span><span class="pln">files</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    createImage</span><span class="pun">(</span><span class="pln">file</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// let image = new Image();</span><span class="pln">
      let reader </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileReader</span><span class="pun">();</span><span class="pln">
      let vm </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
      reader</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        vm</span><span class="pun">.</span><span class="pln">preview </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">result</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
      reader</span><span class="pun">.</span><span class="pln">readAsDataURL</span><span class="pun">(</span><span class="pln">file</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    async submitRecipe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> config </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"content-type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"multipart/form-data"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
      let formData </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FormData</span><span class="pun">();</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let data in </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipe</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        formData</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipe</span><span class="pun">[</span><span class="pln">data</span><span class="pun">]);</span><span class="pln">
      </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">
        let response </span><span class="pun">=</span><span class="pln"> await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$axios</span><span class="pun">.</span><span class="pln">$post</span><span class="pun">(</span><span class="str">"/recipes/"</span><span class="pun">,</span><span class="pln"> formData</span><span class="pun">,</span><span class="pln"> config</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$router</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"/recipes/"</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">e</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="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	وفقًا للتابع <code>()submitRecipe</code>: حالما تُنشر بيانات نموذج التعبئة وتنشأ وصفة التحضير بنجاح، يُعاد توجيه التطبيق إلى المجلد "/recipes/" باستخدام <code>this.$router</code>.
</p>

<h3>
	إنشاء صفحة استعراض وصفة تحضير واحدة
</h3>

<p>
	لننشئ الآن العرض الذي يسمح للمستخدم باستعراض عنصر وصفة طبخ واحدة. افتح الملف "pages/recipes/_id/index.vue/" وضع فيه مقطع الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_120" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container my-5"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12 text-center my-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mb-3 display-4 text-uppercase"</span><span class="tag">&gt;</span><span class="pln">{{ recipe.name }}</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6 mb-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln">
          </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"img-fluid"</span><span class="pln">
          </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">7</span><span class="pun">);</span><span class="atv">"</span><span class="pln">
          :</span><span class="atn">src</span><span class="pun">=</span><span class="atv">"recipe.picture"</span><span class="pln">
          </span><span class="atn">alt</span><span class="pln">
        </span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"recipe-details"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;h4&gt;</span><span class="pln">Ingredients</span><span class="tag">&lt;/h4&gt;</span><span class="pln">
          </span><span class="tag">&lt;p&gt;</span><span class="pln">{{ recipe.ingredients }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
          </span><span class="tag">&lt;h4&gt;</span><span class="pln">Preparation time ⏱</span><span class="tag">&lt;/h4&gt;</span><span class="pln">
          </span><span class="tag">&lt;p&gt;</span><span class="pln">{{ recipe.prep_time }} mins</span><span class="tag">&lt;/p&gt;</span><span class="pln">
          </span><span class="tag">&lt;h4&gt;</span><span class="pln">Difficulty</span><span class="tag">&lt;/h4&gt;</span><span class="pln">
          </span><span class="tag">&lt;p&gt;</span><span class="pln">{{ recipe.difficulty }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
          </span><span class="tag">&lt;h4&gt;</span><span class="pln">Preparation guide</span><span class="tag">&lt;/h4&gt;</span><span class="pln">
          </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"10"</span><span class="pln"> </span><span class="atn">v-html</span><span class="pun">=</span><span class="atv">"recipe.prep_guide"</span><span class="pln"> </span><span class="atn">disabled</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/main&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"View Recipe"</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  async asyncData</span><span class="pun">({</span><span class="pln"> $axios</span><span class="pun">,</span><span class="pln"> params </span><span class="pun">})</span><span class="pln"> </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">
      let recipe </span><span class="pun">=</span><span class="pln"> await $axios</span><span class="pun">.</span><span class="pln">$get</span><span class="pun">(`/</span><span class="pln">recipes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}`);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipe </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipe</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">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipe</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        prep_guide</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</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="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	قدمنا هنا المفتاح <code>params</code> الذي رأيناه في التابع <code>()asyncData</code>، ونستخدمه في حالتنا هذه للحصول على المعرف ID لوصفة الطبخ التي نريد مشاهدتها. نستخرج المفتاح <code>params</code> من <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">الرابط URL</a> ونحضر بياناته قبل عرضها على الصفحة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111513" href="https://academy.hsoub.com/uploads/monthly_2022_11/010.png.bd28ddb4e8fecf8023f05690cf564d5f.png" rel=""><img alt="استخراج المفتاح params من URL ونحضر بياناته قبل العرض على الصفحة" class="ipsImage ipsImage_thumbnailed" data-fileid="111513" data-unique="wzhtdrim3" src="https://academy.hsoub.com/uploads/monthly_2022_11/010.thumb.png.c19e40f59d5364e9c1a795e451fb7414.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	نلاحظ ظهور عنصر وصفة طبخ واحدة على شاشة المتصفح.
</p>

<h3>
	إنشاء صفحة تعديل وصفة تحضير واحدة
</h3>

<p>
	نحتاج لإنشاء العرض الذي يسمح للمستخدم بتحرير وتعديل عنصر وصفة طبخ واحدة. افتح الملف "pages/recipes/_id/edit.vue/" وضع فيه مقطع الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1913_125" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container my-5"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12 text-center my-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"mb-3 display-4 text-uppercase"</span><span class="tag">&gt;</span><span class="pln">{{ recipe.name }}</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6 mb-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"!preview"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"img-fluid"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">7</span><span class="pun">);</span><span class="atv">"</span><span class="pln">  :</span><span class="atn">src</span><span class="pun">=</span><span class="atv">"recipe.picture"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">v-else</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"img-fluid"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400px</span><span class="pun">;</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,.</span><span class="lit">7</span><span class="pun">);</span><span class="atv">"</span><span class="pln">  :</span><span class="atn">src</span><span class="pun">=</span><span class="atv">"preview"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-4"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;form</span><span class="pln"> @</span><span class="atn">submit</span><span class="pln">.</span><span class="atn">prevent</span><span class="pun">=</span><span class="atv">"submitRecipe"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Recipe Name</span><span class="tag">&lt;/label&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">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.name"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Ingredients</span><span class="tag">&lt;/label&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">v-model</span><span class="pun">=</span><span class="atv">"recipe.ingredients"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Ingredients"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Food picture</span><span class="tag">&lt;/label&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">"file"</span><span class="pln"> @</span><span class="atn">change</span><span class="pun">=</span><span class="atv">"onFileChange"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Difficulty</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.difficulty"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Easy"</span><span class="tag">&gt;</span><span class="pln">Easy</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Medium"</span><span class="tag">&gt;</span><span class="pln">Medium</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                  </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Hard"</span><span class="tag">&gt;</span><span class="pln">Hard</span><span class="tag">&lt;/option&gt;</span><span class="pln">
                </span><span class="tag">&lt;/select&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-md-6"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">
                  Prep time
                  </span><span class="tag">&lt;small&gt;</span><span class="pln">(minutes)</span><span class="tag">&lt;/small&gt;</span><span class="pln">
                </span><span class="tag">&lt;/label&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">v-model</span><span class="pun">=</span><span class="atv">"recipe.prep_time"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"Ingredients"</span><span class="pln"> </span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group mb-3"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="tag">&gt;</span><span class="pln">Preparation guide</span><span class="tag">&lt;/label&gt;</span><span class="pln">
            </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"recipe.prep_guide"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"8"</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-success"</span><span class="tag">&gt;</span><span class="pln">Save</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;/form&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/main&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  head</span><span class="pun">(){</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Edit Recipe"</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  async asyncData</span><span class="pun">({</span><span class="pln"> $axios</span><span class="pun">,</span><span class="pln"> params </span><span class="pun">})</span><span class="pln"> </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">
      let recipe </span><span class="pun">=</span><span class="pln"> await $axios</span><span class="pun">.</span><span class="pln">$get</span><span class="pun">(`/</span><span class="pln">recipes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}`);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipe </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> recipe</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">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      recipe</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        picture</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        ingredients</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        difficulty</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        prep_time</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
        prep_guide</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      preview</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    onFileChange</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let files </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">files </span><span class="pun">||</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">dataTransfer</span><span class="pun">.</span><span class="pln">files</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">files</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">return</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipe</span><span class="pun">.</span><span class="pln">picture </span><span class="pun">=</span><span class="pln"> files</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createImage</span><span class="pun">(</span><span class="pln">files</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    createImage</span><span class="pun">(</span><span class="pln">file</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let reader </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileReader</span><span class="pun">();</span><span class="pln">
      let vm </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
      reader</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> e </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        vm</span><span class="pun">.</span><span class="pln">preview </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">result</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
      reader</span><span class="pun">.</span><span class="pln">readAsDataURL</span><span class="pun">(</span><span class="pln">file</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    async submitRecipe</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      let editedRecipe </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">recipe
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">editedRecipe</span><span class="pun">.</span><span class="pln">picture</span><span class="pun">.</span><span class="pln">name</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="str">"http://"</span><span class="pun">)</span><span class="pln"> </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="kwd">delete</span><span class="pln"> editedRecipe</span><span class="pun">[</span><span class="str">"picture"</span><span class="pun">]</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> config </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"content-type"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"multipart/form-data"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
      let formData </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FormData</span><span class="pun">();</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let data in editedRecipe</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        formData</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> editedRecipe</span><span class="pun">[</span><span class="pln">data</span><span class="pun">]);</span><span class="pln">
      </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">
        let response </span><span class="pun">=</span><span class="pln"> await </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$axios</span><span class="pun">.</span><span class="pln">$patch</span><span class="pun">(`/</span><span class="pln">recipes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">editedRecipe</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}/`,</span><span class="pln"> formData</span><span class="pun">,</span><span class="pln"> config</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$router</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">"/recipes/"</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">e</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="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

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

<h3>
	إعداد الانتقالات
</h3>

<p>
	مع أن التطبيق يعمل جيدًا، لكن يمكننا أيضًا إعطاءه مظهرًا أسلس إذا أضفنا الانتقالات التي تسمح لنا بتغيير قيم خصائص <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> من قيمة إلى أخرى بسلاسة ضمن فترة زمنية محددة.
</p>

<p>
	وسنجهز الانتقالات في الملف nuxt.config.js. <a href="https://nuxtjs.org/docs/configuration-glossary/configuration-transition/" rel="external nofollow">ويأخذ اسم الانتقال افتراضيًّا الاسم page</a> الذي يعني أن الانتقالات التي نعرّفها ستكون ساريةً على جميع الصفحات.
</p>

<p>
	لنضمّن نمط الانتقال، لذا أنشئ مجلدًا وسمِّه "css" في المجلد "assets" وأضف الملف "transitions.css" داخله. افتح الآن الملف "transitions.css" وضع فيه مقطع الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1913_130" style="">
<span class="pun">.</span><span class="pln">page</span><span class="pun">-</span><span class="pln">enter</span><span class="pun">-</span><span class="pln">active</span><span class="pun">,</span><span class="pln">
</span><span class="pun">.</span><span class="pln">page</span><span class="pun">-</span><span class="pln">leave</span><span class="pun">-</span><span class="pln">active </span><span class="pun">{</span><span class="pln">
  transition</span><span class="pun">:</span><span class="pln"> opacity </span><span class="pun">.</span><span class="lit">3s</span><span class="pln"> ease</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">page</span><span class="pun">-</span><span class="pln">enter</span><span class="pun">,</span><span class="pln">
</span><span class="pun">.</span><span class="pln">page</span><span class="pun">-</span><span class="pln">leave</span><span class="pun">-</span><span class="pln">to </span><span class="pun">{</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	افتح الملف nuxt.config.js وحدِّثه كما يلي لتحميل ملف CSS الذي أنشأناه للتو:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1913_132" style="">
<span class="com">/*
** Global CSS
*/</span><span class="pln">
css</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="str">'~/assets/css/transitions.css'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// update this</span><span class="pln">
</span><span class="pun">],</span></pre>

<p>
	احفظ التغييرات وافتح التطبيق في متصفحك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="111514" href="https://academy.hsoub.com/uploads/monthly_2022_11/011.gif.545da06f7023a93f536e6054753c2b24.gif" rel=""><img alt="011.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="111514" data-unique="m7vvnl464" src="https://academy.hsoub.com/uploads/monthly_2022_11/011.thumb.gif.4b7166fa88e8c322388d2eb593ec07c9.gif" style="width: 750px; height: auto;"></a>
</p>

<p>
	وبهذا سيغير التطبيقُ الإطاراتِ عند كل انتقال بطريقة أنيقة وجميلة.
</p>

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

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

<p>
	تتوفر <a href="https://github.com/do-community/recipes_app" rel="external nofollow">الشيفرة المصدرية لهذه المقالة على موقع Github</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقالة <a href="https://www.digitalocean.com/community/tutorials/how-to-build-a-universal-application-with-nuxt-js-and-django" rel="external nofollow">How To Build a Universal Application with Nuxt.js and Django</a> لصاحبها Jordan Irabor.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A3%D8%B7%D8%B1-%D8%B9%D9%85%D9%84-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1567/" rel="">مقدمة إلى أطر عمل تطوير الويب من طرف العميل</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1774</guid><pubDate>Sat, 05 Nov 2022 11:41:53 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x645;&#x647;&#x627;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django &#x648;&#x631;&#x64A;&#x622;&#x643;&#x62A; React</title><link>https://academy.hsoub.com/programming/python/django/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-%D9%88%D8%B1%D9%8A%D8%A2%D9%83%D8%AA-react-r1773/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_11/63663390da298_-----Django--React.png.1675786979d587bdbcd8990b036b533e.png" /></p>
<p>
	سنبني في هذه المقالة تطبيق المهام To-Do application باستخدام جانغو Django وريآكت React.
</p>

<p>
	<a href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%A7-%D9%87%D9%8A-react%D8%9F-r773/" rel="">ريآكت</a> هي مكتبة مبنية <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">بلغة جافا سكربت</a>، وتُستخدم لتطوير تطبيقات الصفحة الواحدة Single-page applications -أو اختصارًا SPA. تتمتع ريآكت <a href="https://wiki.hsoub.com/React" rel="external">بتوثيق قوي</a> ومنظومة بيئية حيَّة؛ أما جانغو فهو إطار عمل ويب مبني <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>

<p>
	ستلعب ريآكت في التطبيق الذي سنطوّره دور الواجهة الأمامية <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-frontend-web-development/" rel="">frontend</a>، أو ما يسمى "إطار عمل من جهة العميل"، إذ ستتولى مسؤولية التعامل مع واجهة المستخدم إلى جانب جلب ووضع قيم البيانات من خلال الطلبات المُرسلة إلى الواجهة الخلفية لجانغو، التي تمثّل <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهة برمجة تطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> بُنِيَت باستخدام إطار عمل جانغو ريست Django REST -أو اختصارًا DRF.
</p>

<p>
	ستحصل في نهاية هذا المقال على تطبيق فعال ونظامي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="111494" href="https://academy.hsoub.com/uploads/monthly_2022_11/002fully_working_application.gif.42c277efd7a7b3edd09b07bdbe3c8a09.gif" rel=""><img alt="نتيجة بناء تطبيق مهام باستخدام جانغو Django وريآكت React" class="ipsImage ipsImage_thumbnailed" data-fileid="111494" data-unique="ywf3qcvr9" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/002fully_working_application.thumb.gif.019a1f7557ffff48c26a37f889bb5cd5.gif"></a>
</p>

<p>
	<strong>ملاحظة</strong>: إذا أردت الحصول على الشيفرة المصدرية لهذا المقال، فستجدها <a href="https://github.com/do-community/django-todo-react" rel="external nofollow">هنا</a>.
</p>

<p>
	<strong>تنبيه</strong>: الشيفرة الواردة هي للأغراض التعليمية وليست للاستخدام المهني للشركات.
</p>

<p>
	سيسمح التطبيق لمستخدميه بإنشاء قائمة بالمهام التي يودون إنجازها، وتُنجز كل مهمة بوضع علامة "مكتمل complete" عليها، وفي حال عدم إنجازها تُوضع عليها علامة "غير مكتمل incomplete".
</p>

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

<p>
	سنحتاج لكي نتمكن من تنفيذ ما في هذه المقالة إلى ما يلي:
</p>

<ol>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%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%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r714/" rel="">تثبيت بايثون 3 وإعداد بيئة برمجية</a> محلية له.
	</li>
	<li>
		تثبيت <a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel="">Node.js</a> وإنشاء بيئة تطوير محلية.
	</li>
</ol>

<p>
	إضافةً إلى الاعتماديات التالية:
</p>

<ul>
	<li>
		Python v3.9.1
	</li>
	<li>
		pip v20.2.4
	</li>
	<li>
		Django v3.1.6
	</li>
	<li>
		djangorestframework v3.12.2
	</li>
	<li>
		django-cors-headers v3.7.0
	</li>
	<li>
		Node v15.8.0
	</li>
	<li>
		npm v7.5.4
	</li>
	<li>
		React v17.0.1
	</li>
	<li>
		axios v0.21.0
	</li>
</ul>

<h2>
	الخطوة الأولى - إعداد الواجهة الخلفية
</h2>

<p>
	سننشئ الآن مجلد مشروع جديد ونثبّت جانغو وفق ما يلي:
</p>

<p>
	افتح نافذة طرفية جديدة terminal، ونفّذ الأمر التالي الذي سينشئ مجلد مشروع جديدًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_16" style=""><span class="pln">$ mkdir django</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">react</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_18" style=""><span class="pln">$ cd django</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">react</span></pre>

<p>
	الآن ثبّت <code>pipenv</code> مستخدمًا الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_20" style=""><span class="pln">$ pip install pipenv</span></pre>

<p>
	<strong>ملاحظة</strong>: قد تحتاج إلى استخدام <code>pip3</code> بدلًا من <code>pip</code> وهذا يعتمد على نوع التثبيت الذي تستخدمه.
</p>

<p>
	فعّل الآن بيئة افتراضية جديدة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_22" style=""><span class="pln">$ pipenv shell</span></pre>

<p>
	وثبّت جانغو باستخدام <code>pipenv</code> :
</p>

<pre class="ipsCode">$ pipenv install django
</pre>

<p>
	ثم أنشئ مشروع جانغو جديد وسمِّه <code><a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-backend-web-development/" rel="">backend</a></code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_24" style=""><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin startproject backend</span></pre>

<p>
	ثم انتقل إلى داخل ذلك المجلد:
</p>

<pre class="ipsCode">$ cd backend
</pre>

<p>
	وافتتح تطبيقًا جديدًا وسمِّه <code>todo</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_26" style=""><span class="pln">python manage</span><span class="pun">.</span><span class="pln">py startapp todo</span></pre>

<p>
	نفّذ عمليات التهجير migrations لكي تُطبق التغييرات التي أجريت للتو على مخطط <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_28" style=""><span class="pln">python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	وشغّل الخادم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_32" style=""><span class="pln">python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	اذهب إلى العنوان "http://localhost:8000" في متصفح الويب الذي تستخدمه، وستظهر لك الصفحة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111495" href="https://academy.hsoub.com/uploads/monthly_2022_11/003Django_application_running_successfully.png.840541b9e7a441160631031e0c1a753e.png" rel=""><img alt="صفحة العنوان http://localhost:8000" class="ipsImage ipsImage_thumbnailed" data-fileid="111495" data-unique="y18r581s8" style="width: 750px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/003Django_application_running_successfully.thumb.png.2920a3f6ee91a9b7f2e3054f8489ea92.png"></a>
</p>

<p>
	سيظهر لك في هذه النقطة نسخةً من تطبيق جانغو في وضعية التشغيل. يمكنك الآن بعد أن انتهيت إيقاف الخادم باستخدام المفتاحين التاليين: "CONTROL+C"، أو "CTRL+C".
</p>

<h3>
	تسجيل تطبيق المهام todo
</h3>

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

<p>
	افتح الملف "backend/settings.py" بمحرر الشيفرة الذي تستخدمه وأضف التطبيق "todo" إلى قائمة التطبيقات المثبّتة "INSTALLED_APPS":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_35" style=""><span class="com"># Application definition</span><span class="pln">

INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'todo'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	ثم احفظ التغييرات التي أجريتها على الملف.
</p>

<h3>
	تعريف نموذج تطبيق المهام Todo
</h3>

<p>
	لننشئ الآن نموذجًا نتمكن به من تعريف كيفية تخزين عناصر "Todo" في قاعدة البيانات.
</p>

<p>
	افتح الملف "todo/models.py" بمحرر الشيفرة وأضف السطور التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_37" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models

</span><span class="com"># Create your models here.</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Todo</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">120</span><span class="pun">)</span><span class="pln">
    description </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">
    completed </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">BooleanField</span><span class="pun">(</span><span class="pln">default</span><span class="pun">=</span><span class="kwd">False</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> _str_</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">title</span></pre>

<p>
	تعرّف الشيفرة السابقة ثلاث خاصيّات ضمن النموذج Todo وهي:
</p>

<ul>
	<li>
		<code>title</code>
	</li>
	<li>
		<code>description</code>
	</li>
	<li>
		<code>completed</code>
	</li>
</ul>

<p>
	تدل الخاصية <code>completed</code> على حالة المهمة في لحظة ما، فهي إما مكتملة أو غير مكتملة. ستحتاج الآن إلى إنشاء ملف تهجير بما أنك أنشأت نموذج "Todo":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_39" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations todo</span></pre>

<p>
	ثم طبّق التغييرات على قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_41" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate todo</span></pre>

<p>
	يمكنك التأكد من إمكانية تنفيذ عمليات الإنشاء والقراءة والتحديث والحذف Create Read Update Delete - أو اختصارًا CRUD- على نموذج "Todo" باستخدام واجهة الإدارة التي يوفرها جانغو لمستخدميه.
</p>

<p>
	ولفعل ذلك، افتح الملف "todo/admin.py" بمحرر الشيفرة، وأضف الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_43" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">TodoAdmin</span><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">ModelAdmin</span><span class="pun">):</span><span class="pln">
    list_display </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'title'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'description'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'completed'</span><span class="pun">)</span><span class="pln">

</span><span class="com"># Register your models here.</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="typ">Todo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">TodoAdmin</span><span class="pun">)</span></pre>

<p>
	ثم احفظ التغييرات.
</p>

<p>
	ستحتاج إلى حساب مستخدم مميز superuser لكي تتمكن من الدخول إلى واجهة الإدارة، لذا نفذ الأمر التالي في نافذة الطرفية لديك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_45" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

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

<p>
	شغّل الخادم مرةً أخرى:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_47" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	والآن انتقل إلى العنوان "http://localhost:8000/admin" في متصفح الويب الذي تستخدمه، وسجِّل الدخول مستعملًا اسم المستخدم وكلمة المرور اللذين أنشأتهما للتو.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111496" href="https://academy.hsoub.com/uploads/monthly_2022_11/004Django_administration.png.801b118fee2747eb3261d982fdb93fd3.png" rel=""><img alt="تسجيل الدخول في لوحة تحكم جانغو" class="ipsImage ipsImage_thumbnailed" data-fileid="111496" data-unique="xbkgmg2n3" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/004Django_administration.thumb.png.6544913943f9050817f682bcaaa0969f.png"></a>
</p>

<p>
	يمكنك إنشاء وتحرير وحذف عناصر "Todo" باستخدام هذه الواجهة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111497" href="https://academy.hsoub.com/uploads/monthly_2022_11/005Todo_Items.png.3bd6bcf501a6d87dff36e7dfc766311b.png" rel=""><img alt='التعديل على عناصر "Todo" عبر لوحة تحكم جانغو' class="ipsImage ipsImage_thumbnailed" data-fileid="111497" data-unique="yz3a895u7" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/005Todo_Items.thumb.png.a7d25c51965d9f98bc12737a0d9fdc5d.png"></a>
</p>

<p>
	بعد إجراء تجاربك على هذه الواجهة، يمكنك إيقاف الخادم باستخدام المفتاحين "CONTROL+C" أو "CTRL+C".
</p>

<h2>
	الخطوة الثانية - إعداد واجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	سننشئ هنا واجهة برمجة تطبيقات مستعينين بإطار عمل جانغو ريست، وسنثبّت لتحقيق ذلك كلًّا من <code>djangorestframework</code> و <code>django-cors-headers</code> مستخدمين <code>pipenv</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_53" style=""><span class="pln">pipenv install djangorestframework django</span><span class="pun">-</span><span class="pln">cors</span><span class="pun">-</span><span class="pln">headers</span></pre>

<p>
	يجب أن تضيف اسمي التطبيقين "rest_framework" و "corsheaders" إلى قائمة التطبيقات المثبّتة ضمن ملف الإعدادات. لذلك، افتح ملف الإعدادات "backend/settings.py" بمحرر الشيفرة، وحدّث قسمي التطبيقات المثبّتة "INSTALLED_APPS"، والبرمجيات الوسيطة "MIDDLEWARE" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_55" style=""><span class="com"># Application definition</span><span class="pln">

INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'corsheaders'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'rest_framework'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'todo'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

MIDDLEWARE </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'django.middleware.security.SecurityMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions.middleware.SessionMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.common.CommonMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.csrf.CsrfViewMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth.middleware.AuthenticationMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages.middleware.MessageMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.middleware.clickjacking.XFrameOptionsMiddleware'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'corsheaders.middleware.CorsMiddleware'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	ثم ألحق أسطر الشيفرة التالية بنهاية الملف "backend/settings.py":
</p>

<pre class="ipsCode">CORS_ORIGIN_WHITELIST = [
     'http://localhost:3000'
]
</pre>

<p>
	تُعد مكتبة "django-cors-headers" مكتبة <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> تمنع من حدوث الأخطاء التي تنتج عادةً عن استخدام بنود سياسة تعدد الموارد CORS، وهذا ما جعلك تضيف "localhost:3000" ضمن القائمة البيضاء "CORS_ORIGIN_WHITELIST"، لأنك تريد أن تمكِّن الواجهة الأمامية للتطبيق -التي تستخدم ذلك المنفذ- من التفاعل مع واجهة برمجة التطبيقات.
</p>

<h3>
	إنشاء المسلسلات serializers
</h3>

<p>
	ستحتاج للمسلسِلات لتحويل نسخ النموذج إلى محتوى من النوع <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D8%B9%D9%84%D9%85-json-r604/" rel="">JSON</a>، وذلك لكي تتمكن الواجهة الأمامية من العمل مع البيانات التي تستلمها.
</p>

<p>
	أنشئ الملف "todo/serializers.py" باستخدام محرر الشيفرة، ثم افتحه وأضف إليه أسطر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_60" style=""><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> serializers
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">TodoSerializer</span><span class="pun">(</span><span class="pln">serializers</span><span class="pun">.</span><span class="typ">ModelSerializer</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln">
        fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="str">'id'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'title'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'description'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'completed'</span><span class="pun">)</span></pre>

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

<h2>
	إنشاء العرض
</h2>

<p>
	ستحتاج إلى إنشاء الصنف <code>TodoView</code> في الملف "todo/views.py".
</p>

<p>
	افتح الملف "todo/views.py" بمحرر الشيفرة الذي تستخدمه وأضف أسطر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_62" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> viewsets
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">serializers </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">TodoSerializer</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln">

</span><span class="com"># Create your views here.</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">TodoView</span><span class="pun">(</span><span class="pln">viewsets</span><span class="pun">.</span><span class="typ">ModelViewSet</span><span class="pun">):</span><span class="pln">
    serializer_class </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TodoSerializer</span><span class="pln">
    queryset </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Todo</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">all</span><span class="pun">()</span></pre>

<p>
	يوفِّر الصنف الأساسي <code>viewsets</code> تنفيذًا لعمليات CRUD افتراضيًا. تحدد الشيفرة السابقة صنف المسلسِل <code>serializer_class</code> و مجموعة الاستعلام <code>queryset</code>.
</p>

<p>
	افتح الملف "backend/urls.py" بمحرر الشيفرة وبدّل محتوياته بالأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_64" style=""><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path</span><span class="pun">,</span><span class="pln"> include
</span><span class="kwd">from</span><span class="pln"> rest_framework </span><span class="kwd">import</span><span class="pln"> routers
</span><span class="kwd">from</span><span class="pln"> todo </span><span class="kwd">import</span><span class="pln"> views

router </span><span class="pun">=</span><span class="pln"> routers</span><span class="pun">.</span><span class="typ">DefaultRouter</span><span class="pun">()</span><span class="pln">
router</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="pln">r</span><span class="str">'todos'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="typ">TodoView</span><span class="pun">,</span><span class="pln"> </span><span class="str">'todo'</span><span class="pun">)</span><span class="pln">

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'api/'</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="pln">router</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">)),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	تحدد الشيفرة السابقة مسار محدّد الموارد الموحد <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">URL</a> لواجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>، وبهذه الخطوة نكون قد انتهينا من بناء واجهة برمجة التطبيقات.
</p>

<p>
	أصبح بإمكانك الآن إنجاز عمليات CRUD على نموذج المهام "Todo"، إذ يتيح لك صنف الموجِّه router class إجراء الاستعلامات التالية:
</p>

<ul>
	<li>
		<code>/todos/</code>: يعيد قائمةً بكافة عناصر Todo، ويمكن تنفيذ عمليتي الإنشاء CREATE والقراءة READ هنا.
	</li>
	<li>
		<code>todos/id/</code> - يعيد عنصر Todo واحدًا اعتمادًا على المفتاح الأساسي <code>id</code>، ويمكن تنفيذ عمليتي التحديث UPDATE والحذف DELETE هنا.
	</li>
</ul>

<p>
	دعنا الآن نعيد تشغيل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a>:
</p>

<pre class="ipsCode">$ python manage.py runserver
</pre>

<p>
	اذهب إلى العنوان "http://localhost:8000/api/todos" في متصفح الويب الذي تستخدمه.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111498" href="https://academy.hsoub.com/uploads/monthly_2022_11/006Todo_List.png.51fe97da95a3ad67112d5dd2b3c356fe.png" rel=""><img alt="استخدام http://localhost:8000/api/todos في متصفح الويب المستعمل" class="ipsImage ipsImage_thumbnailed" data-fileid="111498" data-unique="56npa59qz" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/006Todo_List.thumb.png.b9e009b748492a049a0107dcf6fb3c28.png"></a>
</p>

<p>
	يمكنك إنشاء عنصر مهام Todo جديد بهذه الواجهة باستخدام العملية CREATE كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111499" href="https://academy.hsoub.com/uploads/monthly_2022_11/007_New_Todo_Item.png.d03053dd681888c7a591dbadb05cbe5b.png" rel=""><img alt="007_New_Todo_Item.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111499" data-unique="p0hi5gzkk" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/007_New_Todo_Item.thumb.png.f5ca4fab1da8847cc5143e6e23ed8f22.png"></a>
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111500" href="https://academy.hsoub.com/uploads/monthly_2022_11/008_Todo_Item_Created_Succefully.png.511ce502b2ce753a729c75c3a6277fc5.png" rel=""><img alt="نتيجة إنشاء عناصر قائمة المهام Todo" class="ipsImage ipsImage_thumbnailed" data-fileid="111500" data-unique="zkhkep9jl" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/008_Todo_Item_Created_Succefully.thumb.png.f9e27e9dfc1aff4df00d52df88546bb2.png"></a>
</p>

<p>
	يمكنك أيضًا تنفيذ عمليتي الحذف DELETE والتحديث UPDATE على بعض عناصر Todo بناءً على المفاتيح الأساسية id التي تزودها. استخدم بنية العنوان "‎/api/todos/{id}‎" وحدد المفتاح الأساسي "id" الذي تريد تطبيق هذه العمليات عليه.
</p>

<p>
	أضف "1" إلى نهاية عنوان محدد الموارد الموحد URL لمعرفة عنصر Todo الذي يحمل مفتاحه الأساسي القيمة "1"، ثم انتقل إلى "http://localhost:8000/api/todos/1" في متصفح الويب الذي تستخدمه. تبين الشاشة التالية النتيجة التي حصلنا عليها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111501" href="https://academy.hsoub.com/uploads/monthly_2022_11/009_Todo_Instance.png.52009a74f3b19c88c40a4dca7b7581f4.png" rel=""><img alt="009_Todo_Instance.png" class="ipsImage ipsImage_thumbnailed" data-fileid="111501" data-unique="982y81oqj" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/009_Todo_Instance.thumb.png.124fcec2357ec6333decad440b3f3511.png"></a>
</p>

<p>
	إذا ظهرت لك هذه الشاشة فذلك يعني أنك انتهيت من بناء الواجهة الخلفية للتطبيق.
</p>

<h2>
	الخطوة الثالثة - إعداد الواجهة الأمامية
</h2>

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

<p>
	افتح نافذة طرفية واذهب إلى مجلد المشروع "django-todo-react".
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_73" style=""><span class="pln">$ npx create</span><span class="pun">-</span><span class="pln">react</span><span class="pun">-</span><span class="pln">app frontend</span></pre>

<p>
	وللاطلاع أكثر على هذه الطريقة يرجى مراجعة <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-react-r1569/" rel="">بدء العمل مع مكتبة ريآكت</a>.
</p>

<p>
	يمكنك الآن بعد أن أنشأت المشروع الانتقال إلى المجلد الذي أنشأته للتو "frontend":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_75" style=""><span class="pln">$ cd frontend</span></pre>

<p>
	الآن، شغّل التطبيق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_78" style=""><span class="pln">$ npm start</span></pre>

<p>
	سيفتح متصفحك الرابط "http://localhost:3000" وستظهر لك الشاشة الابتدائية لتطبيق "Create React".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111502" href="https://academy.hsoub.com/uploads/monthly_2022_11/010_default_Create_React_App_screen.png.20672b814473696ba1166735f462a1c7.png" rel=""><img alt='الشاشة الابتدائية لتطبيق "Create React"' class="ipsImage ipsImage_thumbnailed" data-fileid="111502" data-unique="mema31e2p" style="width: 650px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/010_default_Create_React_App_screen.thumb.png.9c02e56768a0dfa93ccc99aa6f611997.png"></a>
</p>

<p>
	ثم ثبّت بوتستراب bootstrap وريآكتستراب reactstrap لتصبح أدوات <a href="https://academy.hsoub.com/design/user-interface/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-ui-r652/" rel="">واجهة المستخدم</a> في حوزتك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_82" style=""><span class="pln">$ npm install bootstrap@4</span><span class="pun">.</span><span class="lit">6.0</span><span class="pln"> reactstrap@8</span><span class="pun">.</span><span class="lit">9.0</span><span class="pln"> </span><span class="pun">--</span><span class="pln">legacy</span><span class="pun">-</span><span class="pln">peer</span><span class="pun">-</span><span class="pln">deps</span></pre>

<p>
	<strong>ملاحظة</strong>: ربما تتلقى رسائل خطأ مثل "unable to resolve dependency tree" بحسب إصدارات كل من ريآكت وبوتستراب وريآكتستراب.
</p>

<p>
	أصبحت النسخة الأحدث للملف "popper.js" في لحظة كتابة هذه المقالة مهملة وتتعارض مع الإصدار 17 وما بعده من ريآكت، وهذه <a href="https://github.com/reactstrap/reactstrap/issues/2045" rel="external nofollow">مشكلة معروفة</a>، ويمكن استخدام الخيار <code>legacy-peer-deps--</code> عند التثبيت.
</p>

<p>
	افتح الملف "index.js" في محرر الشيفرة الذي تستخدمه وأضف <code>bootstrap.min.css</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3950_86" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'bootstrap/dist/css/bootstrap.css'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'./index.css'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> reportWebVitals from </span><span class="str">'./reportWebVitals'</span><span class="pun">;</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">React</span><span class="pun">.</span><span class="typ">StrictMode</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">React</span><span class="pun">.</span><span class="typ">StrictMode</span><span class="pun">&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span><span class="pln">

</span><span class="com">// If you want to start measuring performance in your app, pass a function</span><span class="pln">
</span><span class="com">// to log results (for example: reportWebVitals(console.log))</span><span class="pln">
</span><span class="com">// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals</span><span class="pln">
reportWebVitals</span><span class="pun">();</span></pre>

<p>
	إذا واجهت أي صعوبة أثناء هذه الخطوة، فننصحك بالاستعانة <a href="https://create-react-app.dev/docs/adding-bootstrap/" rel="external nofollow">بموقع التوثيق الرسمي لإضافة بوتستراب</a>.
</p>

<p>
	افتح الملف "App.js" بمحرر الشيفرة وأضف أسطر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3950_88" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> todoItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Go to Market"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Buy ingredients to prepare dinner"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Study"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Read Algebra and History textbook for the upcoming test"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy's books"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Go to library to return Sammy's books"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Article"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Write article on how to use Django with React"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      todoList</span><span class="pun">:</span><span class="pln"> todoItems</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  displayCompleted </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderTabList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"nav nav-tabs"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          className</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pun">}</span><span class="pln">
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Complete</span><span class="pln">
        </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
          className</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pun">}</span><span class="pln">
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Incomplete</span><span class="pln">
        </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">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> viewCompleted </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newItems </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">todoList</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
      </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">==</span><span class="pln"> viewCompleted
    </span><span class="pun">);</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> newItems</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li
        key</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
        className</span><span class="pun">=</span><span class="str">"list-group-item d-flex justify-content-between align-items-center"</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          className</span><span class="pun">={`</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">title mr</span><span class="pun">-</span><span class="lit">2</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"completed-todo"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
          </span><span class="pun">}`}</span><span class="pln">
          title</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">description</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">item</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}</span><span class="pln">
        </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</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-secondary mr-2"</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Edit</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-danger"</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Delete</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </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">li</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">main className</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">h1 className</span><span class="pun">=</span><span class="str">"text-white text-uppercase text-center my-4"</span><span class="pun">&gt;</span><span class="typ">Todo</span><span class="pln"> app</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"row"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"col-md-6 col-sm-10 mx-auto p-0"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"card p-3"</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"mb-4"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">button
                  className</span><span class="pun">=</span><span class="str">"btn btn-primary"</span><span class="pln">
                </span><span class="pun">&gt;</span><span class="pln">
                  </span><span class="typ">Add</span><span class="pln"> task
                </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderTabList</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">ul className</span><span class="pun">=</span><span class="str">"list-group list-group-flush border-top-0"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderItems</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">main</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span><span class="pun">;</span></pre>

<p>
	تحتوي هذه الشيفرة على بعض المتوفرة مسبقًا hardcoded لأربعة عناصر، وستبقى هذه القيم إلى حين إحضار العناصر من الواجهة الخلفية.
</p>

<p>
	تعرض الدالة <code>()renderTabList</code> امتدادين spans يظهِر كل منهما عند الضغط عليه مجموعةً من المهام، إذ يظهر الضغط على الامتداد Completed المهام المكتملة، ويظهر الامتداد Incomplete المهام غير المكتملة في المقابل.
</p>

<p>
	احفظ الآن التغييرات التي أجريتها وتأمل النتيجة في متصفحك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111503" href="https://academy.hsoub.com/uploads/monthly_2022_11/011_Todo_Adding_A-Task.png.c2b7fa7119dc97b48e5a5efa7694deb2.png" rel=""><img alt="نتيجة العمل على تطبيق to do" class="ipsImage ipsImage_thumbnailed" data-fileid="111503" data-unique="z0bo2xkdd" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/011_Todo_Adding_A-Task.thumb.png.c07c07a28b409c347c2efb609fde3bff.png"></a>
</p>

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

<p>
	أولًا، أنشئ مجلد المكوّنات "components" داخل المجلد "src":
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_93" style=""><span class="pln">$ mkdir src</span><span class="pun">/</span><span class="pln">components</span></pre>

<p>
	ثم أنشئ الملف "Modal.js" وافتحه بمحرر الشيفرة وأضف إليه الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_95" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Button</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Modal</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">ModalHeader</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">ModalBody</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">ModalFooter</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Form</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">FormGroup</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Input</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Label</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">"reactstrap"</span><span class="pun">;</span><span class="pln">

export default </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">CustomModal</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      activeItem</span><span class="pun">:</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  handleChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> value </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">"checkbox"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value </span><span class="pun">=</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">checked</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    const activeItem </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">name</span><span class="pun">]:</span><span class="pln"> value </span><span class="pun">};</span><span class="pln">

    this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> activeItem </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    const </span><span class="pun">{</span><span class="pln"> toggle</span><span class="pun">,</span><span class="pln"> onSave </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">props</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Modal</span><span class="pln"> isOpen</span><span class="pun">={</span><span class="pln">true</span><span class="pun">}</span><span class="pln"> toggle</span><span class="pun">={</span><span class="pln">toggle</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">ModalHeader</span><span class="pln"> toggle</span><span class="pun">={</span><span class="pln">toggle</span><span class="pun">}&gt;</span><span class="typ">Todo</span><span class="pln"> </span><span class="typ">Item</span><span class="pun">&lt;/</span><span class="typ">ModalHeader</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">ModalBody</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">FormGroup</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Label</span><span class="pln"> </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"todo-title"</span><span class="pun">&gt;</span><span class="typ">Title</span><span class="pun">&lt;/</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Input</span><span class="pln">
                type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
                id</span><span class="pun">=</span><span class="str">"todo-title"</span><span class="pln">
                name</span><span class="pun">=</span><span class="str">"title"</span><span class="pln">
                value</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}</span><span class="pln">
                onChange</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
                placeholder</span><span class="pun">=</span><span class="str">"Enter Todo Title"</span><span class="pln">
              </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="typ">FormGroup</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">FormGroup</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Label</span><span class="pln"> </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"todo-description"</span><span class="pun">&gt;</span><span class="typ">Description</span><span class="pun">&lt;/</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Input</span><span class="pln">
                type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
                id</span><span class="pun">=</span><span class="str">"todo-description"</span><span class="pln">
                name</span><span class="pun">=</span><span class="str">"description"</span><span class="pln">
                value</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">.</span><span class="pln">description</span><span class="pun">}</span><span class="pln">
                onChange</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
                placeholder</span><span class="pun">=</span><span class="str">"Enter Todo description"</span><span class="pln">
              </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="typ">FormGroup</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">FormGroup</span><span class="pln"> check</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Label</span><span class="pln"> check</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="typ">Input</span><span class="pln">
                  type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln">
                  name</span><span class="pun">=</span><span class="str">"completed"</span><span class="pln">
                  checked</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">.</span><span class="pln">completed</span><span class="pun">}</span><span class="pln">
                  onChange</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
                </span><span class="pun">/&gt;</span><span class="pln">
                </span><span class="typ">Completed</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="typ">FormGroup</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">ModalBody</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">ModalFooter</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln">
            color</span><span class="pun">=</span><span class="str">"success"</span><span class="pln">
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> onSave</span><span class="pun">(</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Save</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">ModalFooter</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Modal</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تنشئ الشيفرة السابقة الصنف <code>CustomModal</code> وهو يتداخل مع المكون <code>Modal</code> المشتق من المكتبة <code>reactstrap</code>.
</p>

<p>
	وقد عرَّفت هذه الشيفرة أيضًا ثلاثة حقول ضمن نموذج التعبئة form هي:
</p>

<ul>
	<li>
		<code>title</code>
	</li>
	<li>
		<code>description</code>
	</li>
	<li>
		<code>completed</code>
	</li>
</ul>

<p>
	هذه الحقول هي نفسها التي عرفناها مثل خصائص في نموذج قائمة المهام "Todo" عند إعداد الواجهة الخلفية.
</p>

<p>
	يستقبل <code>CustomModal</code> القيم <code>activeItem</code> و <code>toggle</code> و <code>onSave</code> مثل خاصيّات، بحيث يمثِّل:
</p>

<ul>
	<li>
		<code>activeItem</code> عنصر قائمة المهام الذي سيُحرّر.
	</li>
	<li>
		<code>toggle</code> الدالة التي ستُستخدم للتحكم في حالة المكون <code>Modal</code>، أي فتحه أو غلقه.
	</li>
	<li>
		<code>onSave</code> دالةً تُستدعى لحفظ القيم التي حرِّرت لعنصر قائمة المهام.
	</li>
</ul>

<p>
	الآن، سنستورد المكون <code>CustomModal</code> إلى داخل الملف "App.js".
</p>

<p>
	عد إلى الملف "src/App.js" وافتحه بمحرر الشيفرة واستبدل محتوياته بأسطر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3950_99" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Modal</span><span class="pln"> from </span><span class="str">"./components/Modal"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> todoItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Go to Market"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Buy ingredients to prepare dinner"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Study"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Read Algebra and History textbook for the upcoming test"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Sammy's books"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Go to library to return Sammy's books"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Article"</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Write article on how to use Django with React"</span><span class="pun">,</span><span class="pln">
    completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      todoList</span><span class="pun">:</span><span class="pln"> todoItems</span><span class="pun">,</span><span class="pln">
      modal</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      activeItem</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        title</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        description</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</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">

  toggle </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  handleSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">();</span><span class="pln">

    alert</span><span class="pun">(</span><span class="str">"save"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">item</span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  handleDelete </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    alert</span><span class="pun">(</span><span class="str">"delete"</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">item</span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  createItem </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> item </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> description</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> activeItem</span><span class="pun">:</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  editItem </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> activeItem</span><span class="pun">:</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  displayCompleted </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderTabList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"nav nav-tabs"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          className</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pun">}</span><span class="pln">
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Complete</span><span class="pln">
        </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
          className</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pun">}</span><span class="pln">
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Incomplete</span><span class="pln">
        </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">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> viewCompleted </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newItems </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">todoList</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
      </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">===</span><span class="pln"> viewCompleted
    </span><span class="pun">);</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> newItems</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li
        key</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
        className</span><span class="pun">=</span><span class="str">"list-group-item d-flex justify-content-between align-items-center"</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          className</span><span class="pun">={`</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">title mr</span><span class="pun">-</span><span class="lit">2</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"completed-todo"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
          </span><span class="pun">}`}</span><span class="pln">
          title</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">description</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">item</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}</span><span class="pln">
        </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</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-secondary mr-2"</span><span class="pln">
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">editItem</span><span class="pun">(</span><span class="pln">item</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Edit</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-danger"</span><span class="pln">
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleDelete</span><span class="pun">(</span><span class="pln">item</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Delete</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </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">li</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">main className</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">h1 className</span><span class="pun">=</span><span class="str">"text-white text-uppercase text-center my-4"</span><span class="pun">&gt;</span><span class="typ">Todo</span><span class="pln"> app</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"row"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"col-md-6 col-sm-10 mx-auto p-0"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"card p-3"</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"mb-4"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">button
                  className</span><span class="pun">=</span><span class="str">"btn btn-primary"</span><span class="pln">
                  onClick</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">createItem</span><span class="pun">}</span><span class="pln">
                </span><span class="pun">&gt;</span><span class="pln">
                  </span><span class="typ">Add</span><span class="pln"> task
                </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderTabList</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">ul className</span><span class="pun">=</span><span class="str">"list-group list-group-flush border-top-0"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">renderItems</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Modal</span><span class="pln">
            activeItem</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">}</span><span class="pln">
            toggle</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">}</span><span class="pln">
            onSave</span><span class="pun">={</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">main</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span><span class="pun">;</span></pre>

<p>
	احفظ التغييرات وتأمل ما حصل للتطبيق في متصفحك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="111504" href="https://academy.hsoub.com/uploads/monthly_2022_11/012_Todo_Item_Name_And_Description.png.0ddd23b996ab23d9ad7d5d0aa9bcfa59.png" rel=""><img alt="نتائج حفظ التعديلات على واجهة الموقع" class="ipsImage ipsImage_thumbnailed" data-fileid="111504" data-unique="nk3x1z48i" style="width: 800px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/012_Todo_Item_Name_And_Description.thumb.png.b29ffb8782fcf09bb6986f504a6d8f66.png"></a>
</p>

<p>
	إذا حاولت تحرير وحفظ عنصر من عناصر قائمة المهام Todo، سيظهر لك تنبيه يُظهِرُ الكائن المرتبط بعنصر المهام Todo. سيؤدي النقر على حفظ Save أو حذف Delete إلى تنفيذ الفعل المقابل على هذا العنصر.
</p>

<p>
	<strong>ملاحظة</strong>: قد تواجه أخطاءً في واجهة الطرفية وذلك بحسب نسختي ريآكت وريآكتستراب اللتين تستخدمهما، وأثناء عمل هذه المراجعة، كان الخطآن التاليان من بين <a href="https://github.com/reactstrap/reactstrap/issues/1340" rel="external nofollow">الأخطاء الشائعة في ريآكتستراب</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3950_106" style=""><span class="typ">Warning</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Legacy</span><span class="pln"> context <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> has been detected within a strict</span><span class="pun">-</span><span class="pln">mode tree
</span><span class="typ">Warning</span><span class="pun">:</span><span class="pln"> findDOMNode is deprecated in </span><span class="typ">StrictMode</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_108" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	<strong>ملاحظة</strong>: إذا كنت قد أغلقت نافذة الطرفية هذه، تذكر أنك ستحتاج للذهاب إلى المجلد "backend" واستخدام صدفة Pipenv الافتراضية.
</p>

<p>
	لإنشاء طلبات توجه إلى نقاط النهاية لواجهة برمجة التطبيقات في خادم الواجهة الخلفية، سنثبّت واحدةً من مكتبات جافا سكريبت المهمة وهي مكتبة "axios".
</p>

<p>
	في نافذة الطرفية الثانية، تأكد أنك موجود داخل المجلد "frontend"، ثم ثبّت مكتبة <code>axios</code>:
</p>

<pre class="ipsCode">$ npm install axios@0.21.1
</pre>

<p>
	ثم افتح الملف "frontend/package.json" بمحرر الشيفرة وأضف خادمًا وسيطًا proxy كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_110" style=""><span class="pun">[...]</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"frontend"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"0.1.0"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"private"</span><span class="pun">:</span><span class="pln"> true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"proxy"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"http://localhost:8000"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"dependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"axios"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^0.18.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"bootstrap"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^4.1.3"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.5.2"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-dom"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.5.2"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2.0.5"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"reactstrap"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^6.5.0"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">[...]</span></pre>

<p>
	تتركز مهمة الخادم الوسيط في المساعدة في إنشاء نفق tunneling لطلبات واجهة برمجة التطبيقات إلى شبكة أخرى وإرسالها إلى العنوان "http://localhost:8000"، ليستلمها تطبيق جانغو هناك ويعالجها، وبدون هذا الخادم الوسيط، ستضطر إلى تحديد المسارات الكاملة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_113" style=""><span class="pln">axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">"http://localhost:8000/api/todos/"</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_115" style=""><span class="pln">axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">"/api/todos/"</span><span class="pun">)</span></pre>

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

<p>
	عد إلى الملف "frontend/src/App.js" وافتحه بمحرر الشيفرة، إذ ستحذف في هذه الخطوة عناصر قائمة المهام todoItems ذات القيم الموفرة hardcoded وتستخدم البيانات من الطلبات الموجهة إلى خادم الواجهة الخلفية مستخدمًا <code>handleSubmit</code> و <code>handleDelete</code>.
</p>

<p>
	افتح الملف App.js واستبدل محتوياته بالنسخة النهائية التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_117" style=""><span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Modal</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> </span><span class="str">"./components/Modal"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> axios </span><span class="kwd">from</span><span class="pln"> </span><span class="str">"axios"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> extends </span><span class="typ">Component</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    super</span><span class="pun">(</span><span class="pln">props</span><span class="pun">);</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      viewCompleted</span><span class="pun">:</span><span class="pln"> false</span><span class="pun">,</span><span class="pln">
      todoList</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
      modal</span><span class="pun">:</span><span class="pln"> false</span><span class="pun">,</span><span class="pln">
      activeItem</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        title</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        description</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        completed</span><span class="pun">:</span><span class="pln"> false</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">

  componentDidMount</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">refreshList</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  refreshList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    axios
      </span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="str">"/api/todos/"</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> todoList</span><span class="pun">:</span><span class="pln"> res</span><span class="pun">.</span><span class="pln">data </span><span class="pun">}))</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">catch</span><span class="pun">((</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</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">

  toggle </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  handleSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      axios
        </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">todos</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}/`,</span><span class="pln"> item</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">refreshList</span><span class="pun">());</span><span class="pln">
      </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    axios
      </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">"/api/todos/"</span><span class="pun">,</span><span class="pln"> item</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">refreshList</span><span class="pun">());</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  handleDelete </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    axios
      </span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(`/</span><span class="pln">api</span><span class="pun">/</span><span class="pln">todos</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}/`)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">refreshList</span><span class="pun">());</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  createItem </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    const item </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> description</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln"> completed</span><span class="pun">:</span><span class="pln"> false </span><span class="pun">};</span><span class="pln">

    this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> activeItem</span><span class="pun">:</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  editItem </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> activeItem</span><span class="pun">:</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> modal</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  displayCompleted </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">status</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> true </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">setState</span><span class="pun">({</span><span class="pln"> viewCompleted</span><span class="pun">:</span><span class="pln"> false </span><span class="pun">});</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderTabList </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"nav nav-tabs"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="pln">true</span><span class="pun">)}</span><span class="pln">
          className</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Complete</span><span class="pln">
        </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
          onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">displayCompleted</span><span class="pun">(</span><span class="pln">false</span><span class="pun">)}</span><span class="pln">
          className</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"nav-link"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"nav-link active"</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="typ">Incomplete</span><span class="pln">
        </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">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  renderItems </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    const </span><span class="pun">{</span><span class="pln"> viewCompleted </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">;</span><span class="pln">
    const newItems </span><span class="pun">=</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">todoList</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">
      </span><span class="pun">(</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">completed </span><span class="pun">===</span><span class="pln"> viewCompleted
    </span><span class="pun">);</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> newItems</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">item</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">li
        key</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
        className</span><span class="pun">=</span><span class="str">"list-group-item d-flex justify-content-between align-items-center"</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span
          className</span><span class="pun">={`</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">title mr</span><span class="pun">-</span><span class="lit">2</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">
            this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">viewCompleted </span><span class="pun">?</span><span class="pln"> </span><span class="str">"completed-todo"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
          </span><span class="pun">}`}</span><span class="pln">
          title</span><span class="pun">={</span><span class="pln">item</span><span class="pun">.</span><span class="pln">description</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">item</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}</span><span class="pln">
        </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</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-secondary mr-2"</span><span class="pln">
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">editItem</span><span class="pun">(</span><span class="pln">item</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Edit</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button
            className</span><span class="pun">=</span><span class="str">"btn btn-danger"</span><span class="pln">
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> this</span><span class="pun">.</span><span class="pln">handleDelete</span><span class="pun">(</span><span class="pln">item</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="typ">Delete</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </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">li</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">));</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">

  render</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">main className</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">h1 className</span><span class="pun">=</span><span class="str">"text-white text-uppercase text-center my-4"</span><span class="pun">&gt;</span><span class="typ">Todo</span><span class="pln"> app</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"row"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"col-md-6 col-sm-10 mx-auto p-0"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"card p-3"</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"mb-4"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">button
                  className</span><span class="pun">=</span><span class="str">"btn btn-primary"</span><span class="pln">
                  onClick</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">createItem</span><span class="pun">}</span><span class="pln">
                </span><span class="pun">&gt;</span><span class="pln">
                  </span><span class="typ">Add</span><span class="pln"> task
                </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">{</span><span class="pln">this</span><span class="pun">.</span><span class="pln">renderTabList</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="pln">ul className</span><span class="pun">=</span><span class="str">"list-group list-group-flush border-top-0"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{</span><span class="pln">this</span><span class="pun">.</span><span class="pln">renderItems</span><span class="pun">()}</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">modal </span><span class="pun">?</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Modal</span><span class="pln">
            activeItem</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">state</span><span class="pun">.</span><span class="pln">activeItem</span><span class="pun">}</span><span class="pln">
            toggle</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">toggle</span><span class="pun">}</span><span class="pln">
            onSave</span><span class="pun">={</span><span class="pln">this</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> null</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">main</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

export default </span><span class="typ">App</span><span class="pun">;</span></pre>

<p>
	الدالة <code>()refreshList</code> معدّةٌ ليُعاد استخدامها المرة تلو المرة، وتُستدعى بعد كل مرة يكتمل فيها طلب واجهة برمجة تطبيقات، ومهمتها تحديث قائمة المهام لتعرِض دومًا أحدث حالة لها؛ أما الدالة <code>()handleSubmit</code> فهي مسؤولة عن عمليتي الإنشاء والتحديث، فإذا لم يمتلك العنصر الممرّر مثل معامل parameter مفتاحًا أساسيًّا، فالأرجح عندها أنه لم يُنشأ، لذا يتولى مهمة إنشائه.
</p>

<p>
	تأكد الآن من أن خادم الواجهة الخلفية لديك يعمل في أول نافذة طرفية استخدمتها.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_121" style=""><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver</span></pre>

<p>
	<strong>ملاحظة</strong>: إذا أغلقت نافذة الطرفية هذه، فستحتاج للذهاب إلى المجلد "backend" واستخدام صدفة Pipenv الافتراضية.
</p>

<p>
	وتأكد في نافذة الطرفية الثانية أنك في مجلد الواجهة الأمامية "frontend" وشغّل تطبيق الواجهة الأمامية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3950_123" style=""><span class="pln">$ npm start</span></pre>

<p>
	الآن عندما تذهب في متصفحك إلى العنوان "http://localhost:3000"، سيسمح لك التطبيق بإنشاء المهام وقراءتها وتعديلها وحذفها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="gif" data-fileid="111505" href="https://academy.hsoub.com/uploads/monthly_2022_11/013_Final_Todo_APplication.gif.0c1ba529a9e84c6a8ce557cd70e84e3e.gif" rel=""><img alt="إنشاء المهام وقراءتها وتحليلها" class="ipsImage ipsImage_thumbnailed" data-fileid="111505" data-unique="9qzlgy0hy" style="width: 650px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_11/013_Final_Todo_APplication.thumb.gif.68629b70e8b9dc15de3be4ef5ed1bb48.gif"></a>
</p>

<p>
	وبهذا تكتمل الواجهة الأمامية والواجهة الخلفية لتطبيق المهام.
</p>

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

<p>
	بنينا في هذه المقالة تطبيق مهام باستخدام جانغو وريآكت، وقد حققنا هذا بالاستعانة بالمكتبات: djangorestframework و django-cors-headers و axios و bootstrap و reactstrap.
</p>

<p>
	إذا أردت تعلم المزيد عن جانغو ننصحك بمراجعة <a href="https://academy.hsoub.com/programming/python/django/" rel="">صفحة مواضيع جانغو في أكاديمية حسوب</a>.
</p>

<p>
	وإذا أردت تعلم المزيد عن ريآكت ننصحك بزيارة <a href="https://wiki.hsoub.com/React" rel="external">دلبل ريآكت في موسوعة حسوب</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقالة <a href="https://www.digitalocean.com/community/tutorials/build-a-to-do-application-using-django-and-react" rel="external nofollow">How To Build a To-Do application Using Django and React</a> لصاحبها Jordan Irabor.
</p>

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/react/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-react-r1570/" rel="">إنشاء تطبيق قائمة مهام باستخدام React</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1773</guid><pubDate>Sun, 06 Nov 2022 16:08:00 +0000</pubDate></item><item><title>&#x631;&#x641;&#x639; &#x645;&#x633;&#x62A;&#x648;&#x649; &#x623;&#x645;&#x627;&#x646; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x641;&#x64A; &#x628;&#x64A;&#x626;&#x629; &#x627;&#x644;&#x625;&#x646;&#x62A;&#x627;&#x62C;</title><link>https://academy.hsoub.com/programming/python/django/%D8%B1%D9%81%D8%B9-%D9%85%D8%B3%D8%AA%D9%88%D9%89-%D8%A3%D9%85%D8%A7%D9%86-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%81%D9%8A-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%A7%D8%AC-r1717/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_09/632d8beb2c28b_-------.jpg.1e82a8f6a7f49cbce83998bab8edfa71.jpg" /></p>

<p>
	يتميز تطوير التطبيقات باستخدام <a href="https://academy.hsoub.com/programming/python/django/" rel="">جانغو Django</a> بالمرونة والسرعة، ويعدّ تجربةً جيدة للمطوّر، فتطبيق جانغو قابل للتطوير والتكيف مع المتغيرات بالإضافة إلى أنه يؤمن مجموعة متنوعة من إعدادات الأمان الأساسية التي تُسهل تحضير التطبيق لمرحلة الإنتاج ما بعد نشر التطبيق، إلّا أن إطلاقه للعلن وعمله الفعلي في بيئة الإنتاج يتطلب عوامل أمان أقوى، وله عدة طرق منها إعادة ترتيب ملفات إعدادات التطبيق وتجزئتها بناءً على تبعيتها لمتغيرات البيئة ما يسمح بإعادة ضبطها بسهولة، وأيضًا الاستفادة من <code>dotenv</code> لإخفاء الإعدادات السرية وضمان عدم تسريب أي تفاصيل قد تعرض مشروعك للخطر.
</p>

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

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

<h2>
	متطلبات بيئة العمل
</h2>

<p>
	ستحتاج المتطلبات التالية لتتمكن من التطبيق العملي للمقال:
</p>

<ol>
<li>
		نسخة جاهزة من أي تطبيق جانغو، إن لم تتوفر لديك يمكنك إعدادها بإتباع خطوات المقال <a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django-%D9%88%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%AA%D9%87-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-ubuntu-1604-r643/" rel="">تثبيت إطار العمل Django وتهيئة بيئته البرمجية على Ubuntu</a>، إذ استُعمل هنا التطبيق <code>testsite</code> المطوّر بموجبه.
	</li>
	<li>
		معرفة ببنية ملفات جانغو وإعداداته الأساسية، وننصحك بقراءة سلسلة <a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">بناء مدونة عبر جانغو</a>.
	</li>
</ol>
<p>
	<strong>تنويه</strong>: تم تنظيم هذا المقال وعرضه بطريقة تلائم متطلبات التطبيق <code>testsite</code> فإن كنت تستخدم تطبيقًا آخر ستلاحظ بعض الاختلاف لكن لا بأس يمكنك تنفيذ الفقرات على حدة بما يناسب تطبيقك.
</p>

<h2>
	الخطوة 1: إعادة هيكلة إعدادات جانغو
</h2>

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

<p>
	أنشئ مجلدًا جديدًا باسم settings ضمن المجلد الأب لمشروعك كمايلي:
</p>

<pre class="ipsCode">
mkdir testsite/testsite/settings
</pre>

<p>
	الاسم testsite هو اسم التطبيق كما ذكرنا في فقرة متطلبات بيئة العمل، أنشئ بعدها ثلاث ملفات بايثون ضمن المجلد settings كما يلي إذ ستحلّ هذه الملفات المنفصلة بدلًا من الملف setting.py:
</p>

<pre class="ipsCode">
cd testsite/testsite/settings
touch base.py development.py production.py
</pre>

<p>
	تمامًا كما توحي الأسماء فالملف development.py سيتضمن الإعدادات التي ستحتاج إليها في أثناء التطوير، بينما سيحوي الملف production.py الإعدادات اللازمة لمرحلة الإنتاج وقد فصلنا إعدادات المرحلتين عن بعضهما بسبب اختلاف المتطلبات بينهما، فإعدادات مرحلة الإنتاج مثل توجيه الطلبات إلى HTTPS أو إضافة الترويسات أو استخدام قاعدة بيانات الإنتاج لن تنفع خلال مرحلة التطوير، أما الملف base.py فسيشمل الإعدادات المشتركة الأساسية التي سيرثها كلًا من development.py و production.py فهذ العملية ستساهم في عدم تكرار الإعدادات وتصميم كود نظيف لتطبيقك.
</p>

<p>
	طالما أن الملفات الثلاثة ستحمل كامل الإعدادات المطلوبة فلنزيل إذًا setting.py لضمان عمل جانغو بشكلٍ سليم.
</p>

<p>
	ضمن نفس المجلد settings نفذ الأمر التالي المتضمن تعديل اسم setting.py ليصبح base.py:
</p>

<pre class="ipsCode">
mv ../settings.py base.py
</pre>

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

<h2>
	الخطوة 2: استخدام python-dotenv
</h2>

<p>
	الحزمة <code>python-dotenv</code> هي إحدى اعتماديات التطبيق، مهمتها تحميل متغيرات البيئة من ملف خاص يدعى <code>env.</code>، وتثبيتها ضروري ليتمكن التطبيق من التعامل مع مجلد الإعدادات والملفات الجديدة التي عملنا عليها في الخطوة السابقة. لنبدأ التطبيق العملي:
</p>

<p>
	توجه إلى مسار الجذر لمشروعك:
</p>

<pre class="ipsCode">
cd ../../
</pre>

<p>
	وثبت الاعتمادية <code>python-dotenv</code>:
</p>

<pre class="ipsCode">
pip install python-dotenv
</pre>

<p>
	ومن ثم اضبط إعدادات جانغو ليستخدم <code>dotenv</code> عبر تعديل الملفين manage.py الخاص ببيئة التطوير و wsgi.py الخاص ببيئة الانتاج كما يلي:
</p>

<p>
	افتح أولًا الملف manage.py باستعمال محرر النصوص:
</p>

<pre class="ipsCode">
nano manage.py
</pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_7" style="">
<span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">import</span><span class="pln"> sys
</span><span class="kwd">import</span><span class="pln"> dotenv

</span><span class="kwd">def</span><span class="pln"> main</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="pln">setdefault</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'testsite.settings.development'</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">getenv</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</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">'DJANGO_SETTINGS_MODULE'</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">getenv</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">management </span><span class="kwd">import</span><span class="pln"> execute_from_command_line
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">ImportError</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> exc</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">ImportError</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"Couldn't import Django. Are you sure it's installed and "</span><span class="pln">
            </span><span class="str">"available on your PYTHONPATH environment variable? Did you "</span><span class="pln">
            </span><span class="str">"forget to activate a virtual environment?"</span><span class="pln">
        </span><span class="pun">)</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> exc
    execute_from_command_line</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</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">
    main</span><span class="pun">()</span><span class="pln">

dotenv</span><span class="pun">.</span><span class="pln">load_dotenv</span><span class="pun">(</span><span class="pln">
    os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">__file__</span><span class="pun">),</span><span class="pln"> </span><span class="str">'.env'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	ثم أغلق الملف بعد حفظ التغييرات، وافتح الثاني:
</p>

<pre class="ipsCode">
nano testsite/wsgi.py
</pre>

<p>
	وأضف ضمنه التعليمات الناقصة المتعلقة بـ <code>dotenv</code> ليصبح بهذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_9" style="">
<span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">import</span><span class="pln"> dotenv

</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">wsgi </span><span class="kwd">import</span><span class="pln"> get_wsgi_application

dotenv</span><span class="pun">.</span><span class="pln">load_dotenv</span><span class="pun">(</span><span class="pln">
    os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">dirname</span><span class="pun">(</span><span class="pln">__file__</span><span class="pun">)),</span><span class="pln"> </span><span class="str">'.env'</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="pln">setdefault</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'testsite.settings.development'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">getenv</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</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">'DJANGO_SETTINGS_MODULE'</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">getenv</span><span class="pun">(</span><span class="str">'DJANGO_SETTINGS_MODULE'</span><span class="pun">)</span><span class="pln">

application </span><span class="pun">=</span><span class="pln"> get_wsgi_application</span><span class="pun">()</span></pre>

<p>
	لا تنسَ حفظ التغييرات قبل إغلاق الملف.
</p>

<p>
	بموجب التعديلات التي أجريتها على الملفين: عند كل تشغيل لهما manage.py في التطوير والملف wsgi.py في الإنتاج، سيبحث جانغو عن الملف <code>env.</code> فإن وجده سيستخدم ملف الإعدادات الذي يوصي به <code>env.</code> وفي حال لم يجده يعتمد إعدادات التطوير افتراضيًا.
</p>

<p>
	لننشئ الآن الملف <code>env.</code> ضمن مجلد المشروع كما يلي:
</p>

<pre class="ipsCode">
nano .env
</pre>

<p>
	ونضيف ضمنه السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_11" style="">
<span class="pln">DJANGO_SETTINGS_MODULE</span><span class="pun">=</span><span class="str">"testsite.settings.development"</span></pre>

<p>
	<strong>تنويه</strong>: ننصحك بإضافة <code>env.</code> على قائمة العناصر الموجودة في الملف <code>gitingore.</code> لتُحافظ عليه وتحميه من التعديل فهو في نهاية المطاف يتضمن كلمات المرور وإعدادات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> وغيرها من المعلومات الحساسة المتعلقة بالتطبيق، وعندها ستنشئ ملف <code>env.</code> خاص بكل بيئة تنشر تطبيقك فيها، ولذا نوصيك بإنشاء نموذج ملف جاهز باسم <code>env.example.</code> ضمن مشروعك يمكنك تعديله بسهولة ليشكل <code>env.</code> جديد كلما دعت الحاجة.
</p>

<p>
	بناءً على السطر الذي أضفناه للملف <code>env.</code>، سيستخدم جانغو افتراضيًا <code>testsite.settings.development</code> وبالمثل إن غيرت قيمة المحدد <code>DJANGO_SETTINGS_MODULE</code> إلى <code>testsite.settings.production</code> فإنه سيبدأ باستخدام إعدادات بيئة الإنتاج.
</p>

<h2>
	الخطوة 3: إنشاء ملفات الإعدادات لكل من بيئتي التطوير والإنتاج
</h2>

<p>
	افتح الملف base.py وأضف ضمنه إعدادات التهيئة الخاصة بكل بيئة والتي ستعدلها لاحقًا في ملفي development.py و production.py المنفصلين، وتأكد أنك تملك معلومات الاتصال بقاعدة بيانات الإنتاج إذ ستحتاجها في الملف production.py.
</p>

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

<p>
	لنبدأ بنقل الإعدادات من base.py إلى ملف إعدادات التطوير development.py الخاص بتطبيقنا testsite، لذا افتح ملف إعدادات التطوير:
</p>

<pre class="ipsCode">
nano testsite/settings/development.py
</pre>

<p>
	واكتب ضمنه تعليمة الاستيراد من base.py ومن بعدها الإعدادات الخاصة ببيئة التطوير وفق التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_13" style="">
<span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">base </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">

DEBUG </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'django.db.backends.sqlite3'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'NAME'</span><span class="pun">:</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'db.sqlite3'</span><span class="pun">),</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما ترى، الإعدادات الخاصة ببيئة التطوير لدينا هي التنقيح <code>DEBUG</code> الذي تم تفعيله بالقيمة <code>True</code> ومحدد قاعدة البيانات <code>DATABASES</code> الذي يشير إلى قاعدة البيانات المحلية وهي في حالتنا SQLite، وهذه الإعدادات لن تتماشى مع بيئة الإنتاج إذ إن الإنتاج يتطلب إلغاء تفعيل التنقيح والربط مع قاعدة بيانات الإنتاج.
</p>

<p>
	<strong>تنويه</strong>: يعود إلغاء تفعيل التنقيح في بيئة الإنتاج إلى أسبابٍ أمنية لضمان عدم تسريب أي معلومات سرية عن المشروع من الممكن أن تظهر في أثناء التنقيح، وتعرض تطبيقك للخطر مثل <code><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></code> أو <code>KEY</code> أو <code>PASS</code> أو <code>SECRET</code> أو <code>SIGNATURE</code> أو <code>TOKEN</code>، لذا احرص دائمًا على إلغاء تفعيل التنقيح <code>DEBUG</code> قبل نشر تطبيقك في بيئة الإنتاج.
</p>

<p>
	لننتقل للملف production.py:
</p>

<pre class="ipsCode">
nano testsite/settings/production.py
</pre>

<p>
	سنعتمد نفس الطريقة، ولكن مع إلغاء تفعيل التنقيح ووضع محددات قاعدة بيانات الإنتاج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_15" style="">
<span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">base </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">

DEBUG </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">

ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_ENGINE'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'django.db.backends.sqlite3'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'NAME'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_DATABASE'</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'db.sqlite3'</span><span class="pun">)),</span><span class="pln">
        </span><span class="str">'USER'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_USER'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'PASSWORD'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_PASSWORD'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'password'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'HOST'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_HOST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'PORT'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_PORT'</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>
	يمكنك استخدام <code>dotenv</code> مع وضع قيم افتراضية لضبط محددات قاعدة البيانات وفق المثال المقدم أعلاه، ولكن احرص على تبديل قيم المتغيرات بما يناسب قاعدة بيانات التطوير الخاصة بك.
</p>

<p>
	إذًا، فقد ضبطنا التطبيق ليعمل بنموذجين مختلفين من الإعدادات يتم القرار بينهما بناءً على قيمة المحدد <code>DJANGO_SETTINGS_MODULE</code> الموجود ضمن الملف <code>env.</code>، ففي حالتنا على سبيل المثال سيعني العمل بإعدادات الإنتاج أن <code>DEBUG</code> سيحمل القيمة <code>False</code>، وأن <code>ALLOWED_HOSTS</code> سيُحدد، أما التطبيق فسيبدأ باستخدام قاعدة بيانات مختلفة هي قاعدة بيانات الإنتاج (التي يُفترض أنك جهزتها مسبقًا على الخادم الخاص بك).
</p>

<h2>
	الخطوة 4: ضبط إعدادات الأمان لتطبيق جانغو
</h2>

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

<p>
	أهم ما تتناوله هذه الإعدادات هو فرض استخدام HTTPS للعديد من مميزات مواقع الويب مثل <a href="https://academy.hsoub.com/questions/5636-%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D9%82%D8%B5%D8%AF-%D8%A8%D9%85%D8%B5%D8%B7%D9%84%D8%AD-%D9%85%D9%84%D9%81-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-cookie%D8%9F/" rel="">ملفات تعريف الارتباط للجلسة</a> وملفات تعريف الارتباط CSRF وتوجيه HTTP إلى HTTPS… إلخ، لذا فإن تنفيذ هذه الخطوة يفترض أن تطبيقك مجهز بخادم ويب وأن لديك اسم نطاق يشير إلى خادم التطبيق.
</p>

<p>
	افتح الملف production.py باستخدام محرر النصوص:
</p>

<pre class="ipsCode">
nano production.py
</pre>

<p>
	أضف ضمنه القيم الناقصة ليصبح بهذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_17" style="">
<span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">base </span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln">

DEBUG </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">

ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'your_domain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'www.your_domain'</span><span class="pun">]</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_ENGINE'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'django.db.backends.sqlite3'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'NAME'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_DATABASE'</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'db.sqlite3'</span><span class="pun">)),</span><span class="pln">
        </span><span class="str">'USER'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_USER'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'user'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'PASSWORD'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_PASSWORD'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'password'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'HOST'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_HOST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">),</span><span class="pln">
        </span><span class="str">'PORT'</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="pln">get</span><span class="pun">(</span><span class="str">'SQL_PORT'</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><span class="pln">

SECURE_SSL_REDIRECT </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
SESSION_COOKIE_SECURE </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
CSRF_COOKIE_SECURE </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
SECURE_BROWSER_XSS_FILTER </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span></pre>

<p>
	لنشرح المحددات بالترتيب:
</p>

<ul>
<li>
		<code>SECURE_SSL_REDIRECT</code>: يوجه كافة الطلبات من HTTP إلى HTTPS بالطبع مع استثناء بعض الحالات المعفاة من ذلك، يستخدم التطبيق إذًا الاتصالات المشفرة ما يستلزم تهيئة شهادات <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> على الخادم، وفي حال كنت تستخدم Nginx أو أباتشي فسيكون هذا الضبط إضافيًا وغير ملزم إذ إن كلا الخادمين يقوم فعلًا بهذا التوجيه.
	</li>
	<li>
		<code>SESSION_COOKIE_SECURE</code>: يخبر هذا المحدد المتصفح بعدم إمكانية التعامل مع ملفات تعريف الارتباط خارج HTTPS. ما يعني أن كل ما يولّده مشروعك من ملفات تعريف ارتباط (مثل تلك الخاصة بعمليات تسجيل الدخول) ستعمل فقط عبر اتصالٍ مشفر.
	</li>
	<li>
		<code>CSRF_COOKIE_SECURE</code>: يشبه المحدد السابق ولكنه يُطبق على مفتاح CSRF الخاص بك. تحمي هذه الطريقة تطبيقك من هجمات <a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B2%D9%88%D9%8A%D8%B1_%D8%A7%D9%84%D8%B7%D9%84%D8%A8_%D8%B9%D8%A8%D8%B1_%D8%A7%D9%84%D9%85%D9%88%D8%A7%D9%82%D8%B9" rel="external nofollow">تزوير الطلبات عبر المواقع</a> من خلال تأكدها -باستخدام مفاتيح CSRF- من أن كافة النماذج المقدمة سواء لتسجيل الدخول أو الاشتراكات أو غيرها هي نماذج أصلية تم إنشاؤها بواسطة تطبيقك ولم يزوّرها طرفٌ ثالث.
	</li>
	<li>
		<code>SECURE_BROWSER_XSS_FILTER</code>: يضع هذا المحدد الترويسة <code>X-XSS-Protection: 1; mode=block</code> في كافة الردود الصادرة عن التطبيق ما لم تكن موجودة أساسًا، يمنع هذا الإعداد أي طرف ثالث من حقن سكربتات برمجية في مشروعك، فعلى سبيل المثال لو خزن مستخدمٌ ما سكربتًا في قاعدة بياناتك مستغلًا أحد الحقول العامة، فلن يعمل هذا السكربت عند استرجاعه وعرضه للمستخدمين الآخرين.
	</li>
</ul>
<p>
	يمكنك الحصول على مزيد من المعلومات حول الإعدادات الأمنية بالاطلاع على <a href="https://docs.djangoproject.com/en/3.0/ref/settings/" rel="external nofollow">توثيقات جانغو</a>.
</p>

<p>
	<strong>تحذير</strong>: توصي توثيقات جانغو بعدم الاعتماد كليًا على <code>SECURE_BROWSER_XSS_FILTER</code> وإغفال الجوانب الأخرى، بل عليك دائمًا التأكد من ضبط حقول الإدخال لتطبيقك لتقبل المدخلات الصالحة فقط.
</p>

<h3>
	إعدادات إضافية
</h3>

<p>
	تتعلق الإعدادات الإضافية الواردة أدناه بأمن النقل الصارم HSTS الذي يفرض استخدام <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> على كامل موقعك وفي كل الأوقات:
</p>

<ul>
<li>
		<code>SECURE_HSTS_SECONDS</code>: يعين المدة الزمنية المحددة لاستخدام HSTS مقدرةً بالثانية، ففي حال ضبطت القيمة إلى ساعة واحدة (بالطبع حولها إلى ثواني قبل كتابتها) فهذا يعني أن متصفحك سيستخدم HTTPS حصرًا لمدة ساعة كاملة في كل مرة تزور فيها إحدى صفحات التطبيق، وإن زُرت أي جزء غير آمن من الموقع خلال هذه الساعة فإنك ستحصل على رسالة خطأ.
	</li>
	<li>
		<code>SECURE_HSTS_PRELOAD</code>: استخدامه مشروط بتعيين قيمة للمحدد السابق أي زمن HSTS، يوجه هذا النوع من الترويسات متصفح الإنترنت ليُحمّل موقعك مسبقًا أي ليُضيفه على قائمة خاصة مدمجة مع كود المتصفح وظيفتها فرض استخدام الاتصالات المشفرة مع المواقع الموجودة ضمنها (ومن بينها موقعك)، تعمل هذه الطريقة التي يصطلح على تسميتها <a href="https://hstspreload.org/" rel="external nofollow">Preload</a> مع المتصفحات الشائعة مثل Firefox و Chrome، ولكن احذر في حال اعتمدتها لموقعك فلن يكون التخلي عن التشفير أمرًا سهلًا بعدها، إذ سيتطلب إزالة الموقع يدويًا من قائمة HSTS Preload وقد تمتد العملية لأسابيع.
	</li>
	<li>
		<code>SECURE_HSTS_INCLUDE_SUBDOMAINS</code>: تفعيله يعني تطبيق ترويسة HSTS على كافة النطاقات الفرعية تحت اسم نطاق الرئيس، فلو كان نطاقك <code>your_domain</code> فإن أي رابط فرعي تحته مثل <code>unsecure.your_domain</code> حتى لو كان لا يرتبط بتطبيق جانغو سيخضع للتشفير.
	</li>
</ul>
<p>
	<strong>تحذير</strong>: قد يؤدي الاستخدام الخاطئ لهذه الإعدادات الأمنية الإضافية إلى تعطيل موقعك لفترة لا يستهان بها، لذا تعلم المزيد عنها من <a href="https://docs.djangoproject.com/en/3.0/ref/middleware/#http-strict-transport-security" rel="external nofollow">توثيقات جانغو</a> قبل تطبيقها في بيئتك الفعلية.
</p>

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

<h2>
	الخطوة 5: استخدام python-dotenv مع معلومات التطبيق السرية
</h2>

<p>
	ستتعلم في هذا الجزء الأخير كيفية الاستفادة المثلى من حزمة <code>python-dotenv</code> لحماية معلومات تطبيقك الحساسة مثل المفتاح السري <a href="https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-SECRET_KEY" rel="external nofollow"><code>SECRET_KEY</code></a> ورابط تسجيل الدخول إلى لوحة التحكم، في الواقع تعدّ هذه الآلية فكرةً ممتازة لمن يرغب برفع تطبيقه على GitHub أو GitLab أو أي منصة أخرى مشابهة فهي ستحمي بياناته السرية من النشر أمام العامة، وبدلًا من نشرها على المنصة سينشئ المطور ملف <code>env.</code> جديد يحدد من خلاله المتغيرات السرية لكل بيئة جديدة يستخدمها سواء محليًا أو على خادم.
</p>

<p>
	لنبدأ بإخفاء المفتاح السري <code>SECRET_KEY</code>، افتح الملف <code>env.</code>:
</p>

<pre class="ipsCode">
nano .env
</pre>

<p>
	واكتب ضمنه التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_19" style="">
<span class="pln">DJANGO_SETTINGS_MODULE</span><span class="pun">=</span><span class="str">"django_hardening.settings.development"</span><span class="pln">
SECRET_KEY</span><span class="pun">=</span><span class="str">"your_secret_key"</span></pre>

<p>
	ثم افتح الملف base.py:
</p>

<pre class="ipsCode">
nano testsite/settings/base.py
</pre>

<p>
	وعدّل ضمنه المفتاح السري <code>SECRET_KEY</code> ليأخذ قيمته من متغيرات البيئة المعرفة في <code>env.</code> وفق التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_21" style="">
<span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
SECRET_KEY </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">getenv</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="pun">.</span><span class="pln"> </span><span class="pun">.</span></pre>

<p>
	أما عمليتنا الأخيرة فهي إخفاء عنوان URL للوحة التحكم عبر إضافة سلسلة طويلة من المحارف العشوائية إليه، سيحميك ذلك هجمات القوة الغاشمة brute force التي تتعرض لها مواقع الويب بهدف فرض حقول تسجيل الدخول عنوةً ومحاولة تخمينها من قبل المهاجم.
</p>

<p>
	افتح الملف <code>env.</code> مجددًا:
</p>

<pre class="ipsCode">
nano .env
</pre>

<p>
	وأضف على محتوياته المحدد <code>SECRET_ADMIN_URL</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_23" style="">
<span class="pln">DJANGO_SETTINGS_MODULE</span><span class="pun">=</span><span class="str">"django_hardening.settings.development"</span><span class="pln">
SECRET_KEY</span><span class="pun">=</span><span class="str">"your_secret_key"</span><span class="pln">
SECRET_ADMIN_URL</span><span class="pun">=</span><span class="str">"very_secret_url"</span></pre>

<p>
	لنخفي الآن عنوان URL بالمحدد <code>SECRET_ADMIN_URL</code>، افتح الملف <code>urls.py</code>:
</p>

<pre class="ipsCode">
nano /testsite/urls.py
</pre>

<p>
	<strong>تنويه</strong>: لا تنسَ استبدال <code>your_secret_key</code> و <code>very_secret_url</code> بالسلاسل النصية التي تشكل مفتاحك السري وعنوان URL الخاص بك، وفي حال رغبت باستعمال سلاسل نصية عشوائية فإن بايثون يقدم لك مكتبة مميزة <a href="https://docs.python.org/3/library/secrets.html" rel="external nofollow">secrets.py</a> لتوليدها، مع مجموعة مفيدة من الأمثلة لإنشاء برامج بسيطة تولد هذا النوع من السلاسل العشوائية الآمنة.
</p>

<p>
	ومن ثم عدّله ليصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1883_25" style="">
<span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="pln">os</span><span class="pun">.</span><span class="pln">getenv</span><span class="pun">(</span><span class="str">'SECRET_ADMIN_URL'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">'/admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	وبذلك يكون رابط لوحة التحكم لتطبيقك هو <code>/very_secret_url/admin</code> بدلًا من <code>/admin/</code> فقط.
</p>

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

<p>
	أعددنا في هذا المقال تطبيق جانغو سهل الاستخدام والنشر في بيئاتٍ مختلفة، ويستثمر ميزات <code>python-dotenv</code> للتعامل مع الإعدادات والأسرار، بالإضافة لكونه آمن ومجهز بضوابط الأمان الأساسية اللازمة لمرحلة الإنتاج، وفي حال طبقت المعايير التي ناقشناها والموصى بها فإنك ستحظى بتطبيقٍ آمن يحمل المزايا الأساسية التالية:
</p>

<ul>
<li>
		تشفير كافة الاتصالات عبر <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/HTTPS (مثل: النطاقات الفرعية وملفات تعريف الارتباط وملفات ارتباط CSRF).
	</li>
	<li>
		الحماية من هجمات البرمجة العابرة للمواقع XSS.
	</li>
	<li>
		الحماية من هجمات تزوير الطلبات عبر المواقع CSRF.
	</li>
	<li>
		إخفاء المفتاح السري للمشروع.
	</li>
	<li>
		إخفاء رابط لوحة التحكم ما يمنع هجمات القوة الغاشمة brute force.
	</li>
	<li>
		فصل إعدادات التطوير عن إعدادات الإنتاج.
	</li>
</ul>
<p>
	إن رغبت بمعرفة المزيد حول جانغو وإعداداته اطلع على <a href="https://docs.djangoproject.com/en/3.0/ref/settings/" rel="external nofollow">توثيقاته الرسمية</a> و<a href="https://academy.hsoub.com/programming/python/django/" rel="">القسم الخاص به</a> على أكاديمية حسوب.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-harden-your-production-django-project" rel="external nofollow">How To Harden the Security of Your Production Django Project</a> لصاحبه Ari Birnbaum.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/" rel="">تثبيت إطار العمل جانغو على أوبنتو</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AD%D8%B2%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B3%D9%87%D9%84-%D8%AA%D8%B9%D8%A7%D9%85%D9%84%D9%83-%D9%85%D8%B9-django-r656/" rel="">حزم بايثون الثمانية التي تسهل تعاملك مع Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AE%D8%B5%D9%8A%D8%B5-%D9%84%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D9%81%D9%82%D8%A9-%D9%85%D8%B9-django-r479/" rel="">تخصيص لوحة التحكم المرفقة مع Django</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1717</guid><pubDate>Wed, 21 Sep 2022 11:00:00 +0000</pubDate></item><item><title>&#x645;&#x639;&#x627;&#x644;&#x62C;&#x629; &#x637;&#x644;&#x628;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x639;&#x628;&#x631; &#x627;&#x644;&#x639;&#x631;&#x648;&#x636; views &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x62C;&#x627;&#x646;&#x63A;&#x648;</title><link>https://academy.hsoub.com/programming/python/django/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r1629/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c813d78de83_---.png.9593d8d4e2fe54b6ead7a36526359417.png" /></p>

<p>
	تعلمت في المقالات السابقة كيفية إنشاء تطبيق جانغو Django (تطبيق المدونة) وكيفية السماح للمستخدمين الذين لديهم الصلاحيات الإدارية إضافة التعليقات والمنشورات باستخدام لوحة التحكم في <a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/" rel="">واجهة مدير جانغو Django admin interface</a>.
</p>

<p>
	ستتعلم في هذا المقال إنشاء عروض جانغو views تُمكّن تطبيق الويب الخاص بك من التعامل مع طلبات الويب بالطريقة الصحيحة وارسال استجابات الويب ردًا على الطلبيات المرسلة، ويمكن أن تكون الاستجابة محتوى <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> لصفحة ويب معينة أو إعادة توجيه أو خطأ <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">HTTP</a> (مثل خطأ 404).
</p>

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

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

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

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-models-%D9%88%D8%B1%D8%A8%D8%B7%D9%87%D8%A7-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1627/" rel="">إنشاء نماذج جانغو Django Models وربطها بقاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/" rel="">تنشيط واجهة مدير جانغو والاتصال بها</a>
	</li>
	<li>
		معالجة طلبات الويب عبر العروض views في تطبيق جانغو
	</li>
</ul>
<p>
	فإذا لم تقرأ المقالات السابقة، فيجب أن تعلم أننا نفترض ما يلي:
</p>

<ul>
<li>
		لديك نسخة جانغو 3 أو أحدث.
	</li>
	<li>
		وصلت تطبيقك بقاعدة بيانات (نحن نستخدم <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">MySQL</a>).
	</li>
	<li>
		أنك تعمل على نظام تشغيل مبني على يونيكس Unix. يُفضل أن يكون خادمًا سحابيًّا أبونتو 20.04 Ubuntu، لأنه النظام الذي تم إجراء الاختبار عليه. إذا كنت تريد العمل على بيئة مشابهة، فيجب عليك إعداد جانغو عليها.
	</li>
	<li>
		أعددت واجهة مُدير جانغو الخاصة بك.
	</li>
</ul>
<p>
	هذا المقال يتعامل مع عروض جانغو، وبالتالي قد تتمكن من اتباع هذا الدرس، حتى لو كان لديك إعداد مختلف.
</p>

<h2>
	الخطوة الأولى - إنشاء دوال العروض
</h2>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_10" style="">
<span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app
$ </span><span class="pun">.</span><span class="pln">env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	انتقل بعد ذلك إلى المجلد blogsite لكي نفتح بعد ذلك ملف العروض وننشئ أول عرض:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_12" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span></pre>

<p>
	افتح ملف العروض views.py باستخدام محرر النصوص الذي تفضله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_21" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano views</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	بعد فتح الملف يجب أن تضع فيه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_14" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render

</span><span class="com"># Create your views here.</span></pre>

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

<p>
	سنضيف الآن العرض الأول الذي سيرحب بالمستخدمين في صفحة الفهرس. لذا سنستورد الدالة <code>()HttpResponse</code> من المكتبة <code>http</code>، وسنمرر لهذه الدالة نصًا ليتم عرضه عند طلب صفحة الويب.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_16" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">


</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hello, welcome to the index page.'</span><span class="pun">)</span></pre>

<p>
	بعد ذلك سنضيف دالة أخرى لعرض منشور محدد.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_25" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> individual_post</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hi, this is where an individual post will be.'</span><span class="pun">)</span></pre>

<p>
	الآن تكون قد انتهيت من تعديل ملف العروض views.py سيبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_23" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render


</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hello, welcome to the index page.'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> individual_post</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hi, this is where an individual post will be.'</span><span class="pun">)</span></pre>

<p>
	بعد الانتهاء احفظ الملف واغلقه. إذا كنت تستخدم المحرر nano، اضغط على CTRL+X ثم Y ثم ENTER.
</p>

<p>
	حتى الآن لم يتم ربط <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> مع هذه الدوال، لذا يجب عليك إضافة ذلك إلى أنماط العناوين <code>urlpatterns</code> في ملف العناوين urls.py.
</p>

<h2>
	الخطوة الثانية - ربط العناوين بالعروض
</h2>

<p>
	يمكنك إنشاء عناوين URLs الخاصة بك في جانغو لاستخدامها في تطبيقك، ويتم ذلك من خلال ملف تهيئة العناوين <strong>URLconf</strong>.
</p>

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

<p>
	إذا فشلت أي خطوة من الخطوات السابقة، فسيتم استخدام العرض <a href="https://docs.djangoproject.com/en/3.0/topics/http/views/#customizing-error-views" rel="external nofollow">error-handling</a> المخصص لمعالجة الأخطاء وعرضها.
</p>

<p>
	ستعمل في هذا القسم مع ملفي عناوين مُختلفين وفي مجلدين مختلفين في تطبيقك. الآن، من مجلد <code>‎~/my_blog_app/blog/blogsite</code> افتح الملف urls.py (الذي يسمى أيضًا "URLconf") لكي تُعدله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_28" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano urls</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	عدّل الملف الموجود لديك بحيث يصبح كما يلي، ثم احفظه واغلقه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_30" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> views


urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">''</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'index'</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'post/'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">individual_post</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'individual_post'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	بعد تحديث ملف URLconf الخاص بمجلد blogsite، ويجب عليك تضمينه في ملف URLconf الخاص بمجلد المُدونة، وإلا فلن يتم التعرّف عليه، وتحتاج ذلك لأنه تم تحديده على أنه <code>ROOT_URLCONF</code> في ملف الإعدادات الخاص بك. هذا يعني أن جانغو يبحث في ملف URLconf الخاص بمجلد المدونة blog عندما يحتاج إلى مُطابقة أنماط عناوين <code>urlpatterns</code>. لإنجاز ذلك انتقل إلى مجلد المدونة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_32" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blog</span></pre>

<p>
	افتح ملف العناوين لتعديله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_34" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano urls</span><span class="pun">.</span><span class="pln">py</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_36" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> include</span><span class="pun">,</span><span class="pln"> path


urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">''</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="str">'blogsite.urls'</span><span class="pun">))</span><span class="pln">
</span><span class="pun">]</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_38" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">..</span></pre>

<p>
	نفّذ الأمر التالي (استبدل <code>0.0.0.0</code> بعنوان IP الخاص بك):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_40" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	انتقل إلى عنوان IP الخاص بك والمنفذ 8000 في متصفحك:
</p>

<pre class="ipsCode">
your-server-ip:8000
</pre>

<p>
	ستظهر لك صفحة ويب كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102756" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-initial-index01.png.f58d0e7ed1151de1f151b0aa1fb39d30.png" rel=""><img alt="django-initial-index01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102756" data-unique="l183nsihj" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-initial-index01.thumb.png.d0b2559ba485aa6c172681922f4537f5.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	انتقل الآن إلى العنوان التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_43" style="">
<span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">post</span><span class="pun">/</span></pre>

<p>
	يجب أن تظهر الصفحة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102757" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-initial-post02.png.146bdcf348629905fdd5b26c0288f4ce.png" rel=""><img alt="django-initial-post02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102757" data-unique="cbpexqjyv" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-initial-post02.thumb.png.d820d41a920909667a52530cc63dd59d.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	بهذا تكون قد تحققت من عمل ملفي urls.py بنجاح.
</p>

<h2>
	الخطوة الثالثة - إضافة منشور في المدونة
</h2>

<p>
	سنضيف الآن منشورًا في المدونة ونعرضه على صفحة الويب بدلًا من النص الذي عرضناه في الخطوة السابقة والذي عرّفناه ضمن ملفات المشروع.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_46" style="">
<span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span><span class="pln">blogsite</span><span class="pun">/</span></pre>

<p>
	بعد أن تظهر لك واجهة المُدير، اضغط على الزر "‎+ Add" الموجودة في السطر الثاني (سطر المنشورات Posts) لإضافة منشور ووضعه في قاعدة البيانات (بالنسبة للزر الآخر "change" فستحتاجه في حال أردت تعديل المنشور لاحقًا).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102755" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-blogsite-administration03.png.0e6003f21ea17834b95671e56975b19e.png" rel=""><img alt="django-blogsite-administration03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102755" data-unique="1yvkykyrh" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-blogsite-administration03.thumb.png.b549fd4555d7354d6719e9fa2fd9489f.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	عند النقر على الرابط، ستتلقى نموذجًا للإدخال كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102753" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-add-post04.png.e60420df6b2018cf49c73ce749b01256.png" rel=""><img alt="django-add-post04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102753" data-unique="cevuud3ds" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-add-post04.thumb.png.a31606fb5768c14cd0e8416d0f9073a9.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	النموذج يحتوي على الحقول التالية:
</p>

<ul>
<li>
		العنوان Title: تضع هنا عنوان المنشور، مثلًا <code>My First Blog Post</code>.
	</li>
	<li>
		عنوان فرعي Slug: كلمات رئيسية مقروءة، تُشتق من عنوان الصفحة، لذلك في هذه الحالة يمكننا استخدام <code>my-first-blog-post</code>.
	</li>
	<li>
		المحتوى Content: المحتوى النصي للمنشور.
	</li>
	<li>
		المؤلف author: الشخص الذي كتب المنشور.
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102754" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-blog-post-data05.png.5001c820fa1f107f1a4f839b74852761.png" rel=""><img alt="django-blog-post-data05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102754" data-unique="mdc5a0y81" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-blog-post-data05.thumb.png.27ca1086360b2a4c7cbed3847791f365.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	بعد ذلك اضغط على زر الحفظ "SAVE".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102759" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-successful-post06.png.864a423b805955b660069bf182d64827.png" rel=""><img alt="django-successful-post06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102759" data-unique="3nmfnmkhb" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-successful-post06.thumb.png.5c8ae0ce6f31d343b5657254dc2a253e.png" style="width: 650px; height: auto;"></a>
</p>

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

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

<p>
	يجب أن ننتقل الآن إلى قاعدة بيانات MySQL، لذا أوقف تشغيل <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> من خلال الأمر CTRL+C، ثم افتح مُفسّر MySQL interpreter مع تحديد المُستحدم djangouser الذي أنشأته سابقًا.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_54" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ mysql </span><span class="pun">-</span><span class="pln">u djangouser</span></pre>

<p>
	انتقل إلى قاعدة البيانات <code>blog_data</code> التي أنشأتها سابقًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_56" style="">
<span class="typ">Mysql</span><span class="pun">&gt;</span><span class="pln"> use blog_data</span><span class="pun">;</span></pre>

<p>
	اعرض محتويات الجدول blogsite_post:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_58" style="">
<span class="typ">Mysql</span><span class="pun">&gt;</span><span class="pln"> select </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">from</span><span class="pln"> blogsite_post</span><span class="pun">;</span></pre>

<p>
	يجب أن يكون الخرج مُشابهًا لما يلي. يجب أن يُعرض لك معلومات المنشور الذي أضفته في الخطوة السابقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_60" style="">
<span class="pun">+----+--------------------+--------------------+---------------+----------------------------+--------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> id </span><span class="pun">|</span><span class="pln"> title              </span><span class="pun">|</span><span class="pln"> slug               </span><span class="pun">|</span><span class="pln"> content       </span><span class="pun">|</span><span class="pln"> created_on                 </span><span class="pun">|</span><span class="pln"> author </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">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="typ">First</span><span class="pln"> </span><span class="typ">Blog</span><span class="pln"> </span><span class="typ">Post</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> my</span><span class="pun">-</span><span class="pln">first</span><span class="pun">-</span><span class="pln">blog</span><span class="pun">-</span><span class="pln">post </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">World</span><span class="pun">!</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">-</span><span class="lit">05</span><span class="pun">-</span><span class="lit">14</span><span class="pln"> </span><span class="lit">00</span><span class="pun">:</span><span class="lit">30</span><span class="pun">:</span><span class="lit">03.186564</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Sammy</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+--------------------+--------------------+---------------+----------------------------+--------+</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> row </span><span class="kwd">in</span><span class="pln"> set </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

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

<p>
	انتقل إلى الملف views.py الموجود في المجلد blogsite:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_62" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span></pre>

<p>
	افتح الملف الآن باستخدام المحرر الذي يناسبك لكي تضيف البيانات اللازمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_64" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano views</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	عدّل ملفك بحيث يصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_67" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">


</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="str">'Hello, welcome to the index page.'</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> individual_post</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    recent_post </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">id__exact</span><span class="pun">=</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="pln">recent_post</span><span class="pun">.</span><span class="pln">title </span><span class="pun">+</span><span class="pln"> </span><span class="str">': '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> recent_post</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span></pre>

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

<p>
	انتقل إلى ملف الإدارة manage.py بعد إغلاق وحفظ الملف لتشغيل التطبيق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_69" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog
</span><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	انتقل من خلال المتصفح إلى الموقع التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_71" style="">
<span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">post</span><span class="pun">/</span></pre>

<p>
	سترى هنا التغييرات التي أجريتها؛ سترى النص الذي أضفته إلى المنشور.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102758" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-served-blog-post07.png.d7debbc319a2d136b3ef558e46be466b.png" rel=""><img alt="django-served-blog-post07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102758" data-unique="0q4ijkt1o" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-served-blog-post07.thumb.png.0418f853494377d351364585f260a37c.png" style="width: 650px; height: auto;"></a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5346_75" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ deactivate</span></pre>

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-create-views-for-django-web-development" rel="external nofollow">How To Create Views for Django Web Development</a> لصاحبه Jeremy Morris.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%B9%D8%A7%D8%AA-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%B9%D9%84%D9%89-django-r384/" rel="">إنشاء تطبيق الاقتراعات وكتابة العرض الأول على Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-%D9%88%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-%D9%81%D9%8A-django-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r436/" rel="">العروض والقوالب في Django - الجزء الأول</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1629</guid><pubDate>Sat, 30 Jul 2022 16:06:00 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x634;&#x64A;&#x637; &#x648;&#x627;&#x62C;&#x647;&#x629; &#x645;&#x62F;&#x64A;&#x631; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x648;&#x627;&#x644;&#x627;&#x62A;&#x635;&#x627;&#x644; &#x628;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c80fd93a2d6_-----.png.c0c3684c7bbb32d4e64faa5db3c21359.png" /></p>

<p>
	هذا المقال هو جزء من سلسلة مقالات سابقة، حيث تعلمت في المقالات السابقة كيفية إنشاء تطبيق جانغو وربطه <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">بقاعدة بيانات MySQL</a> وإنشاء نماذج للمنشورات والتعليقات داخل تطبيق الويب، وستتعلم في مقال اليوم كيفية الاتصال بموقع مُدير جانغو Django admin site وتنشيطه لكي تتمكن من إدارة تطبيق جانغو الخاص بك على الويب (المُدونة التي أنشأتها في المقالات السابقة).
</p>

<p>
	موقع مُدير جانغو يمتلك واجهة تُسمى واجهة مُدير جانغو Django admin interface تُسهل عليك العمل وتمنحك القدرة على إدارة موقعك أنت وأي مستخدم آخر لديه الصلاحيات في ذلك.
</p>

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

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-models-%D9%88%D8%B1%D8%A8%D8%B7%D9%87%D8%A7-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1627/" rel="">إنشاء نماذج جانغو Django Models وربطها بقاعدة البيانات</a>
	</li>
	<li>
		تنشيط واجهة مدير جانغو والاتصال بها
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r1629/" rel="">معالجة طلبات الويب عبر العروض views في تطبيق جانغو</a>
	</li>
</ul>
<p>
	إذا لم تقرأ المقالات السابقة، فيجب أن تعلم أننا نفترض ما يلي:
</p>

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

<h2>
	الخطوة الأولى - تنشيط المدير Admin
</h2>

<p style="direction: ltr; ">
	كما في المقالات السابقة؛ عليك أولًا تنشيط <a href="https://academy.hsoub.com/programming/python/%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%AA%D9%87%D8%A7-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r714/" rel="">بيئة بايثون</a> الخاصة بك والانتقال إلى المجلد الجذر للتطبيق:‏
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_7" style="">
<span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app
$ </span><span class="pun">.</span><span class="pln"> env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	يجب عليك الآن التأكد من أن تطبيقك موجود في القائمة <code>INSTALLED_APPS</code> في ملف الإعدادات settings.py، لذا انتقل إلى المجلد الذي يحتوي على هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_11" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span></pre>

<p>
	افتح ملف الإعدادات بواسطة أي محرر تريده (سنستخدم هنا المحرر nano):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_13" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ nano settings</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	إذا لم تجد تطبيقك في القائمة، أضفه من خلال <code>django.contrib.admin</code>.
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_15" style="">
<span class="pun">...</span><span class="pln">
</span><span class="com"># Application definition</span><span class="pln">
INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'blogsite'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	في حال أجريت أيّة تعديلات، فيجب عليك حفظ الملف وإغلاقه (إذا كنت تستخدم المحرر nano، اضغط على CTRL+X ثم Y ثم ENTER).
</p>

<p>
	افتح الآن ملف العناوين urls.py باستخدام محرر النصوص الذي تستخدمه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_17" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ nano urls</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يجب أن يكون الملف يشبه التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_19" style="">
<span class="pun">…</span><span class="pln">
</span><span class="str">"""
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]</span></pre>

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

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

<h2>
	الخطوة الثانية - تنشيط تطبيق المدير
</h2>

<p>
	يجب أن يتم الآن تهجير النماذج إلى قاعدة البيانات، لكي تتعرّف على نماذج المُدير التي تمت إضافتها. انتقل إلى المجلد الذي يوجد فيه ملف الإدارة manager.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_21" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

<p>
	تذكر أنّه يتوجب عليك دائمًا تنفيذ أمر التهجير <code>migrate</code> عندما تُجري أي تعديلات على النماذج:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_23" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	يجب أن تحصل على خرج مشابه للخرج التالي عند تنفيذ أمر التهجير في حال لم تٌجري تعديلات الملفات السابقة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_25" style="">
<span class="typ">Operations</span><span class="pln"> to perform</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Apply</span><span class="pln"> all migrations</span><span class="pun">:</span><span class="pln"> admin</span><span class="pun">,</span><span class="pln"> auth</span><span class="pun">,</span><span class="pln"> blogsite</span><span class="pun">,</span><span class="pln"> contenttypes</span><span class="pun">,</span><span class="pln"> sessions
</span><span class="typ">Running</span><span class="pln"> migrations</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">No</span><span class="pln"> migrations to apply</span><span class="pun">.</span></pre>

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

<p>
	شغّل الخادم الآن من خلال الأمر التالي (استبدال <code>0.0.0.0</code> بعنوان IP الخاص بك):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_27" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $python manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	ثم انتقل إلى عنوان URL الخاص بلوحة التحكم في المتصفح الذي تستخدمه (تأكد من ادخال عنوان IP الخاص بخادمك).
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_29" style="">
<span class="pln">http</span><span class="pun">://</span><span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span></pre>

<p>
	ستظهر لك شاشة تسجيل الدخول التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102750" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login01.png.0874a6ed1d5798bc4cc9e7c263577677.png" rel=""><img alt="django-admin-login01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102750" data-unique="qio9m96lm" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login01.thumb.png.3f1e8e37322dc292b404cabbb91b4602.png" style="width: 600px; height: auto;"></a>
</p>

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

<h2>
	الخطوة الثالثة - إنشاء حساب مُدير أساسي Admin Super-User
</h2>

<p>
	افتح نافذة جديدة للطرفية للاتصال <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">بالخادم</a>، أو أوقف تطبيق جانغو بالضغط على CTRL+C لكي تتمكن من العمل ضمن البيئة الخاصة بك. افتح ملف الإدارة manager.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_34" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

<p>
	بعد ذلك سيطلب منك تحديد معلومات المستخدم، مثل اسم المستخدم والبريد الإلكتروني وكلمة المرور. هنا سنسميه <code>admin_user</code> وسيكون البريد <code>sammy@example.com</code> وكلمة المرور <code>admin123</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_36" style="">
<span class="typ">Username</span><span class="pln"> </span><span class="pun">(</span><span class="pln">leave blank to use </span><span class="str">'root'</span><span class="pun">):</span><span class="pln"> admin_user
</span><span class="typ">Email</span><span class="pln"> address</span><span class="pun">:</span><span class="pln"> sammy@example</span><span class="pun">.</span><span class="pln">com</span></pre>

<p>
	بعد ذلك سيطلب منك إدخال كلمة المرور مرتين (للتأكيد). لذا ادخل الكلمة الأولى ثم اضغط ENTER ثم أعد كتابتها واضغط ENTER.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_39" style="">
<span class="typ">Password</span><span class="pun">:</span><span class="pln"> 
</span><span class="typ">Password</span><span class="pln"> </span><span class="pun">(</span><span class="pln">again</span><span class="pun">):</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102752" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel02.png.69cc9249305aa2a87cd67d09045fc278.png" rel=""><img alt="django-admin-panel02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102752" data-unique="adpna54r9" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel02.thumb.png.f6b878a15d4a08f026d5f277367a71f9.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	بعد ذلك تحتاج إلى ربط تطبيقك بلوحة الإدارة admin panel.
</p>

<h2>
	الخطوة الرابعة - إنشاء أنماط عناوين للنشر والتعليق
</h2>

<p>
	حتى الآن لازالت لوحة الإدارة لا تحتوي على تطبيقك (تطبيق المدونة)، لذا يجب أن تضيفها وتسجلها مع النماذج المرتبطة بها (<code>Comment</code> و <code>Post</code>). لإنجاز ذلك، أنشئ ملفًا فارغًا يُسمى urls.py في المجلد blogsite:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_44" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ touch </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span><span class="pun">/</span><span class="pln">urls</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أضف في هذا الملف نمط <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> لتطبيقك، لكي تتمكن من الوصول إليه عبر واجهة المٌدير. انتقل إلى المجلد الذي يحتوي على ملف العناوين urls.py الذي أنشأته:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_47" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span><span class="pun">/</span></pre>

<p>
	ثم افتح الملف باستخدام محرر النصوص:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_50" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ nano urls</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أضف التعليمات البرمجية التالية إليه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_53" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> path
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> views
urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'$/'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">posts</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'posts'</span><span class="pun">),</span><span class="pln">
    path</span><span class="pun">(</span><span class="str">'$/'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">comments</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'comments'</span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	بذلك نكون انتهينا من إضافة أنماط العناوين اللازمة ليتمكن التطبيق من الوصول إلى العروض views (لم نتحدث عنها في المقالات السابقة، لكن سنغطيها لاحقًا) والمنشورات <code>Posts</code> والتعليقات <code>Comments</code>.
</p>

<h2>
	الخطوة الخامسة - ربط تطبيق المدونة بحساب المدير
</h2>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_55" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_57" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ nano admin</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	سيكون بهذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_59" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin

</span><span class="com"># Register your models here.</span></pre>

<p>
	الآن أضف إليه التعليمات البرمجية اللازمة لتسجيلهم كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_61" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="kwd">import</span><span class="pln"> admin
</span><span class="kwd">from</span><span class="pln"> blogsite</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Post</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> blogsite</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Comment</span><span class="pln">


admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">)</span><span class="pln">
admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">register</span><span class="pun">(</span><span class="typ">Comment</span><span class="pun">)</span></pre>

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

<h2>
	الخطوة السادسة - تحقق من أن عملية الربط تمت بنجاح
</h2>

<p>
	بعد إضافة الشيفرة البرمجية اللازمة لتسجيل النماذج في ملف المُدير، شغّل الخادم مرة أخرى من خلال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_63" style="">
<span class="pln">http</span><span class="pun">://</span><span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102751" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-models-added03.png.8c1a9383ca03debcdfffbc231c6e3367.png" rel=""><img alt="django-admin-models-added03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102751" data-unique="voug3t9ri" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-models-added03.thumb.png.ff616057553e5410e1e235ba2faf9c67.png" style="width: 650px; height: auto;"></a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3525_66" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln"> $ deactivate</span></pre>

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-enable-and-connect-the-django-admin-interface" rel="external nofollow">How To Enable and Connect the Django Admin Interface</a> لصاحبه Jeremy Morris.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/" rel="">تثبيت إطار العمل جانغو على أوبنتو </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1628</guid><pubDate>Wed, 27 Jul 2022 16:06:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x646;&#x645;&#x627;&#x630;&#x62C; &#x62C;&#x627;&#x646;&#x63A;&#x648; Django Models &#x648;&#x631;&#x628;&#x637;&#x647;&#x627; &#x628;&#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-models-%D9%88%D8%B1%D8%A8%D8%B7%D9%87%D8%A7-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1627/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c80b675c6d3_---.png.1ddf4698114ef23b42279ba5245c0cc5.png" /></p>

<p>
	تعلمت في <a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">المقال السابق</a> كيفية إنشاء قاعدة بيانات MySQL وإنشاء تطبيق <a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو Django</a> وربطه بها وتشغيله. في هذا المقال سننشئ نماذج models في جانغو التي تُعرّف الحقول والسلوكيات الخاصة ببيانات تطبيقك (تطبيق المُدونة الذي بدأنا به في المقال السابق)، إذ تربط هذه النماذج البيانات من تطبيقك إلى قاعدة البيانات، ويستخدمها جانغو لإنشاء جداول قاعدة البيانات من خلال واجهة برمجة التطبيقات ORM (اختصار للعبارة Object Relational Mapping أي "ربط الكائنات العِلاقيَّة") وهو عبارة عن طريقة لربط الكائنات الخاصة بتطبيق ما بجداول في نظام إدارة قواعد بيانات علائقية. ويمكن تعريف النماذج بشكل مبسط على أنها وصف للبيانات الموجودة في قاعدة البيانات، وبمعنى آخر تمثّل النماذج في جانغو بنية قاعدة البيانات، أي ما ستحصل عليه من إجراء الأمر <code>CREATE TABLE</code>، لكن بلغة بايثون بدلًا من <a href="https://academy.hsoub.com/programming/sql/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-sql-r844/" rel="">SQL</a>.
</p>

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

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		إنشاء نماذج جانغو Django Models وربطها بقاعدة البيانات
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/" rel="">تنشيط واجهة مدير جانغو والاتصال بها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r1629/" rel="">معالجة طلبات الويب عبر العروض views في تطبيق جانغو</a>
	</li>
</ul>
<p>
	فإذا لم تكن قد قرأت المقالات السابقة وطبقتها، فيجب أن تعلم أننا نفترض ما يلي:
</p>

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

<h2>
	الخطوة الأولى - إنشاء تطبيق جانغو
</h2>

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

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_8" style="">
<span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app
$ </span><span class="pun">.</span><span class="pln"> env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate
$ cd blog</span></pre>

<p>
	بعد الانتقال إلى المشروع، نفّذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_10" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py startapp blogsite</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_12" style="">
<span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">
</span><span class="pun">└──</span><span class="pln"> blog
    </span><span class="pun">├──</span><span class="pln"> blog
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __pycache__
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">cpython</span><span class="pun">-</span><span class="lit">38.pyc</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"> settings</span><span class="pun">.</span><span class="pln">cpython</span><span class="pun">-</span><span class="lit">38.pyc</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"> urls</span><span class="pun">.</span><span class="pln">cpython</span><span class="pun">-</span><span class="lit">38.pyc</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"> wsgi</span><span class="pun">.</span><span class="pln">cpython</span><span class="pun">-</span><span class="lit">38.pyc</span><span class="pln">
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> asgi</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> settings</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> urls</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> wsgi</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">├──</span><span class="pln"> blogsite
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> apps</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> migrations
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> __init__</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> models</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">├──</span><span class="pln"> tests</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">│</span><span class="pln">   </span><span class="pun">└──</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">└──</span><span class="pln"> manage</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	سنركز في هذا المقال على الملف models.py الموجود في المجلد blogsite.
</p>

<h2>
	الخطوة الثانية - إنشاء نموذج المنشورات Posts Model
</h2>

<p>
	يجب علينا أولًا أن نفتح ملف model.py وأن نحرره بحيث يحتوي على الشيفرة الخاصة بإنشاء نموذج النشر، وهو نموذج يتضمن حقول قاعدة البيانات التالية:
</p>

<ul>
<li>
		<code>title</code>: عنوان المنشور على المدونة.
	</li>
	<li>
		<code>slug</code>: يتم فيها تخزين <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عناوين URL</a> الصالحة وإنشاءها لصفحات الويب.
	</li>
	<li>
		<code>content</code>: المحتوى النصي لمنشور المدونة.
	</li>
	<li>
		<code>Creat_on</code>: تاريخ إنشاء المنشور.
	</li>
	<li>
		<code>author</code>: الشخص الذي كتب المنشور.
	</li>
</ul>
<p>
	انتقل الآن إلى المجلد الذي يحتوي الملف model.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_15" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blogsite</span></pre>

<p>
	استخدم الأمر <code>cat</code> لإظهار محتويات الملف في الطرفية terminal:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_17" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cat models</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	يجب أن يحتوي الملف على الشيفرة التالية، حيث ستجد فيه تعليمة استيراد النماذج <code>import models</code>، جنبًا إلى جنب مع تعليق يصف ما سيتم وضعه في ملف model.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_19" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models
</span><span class="com"># Create your models here.</span></pre>

<p>
	أضف الشيفرة التالية إلى ملف model.py باستخدام أحد محررات النصوص (هنا سيتم استخدام المحرر nano):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_21" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano models</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	نضع الآن داخل هذا الملف تعليمات استيراد الوحدات التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_23" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">template</span><span class="pun">.</span><span class="pln">defaultfilters </span><span class="kwd">import</span><span class="pln"> slugify
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib</span><span class="pun">.</span><span class="pln">auth</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> reverse</span></pre>

<p>
	حيث نستورد الوحدة <code>slugify</code> لتوليد العناوين الفرعية slugs من السلاسل strings، ونستخدم الوحدة <code>User</code> للاستيثاق authentication، ونستخدم <code>reverse</code> لتوفير مرونة أكبر في إنشاء عناوين URL.
</p>

<p>
	أضف بعد ذلك تابع لصنف class method إلى صنف النموذج model class والتي سنسميها Post، مع إضافة الحقول التالية أيضًا إلى <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة البيانات</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_26" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    slug </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">SlugField</span><span class="pun">(</span><span class="pln">unique</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">
    created_on </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="pln">auto_now_add</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    author </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span></pre>

<p>
	سنضيف بعد ذلك دالة لإنشاء عنوان URL، ودالة لحفظ المنشور، وهذا أمر مهم جدًا لأنه يُنشئ رابطًا فريدًا لكل منشور في المدونة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_28" style="">
<span class="pun">...</span><span class="pln">
    </span><span class="kwd">def</span><span class="pln"> get_absolute_url</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> reverse</span><span class="pun">(</span><span class="str">'blog_post_detail'</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">=[</span><span class="pln">self</span><span class="pun">.</span><span class="pln">slug</span><span class="pun">])</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> save</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">args</span><span class="pun">,</span><span class="pln"> </span><span class="pun">**</span><span class="pln">kwargs</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">slug</span><span class="pun">:</span><span class="pln">
            self</span><span class="pun">.</span><span class="pln">slug </span><span class="pun">=</span><span class="pln"> slugify</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">title</span><span class="pun">)</span><span class="pln">
        super</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">).</span><span class="pln">save</span><span class="pun">(*</span><span class="pln">args</span><span class="pun">,</span><span class="pln"> </span><span class="pun">**</span><span class="pln">kwargs</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_30" style="">
<span class="pun">...</span><span class="pln">
    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        ordering </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'created_on'</span><span class="pun">]</span><span class="pln">

        </span><span class="kwd">def</span><span class="pln"> __unicode__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">title</span></pre>

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

<ul>
<li>
		الاسم: اسم الشخص الذي يقوم بنشر التعليق.
	</li>
	<li>
		البريد الإلكتروني: عنوان بريده الإلكتروني.
	</li>
	<li>
		النص: نص التعليق.
	</li>
	<li>
		المنشور: المنشور الذي تم التعليق عليه.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_32" style="">
<span class="pun">...</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Comment</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">EmailField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">75</span><span class="pun">)</span><span class="pln">
    website </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">URLField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">200</span><span class="pun">,</span><span class="pln"> null</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> blank</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">
    post </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">ForeignKey</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> on_delete</span><span class="pun">=</span><span class="pln">models</span><span class="pun">.</span><span class="pln">CASCADE</span><span class="pun">)</span><span class="pln">
    created_on </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="pln">auto_now_add</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span></pre>

<p>
	انتهيت الآن ولكن تأكد من أن ملفك يحتوي على يُطابق الملف التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_34" style="">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">db </span><span class="kwd">import</span><span class="pln"> models
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">template</span><span class="pun">.</span><span class="pln">defaultfilters </span><span class="kwd">import</span><span class="pln"> slugify
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib</span><span class="pun">.</span><span class="pln">auth</span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">User</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">urls </span><span class="kwd">import</span><span class="pln"> reverse


</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Post</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    title </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    slug </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">SlugField</span><span class="pun">(</span><span class="pln">unique</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> max_length</span><span class="pun">=</span><span class="lit">255</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">
    created_on </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="pln">auto_now_add</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    author </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> get_absolute_url</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> reverse</span><span class="pun">(</span><span class="str">'blog_post_detail'</span><span class="pun">,</span><span class="pln"> args</span><span class="pun">=[</span><span class="pln">self</span><span class="pun">.</span><span class="pln">slug</span><span class="pun">])</span><span class="pln">

    </span><span class="kwd">def</span><span class="pln"> save</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> </span><span class="pun">*</span><span class="pln">args</span><span class="pun">,</span><span class="pln"> </span><span class="pun">**</span><span class="pln">kwargs</span><span class="pun">):</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">slug</span><span class="pun">:</span><span class="pln">
            self</span><span class="pun">.</span><span class="pln">slug </span><span class="pun">=</span><span class="pln"> slugify</span><span class="pun">(</span><span class="pln">self</span><span class="pun">.</span><span class="pln">title</span><span class="pun">)</span><span class="pln">
        super</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> self</span><span class="pun">).</span><span class="pln">save</span><span class="pun">(*</span><span class="pln">args</span><span class="pun">,</span><span class="pln"> </span><span class="pun">**</span><span class="pln">kwargs</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Meta</span><span class="pun">:</span><span class="pln">
        ordering </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'created_on'</span><span class="pun">]</span><span class="pln">

        </span><span class="kwd">def</span><span class="pln"> __unicode__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">title


</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Comment</span><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">):</span><span class="pln">
    name </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">42</span><span class="pun">)</span><span class="pln">
    email </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">EmailField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">75</span><span class="pun">)</span><span class="pln">
    website </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">URLField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="lit">200</span><span class="pun">,</span><span class="pln"> null</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">,</span><span class="pln"> blank</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span><span class="pln">
    content </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">TextField</span><span class="pun">()</span><span class="pln">
    post </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">ForeignKey</span><span class="pun">(</span><span class="typ">Post</span><span class="pun">,</span><span class="pln"> on_delete</span><span class="pun">=</span><span class="pln">models</span><span class="pun">.</span><span class="pln">CASCADE</span><span class="pun">)</span><span class="pln">
    created_on </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="pln">auto_now_add</span><span class="pun">=</span><span class="kwd">True</span><span class="pun">)</span></pre>

<p>
	بعد ذلك احفظ الملف واغلقه (إذا كنت تستخدم المحرر nano اضغط CTRL+X ثم Y ثم ENTER).
</p>

<p>
	بعد الانتهاء من إعداد ملف models.py، يمكنك الانتقال إلى ملف settings.py لتحديثه.
</p>

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

<p>
	بعد الانتهاء من إضافة النماذج إلى التطبيق، يجب أن تُخبر المشروع أن التطبيق blogsite الذي أضفناه منذ قليل موجود. لإنجاز ذلك، عليك بإضافته إلى قسم <code>INSTALLED_APPS</code> في ملف الإعدادات settings.py.
</p>

<p>
	انتقل إلى المجلد الذي يحتوي ملف الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_36" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blog</span></pre>

<p>
	افتح الآن ملف settings.py باستخدام محرر النصوص:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_38" style="">
<span class="pln">$ nano settings</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	أضف الآن التطبيق blogsite إلى القائمة <code>INSTALLED_APPS</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_40" style="">
<span class="com"># Application definition</span><span class="pln">
INSTALLED_APPS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">'blogsite'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.admin'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.auth'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.contenttypes'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.sessions'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.messages'</span><span class="pun">,</span><span class="pln">
    </span><span class="str">'django.contrib.staticfiles'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">]</span></pre>

<h2>
	الخطوة الرابعة - عمليات التهجير
</h2>

<p>
	بعد إضافة النموذج <code>Comment</code> والنموذج <code>Post</code>، يجب عليك تطبيق هذه التغييرات، لكي يتعرف <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">مخطط قاعدة بيانات MySQL</a> عليها وينشئ الجداول اللازمة.
</p>

<p>
	الآن لو انتقلنا إلى المجلد <code>‎~/my_blog_app/blog/blogsite/migrations</code> ونفذنا الأمر <code>ls</code>، ستلاحظ وجود ملف واحد هو <code>‎__init__.py</code>، لكن ذلك سيتغير بعد التهجير.
</p>

<p>
	توجّه إلى مجلد المشروع عن طريق سطر الأوامر ونفّذ الأمر التالي للانتقال إلى المجلد blog:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_45" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span></pre>

<p>
	ثم نفذ الأمر <code>makemigrations</code> على الملف manage.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_47" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations</span></pre>

<p>
	وظيفة الأمر <code>makemigrations</code> هي إخبار جانغو بأنّك قد أجريت بعض التعديلات على النماذج وأنّك ترغب في حفظ هذه التعديلات على هيئة ملف تهجير يُحفظ على القرص الصلب كملف بايثون في مجلد migrations، تحت اسم ‎0001_initial.py و <strong>pycache</strong> وهي من ضمن ملفات تُنشَأ تلقائيًّا في كل مرة تنفذ هذا الأمر:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_49" style="">
<span class="typ">Migrations</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="str">'blogsite'</span><span class="pun">:</span><span class="pln">
  blogsite</span><span class="pun">/</span><span class="pln">migrations</span><span class="pun">/</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">.</span><span class="pln">py
    </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Create</span><span class="pln"> model </span><span class="typ">Post</span><span class="pln">
    </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Create</span><span class="pln"> model </span><span class="typ">Comment</span></pre>

<p>
	تذكر عندما انتقلنا إلى <code>‎~/my_blog_app/blog/blogsite/migrations</code> كان يحتوي فقط على ملف <code>‎__init__.py</code>. الآن لو رجعت إلى هذا المجلد، ستلاحظ وجود ملفين هما ‎0001_initial.py و <strong>pycache</strong>، ويمكنك تنفيذ الأمر التالي لرؤية محتويات هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_51" style="">
<span class="pln">less </span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	انتقل الآن إلى المجلد <code>‎~/my_blog_app/blog</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_53" style="">
<span class="pln">$cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_55" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py showmigrations</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_57" style="">
<span class="pln">admin
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0001</span><span class="pln">_initial
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0002</span><span class="pln">_logentry_remove_auto_add
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0003</span><span class="pln">_logentry_add_action_flag_choices
auth
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0001</span><span class="pln">_initial
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0002</span><span class="pln">_alter_permission_name_max_length
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0003</span><span class="pln">_alter_user_email_max_length
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0004</span><span class="pln">_alter_user_username_opts
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0005</span><span class="pln">_alter_user_last_login_null
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0006</span><span class="pln">_require_contenttypes_0002
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0007</span><span class="pln">_alter_validators_add_error_messages
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0008</span><span class="pln">_alter_user_username_max_length
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0009</span><span class="pln">_alter_user_last_name_max_length
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0010</span><span class="pln">_alter_group_name_max_length
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0011</span><span class="pln">_update_proxy_permissions
blogsite
 </span><span class="pun">[</span><span class="pln"> </span><span class="pun">]</span><span class="pln"> </span><span class="lit">0001</span><span class="pln">_initial
contenttypes
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0001</span><span class="pln">_initial
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0002</span><span class="pln">_remove_content_type_name
sessions
 </span><span class="pun">[</span><span class="pln">X</span><span class="pun">]</span><span class="pln"> </span><span class="lit">0001</span><span class="pln">_initial</span></pre>

<p>
	ستلاحظ أنه تم التحقق من جميع عمليات التهجير باستثناء التهجير الخاص بالملف ‎0001_initial.py الذي أنشأناه منذ قليل.
</p>

<p>
	تحقق الآن من تعليمات SQL التي يتم تنفيذها عند إجراء عمليات التهجير من خلال الأمر التالي (يأخذ هذا الأمر اسم التهجير والتهجير كوسطاء):
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_65" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py sqlmigrate blogsite </span><span class="lit">0001</span><span class="pln">_initial</span></pre>

<p>
	ستلاحظ الخرج التالي الذي يوضح تعليمات SQL التي تم تنفيذها في الخلفية.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_63" style="">
<span class="pun">--</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> </span><span class="typ">Create</span><span class="pln"> model </span><span class="typ">Post</span><span class="pln">
</span><span class="pun">--</span><span class="pln">
CREATE TABLE </span><span class="str">`blogsite_post`</span><span class="pln"> </span><span class="pun">(</span><span class="str">`id`</span><span class="pln"> integer AUTO_INCREMENT NOT NULL PRIMARY KEY</span><span class="pun">,</span><span class="pln"> </span><span class="str">`title`</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`slug`</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> NOT NULL UNIQUE</span><span class="pun">,</span><span class="pln"> </span><span class="str">`content`</span><span class="pln"> longtext NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`created_on`</span><span class="pln"> datetime</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`author`</span><span class="pln"> longtext NOT NULL</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">Create</span><span class="pln"> model </span><span class="typ">Comment</span><span class="pln">
</span><span class="pun">--</span><span class="pln">
CREATE TABLE </span><span class="str">`blogsite_comment`</span><span class="pln"> </span><span class="pun">(</span><span class="str">`id`</span><span class="pln"> integer AUTO_INCREMENT NOT NULL PRIMARY KEY</span><span class="pun">,</span><span class="pln"> </span><span class="str">`name`</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`email`</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">75</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`website`</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln"> NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`content`</span><span class="pln"> longtext NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`created_on`</span><span class="pln"> datetime</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln"> NOT NULL</span><span class="pun">,</span><span class="pln"> </span><span class="str">`post_id`</span><span class="pln"> integer NOT NULL</span><span class="pun">);</span><span class="pln">
ALTER TABLE </span><span class="str">`blogsite_comment`</span><span class="pln"> ADD CONSTRAINT </span><span class="str">`blogsite_comment_post_id_de248bfe_fk_blogsite_post_id`</span><span class="pln"> FOREIGN KEY </span><span class="pun">(</span><span class="str">`post_id`</span><span class="pun">)</span><span class="pln"> REFERENCES </span><span class="str">`blogsite_post`</span><span class="pln"> </span><span class="pun">(</span><span class="str">`id`</span><span class="pun">);</span></pre>

<p>
	نفّذ الآن أمر التهجير لكي يتم تطبيق التغييرات على قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_2720_67" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	ستحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_69" style="">
<span class="typ">Operations</span><span class="pln"> to perform</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Apply</span><span class="pln"> all migrations</span><span class="pun">:</span><span class="pln"> admin</span><span class="pun">,</span><span class="pln"> auth</span><span class="pun">,</span><span class="pln"> blogsite</span><span class="pun">,</span><span class="pln"> contenttypes</span><span class="pun">,</span><span class="pln"> sessions
</span><span class="typ">Running</span><span class="pln"> migrations</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Applying</span><span class="pln"> blogsite</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK</span></pre>

<p>
	بذلك تكون قد انتهيت من إنجاز عمليات التهجير.
</p>

<p>
	هناك ثلاث ملاحظات يجب الانتباه لها عند إجراء عمليات التهجير:
</p>

<ul>
<li>
		إذا لم تكتمل عملية التهجير بنجاح، يتعين عليك إلغاء التغييرات التي أجريتها يدويًّا قبل معاودة المحاولة (إجراء محاولة تهجير أخرى)، لأن دعم هذا النوع من عمليات التعديل على المخطط ضعيفة.
	</li>
	<li>
		معظم عمليات التعديل على مخطط قاعدة البيانات تؤدي إلى إعادة كتابة الجداول بالكامل، وبالتالي قد يؤدي إلى بطء في التنفيذ.
	</li>
	<li>
		في MySQL هناك حدود معينة لطول أسماء الأعمدة والجداول والفهارس.
	</li>
</ul>
<p>
	من أجل كل قاعدة بيانات تفكر في استخدامها مع جانغو، حبذا لو تقارن بين مزايا وعيوب كل قاعدة بيانات.
</p>

<h2>
	الخطوة الخامسة - تحقق من مخطط قاعدة البيانات
</h2>

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

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_71" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ mysql blog_data </span><span class="pun">-</span><span class="pln">u djangouser</span></pre>

<p>
	حدد الآن قاعدة البيانات <code>blog_data</code>. إذا كنت لا تتذكرها، فيمكنك استخدام الأمر <code>SHOW DATABASES;‎</code> لإظهار جميع قواعد البيانات الموجودة.
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_73" style="">
<span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> USE blog_data</span><span class="pun">;</span></pre>

<p>
	ثم اكتب الأمر التالي لعرض الجداول:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_75" style="">
<span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> SHOW TABLES</span><span class="pun">;</span></pre>

<p>
	يجب أن تحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_81" style="">
<span class="pun">+----------------------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Tables_in_blog_data</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"> auth_group                 </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> auth_group_permissions     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> auth_permission            </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> auth_user                  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> auth_user_groups           </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> auth_user_user_permissions </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> blogsite_comment           </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> blogsite_post              </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> django_admin_log           </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> django_content_type        </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> django_migrations          </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> django_session             </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------+</span><span class="pln">
</span><span class="lit">12</span><span class="pln"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.01</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	الجدولين <code>blogsite_comment</code> و <code>blogsite_post</code> هما الجداول التي تمثل النماذج التي أنشأنها. للتحقق من أنها تحتوي على الحقول التي عرفناها:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_83" style="">
<span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> DESCRIBE blogsite_comment</span><span class="pun">;</span></pre>

<p>
	الخرج:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_88" style="">
<span class="pun">+------------+--------------+------+-----+---------+----------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Field</span><span class="pln">      </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln">         </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Default</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Extra</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"> id         </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">int</span><span class="pln">          </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln"> PRI </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln"> auto_increment </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> name       </span><span class="pun">|</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">42</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> email      </span><span class="pun">|</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">75</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> website    </span><span class="pun">|</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">200</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> YES  </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> content    </span><span class="pun">|</span><span class="pln"> longtext     </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> created_on </span><span class="pun">|</span><span class="pln"> datetime</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> post_id    </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">int</span><span class="pln">          </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln"> MUL </span><span class="pun">|</span><span class="pln"> NULL    </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">7</span><span class="pln"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	والأمر نفسه بالنسبة للجدول blogsite_post:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_90" style="">
<span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> DESCRIBE blogsite_post</span><span class="pun">;</span></pre>

<p>
	الخرج:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_92" style="">
<span class="pun">+------------+--------------+------+-----+---------+----------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Field</span><span class="pln">      </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Type</span><span class="pln">         </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Null</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Key</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Default</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Extra</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"> id         </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">int</span><span class="pln">          </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln"> PRI </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln"> auto_increment </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> title      </span><span class="pun">|</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> slug       </span><span class="pun">|</span><span class="pln"> varchar</span><span class="pun">(</span><span class="lit">255</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln"> UNI </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> content    </span><span class="pun">|</span><span class="pln"> longtext     </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> created_on </span><span class="pun">|</span><span class="pln"> datetime</span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </span><span class="pun">|</span><span class="pln">                </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> author     </span><span class="pun">|</span><span class="pln"> longtext     </span><span class="pun">|</span><span class="pln"> NO   </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln"> NULL    </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"> rows </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">set</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	يمكنك الآن إغلاق MySQL باستخدام CTRL+D، بعد ذلك يمكنك مغادرة بيئة بايثون الخاصة بك من خلال تنفيذ أمر إلغاء التنشيط، وبالتالي الانتقال إلى الموقع الافتراضي في الطرفية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_2720_94" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ deactivate</span></pre>

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-create-django-models" rel="external nofollow">How To Create Django Models</a> لصاحبه Jeremy Morris.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%B9%D8%A7%D8%AA-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%B9%D9%84%D9%89-django-r384/" rel="">إنشاء تطبيق الاقتراعات وكتابة العرض الأول على Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">مقدمة عن قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1627</guid><pubDate>Sun, 24 Jul 2022 16:09:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x648;&#x62A;&#x648;&#x635;&#x64A;&#x644;&#x647; &#x628;&#x642;&#x627;&#x639;&#x62F;&#x629; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c806ffaad9b_------.png.d02debbfba9297ceb2531132cf58c4d1.png" /></p>
<p>
	<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو Django</a> هو<a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel=""> إطار عمل Framework</a>  مجاني ومفتوح المصدر، كُتِب بلغة بايثون، يوفر لنا ميزات قابلية التوسع وإعادة الاستخدام والتطوير السريع.
</p>

<p>
	سنتحدث في هذا المقال عن كيفية تهيئة وإكمال العمليات الأساسية لبناء موقع ويب لمدونة، ووصلها <a href="https://academy.hsoub.com/devops/servers/databases/%D9%85%D9%88%D8%A7%D8%B2%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-mysql-%D9%88-mongodb-r627/" rel="">بقاعدة بيانات MySQL</a>. يتضمن ذلك إنشاء البنية الهيكلية لتطبيق الويب الخاص بمدونة باستخدام <code>django-admin</code> وإنشاء قاعدة بيانات MySQL ووصل تطبيق الويب بها.
</p>

<p>
	يوفر لك جانغو بيئة تطوير للعمل على تطبيق الويب الخاص بمدونتك، لكن ستحتاج إلى اتخاذ المزيد من الخطوات لنشر مدونتك على <a href="https://academy.hsoub.com/devops/networking/%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r571/" rel="">الإنترنت</a>.
</p>

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">البدء مع إطار العمل جانغو لإنشاء تطبيق ويب</a>
	</li>
	<li>
		إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-models-%D9%88%D8%B1%D8%A8%D8%B7%D9%87%D8%A7-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1627/" rel="">إنشاء نماذج جانغو Django Models وربطها بقاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/" rel="">تنشيط واجهة مدير جانغو والاتصال بها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r1629/" rel="">معالجة طلبات الويب عبر العروض views في تطبيق جانغو</a>
	</li>
</ul>

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

<p>
	ستحتاج في هذا المقال إلى:
</p>

<ul>
	<li>
		خادم أبونتو Ubuntu، مع صلاحيات مستخدم عادي (أي ليس جذر root) وجدار حماية firewall. انظر مقال <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">التهيئة الأولية لخادم أوبونتو</a>
	</li>
	<li>
		قاعدة بيانات MySQL مثبتة التي تمثل خادم قاعدة البيانات، انظر مقال <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">تعلم أساسيات MySQL</a>.
	</li>
	<li>
		تثبيت بايثون 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%AA%D9%87-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1804-r709/" rel="">كيفية تثبيت بايثون 3 وإعداد بيئته البرمجية على خادم أوبنتو</a>..
	</li>
</ul>

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

<h2>
	الخطوة الأولى - إنشاء قاعدة البيانات
</h2>

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

<p>
	لإنجاز ذلك، اتصل بقاعدة بيانات MySQL كمستخدم جذر، باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_9" style=""><span class="pln">$ sudo mysql</span></pre>

<p>
	بعد ذلك سيتغير رمز <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> ليصبح هكذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_11" style=""><span class="pln">mysql</span><span class="pun">&gt;</span></pre>

<p>
	يمكنك استعراض قواعد البيانات الحالية باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_15" style=""><span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> SHOW DATABASES</span><span class="pun">;</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_21" style=""><span class="pun">+--------------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Database</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"> information_schema </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> mysql             </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> performance_schema </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> sys                </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"> rows </span><span class="kwd">in</span><span class="pln"> set </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	هناك 4 قواعد بيانات يتم إنشاؤها افتراضيًّا، موضحة في الخرج السابق، ولن تحتاج إلى التعامل معها، فهي تحتوي على معلومات خاصة بخادم MySQL.
</p>

<p>
	الآن، لإنشاء قاعدة بيانات MySQL تحتفظ ببيانات مدونتك، نفذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_24" style=""><span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln"> CREATE DATABASE blog_data</span><span class="pun">;</span></pre>

<p>
	عند إنشاء قاعدة البيانات بنجاح، ستحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_27" style=""><span class="typ">Query</span><span class="pln"> OK</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> row affected </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

<p>
	انتبه فهناك احتمال أن تتلقى الخطأ التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_29" style=""><span class="pln">ERROR </span><span class="lit">1007</span><span class="pln"> </span><span class="pun">(</span><span class="pln">HY000</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Can</span><span class="str">'t create database blog_data; database exists</span></pre>

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

<p>
	إذا تلقيت خطأ MySQL التالي، فهذا يعني أن هناك خطأ قواعدي في كتابة أمر MySQL. لذا تأكد من أنك كتبت الأمر كما هو تمامًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_31" style=""><span class="pln">ERROR </span><span class="lit">1064</span><span class="pln"> </span><span class="pun">(</span><span class="lit">42000</span><span class="pun">):</span><span class="pln"> </span><span class="typ">You</span><span class="pln"> have an error </span><span class="kwd">in</span><span class="pln"> your SQL syntax</span><span class="pun">;</span></pre>

<p>
	تأكد الآن من وجود قاعدة البيانات من خلال استعراض قواعد البيانات الحالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_33" style=""><span class="pln">$ SHOW DATABASES</span><span class="pun">;</span></pre>

<p>
	الآن يجب أن تظهر قاعدة البيانات blog_data ضمن الخرج.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_35" style=""><span class="pun">+--------------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Database</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"> information_schema </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> blog_data          </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> mysql                 </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> performance_schema </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> sys                </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"> rows </span><span class="kwd">in</span><span class="pln"> set </span><span class="pun">(</span><span class="lit">0.00</span><span class="pln"> sec</span><span class="pun">)</span></pre>

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

<p>
	أولًا، أنشئ المستخدم وحدد كلمة المرور عن طريق الأمر التالي (حدد كلمة مرور قوية -استبدل "password" بكلمة المرور التي تريدها-):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_37" style=""><span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln">  CREATE USER </span><span class="str">'djangouser'</span><span class="pun">@</span><span class="str">'localhost'</span><span class="pln"> IDENTIFIED WITH mysql_native_password BY </span><span class="str">'password'</span><span class="pun">;</span></pre>

<p>
	الآن، يجب أن تعطي المستخدم <code>djangouser</code> صلاحيات الوصول الكامل إلى قاعدة البيانات التي هيأتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_39" style=""><span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln">  GRANT ALL ON blog_data</span><span class="pun">.*</span><span class="pln"> TO </span><span class="str">'djangouser'</span><span class="pun">@</span><span class="str">'localhost'</span><span class="pun">;</span></pre>

<p>
	لديك الآن قاعدة بيانات وحساب مستخدم، كل منهما مصمم خصيصًا لجانغو. نفذ الآن الأمر التالي حتى يعرف MySQL التغييرات الأخيرة التي أجريتها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_41" style=""><span class="pln">mysql</span><span class="pun">&gt;</span><span class="pln">  FLUSH PRIVILEGES</span><span class="pun">;</span></pre>

<p>
	الأمر السابق ضروري لإخبار الخادم أن يُعيد تحميل جداول الصلاحيات grant tables.
</p>

<p>
	بعد الانتهاء من ذلك، يمكنك الخروج من خادم MySQL بكتابة الأمر <code>EXIT</code>؛ أو بالضغط على CTRL + D.
</p>

<h2>
	الخطوة الثانية - إنشاء ملف ضبط MySQL
</h2>

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

<p>
	افتح ملف الضبط my.cnf باستخدام محرر النصوص المفضل لديك لتحديث بيانات اعتماد MySQL (هنا سنستخدم محرر النصوص nano):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_43" style=""><span class="pln">$ sudo nano </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">mysql</span><span class="pun">/</span><span class="pln">my</span><span class="pun">.</span><span class="pln">cnf</span></pre>

<p>
	أضف الأسطر التالية مع المعلومات المطلوبة ضمن ملف ‎/etc/mysql/my.cnf:
</p>

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

</span><span class="pun">[</span><span class="pln">client</span><span class="pun">]</span><span class="pln">
database </span><span class="pun">=</span><span class="pln"> blog_data
user </span><span class="pun">=</span><span class="pln"> djangouser
password </span><span class="pun">=</span><span class="pln"> your_actual_password
default</span><span class="pun">-</span><span class="pln">character</span><span class="pun">-</span><span class="pln">set </span><span class="pun">=</span><span class="pln"> utf8</span></pre>

<p>
	ستلاحظ أنه تم تعيين الترميز utf8 كترميز افتراضي، لأنها الطريقة الشائعة لترميز بيانات Unicode في MySQL. عندما تتأكد من صحة التفاصيل الخاصة بك، احفظ الملف واغلقه. في حال استخدمت المحرر <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-%D9%85%D8%AD%D8%B1%D8%B1-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A%D9%85-vim-%D9%88%D9%86%D8%A7%D9%86%D9%88-nano-r1590/" rel="">نانو nano</a> لتحرير الملف، فيمكنك القيام بذلك عن طريق الضغط على CTRL + X ثم Y لتأكيد التغييرات.
</p>

<p>
	بعد الانتهاء من تعديل الملف، ستحتاج إلى إعادة تشغيل MySQL لتصبح التغييرات سارية المفعول:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_47" style=""><span class="pln">$ sudo systemctl daemon</span><span class="pun">-</span><span class="pln">reload
$ sudo systemctl restart mysql</span></pre>

<p>
	إن إعادة تشغيل MySQL تستغرق بضع ثوانٍ، لذا يرجى التحلي بالصبر.
</p>

<h2>
	الخطوة الثالثة - إنشاء البنية الأولية لمشروع جانغو
</h2>

<p>
	ستضع في هذه الخطوة اللبنة الأساسية لتطبيقك عن طريق إنشاء الهيكل الأساسي للمشروع باستخدام الأمر <code>django-admin</code>.
</p>

<p>
	انتقل أولًا إلى المجلد الذي ترغب أن تضع مجلد مشروعك فيه، ثم أنشئ مجلد مشروعك واعطه اسمًا مناسبًا، مثل my_blog_app:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_49" style=""><span class="pln">$ mkdir my_blog_app</span></pre>

<p>
	انتقل الآن إلى المجلد الذي أنشأته:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_51" style=""><span class="pln">$ cd my_blog_app</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_53" style=""><span class="pln">$ python3 </span><span class="pun">-</span><span class="pln">m venv env</span></pre>

<p>
	بعد إنشاء البيئة، يجب أن تنشطها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_55" style=""><span class="pln">$ </span><span class="pun">.</span><span class="pln"> env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	ثبت الآن جانغو داخل البيئة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_57" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ pip install django</span></pre>

<p>
	نفذ الأمر التالي داخل مجلد <code>my_blog_app</code>، لإنشاء مشروع بداخله:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_59" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin startproject blog</span></pre>

<p>
	تأكد من أنه يعمل من خلال الانتقال إلى المجلد <code>blog/</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_61" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd blog</span></pre>

<p>
	ثم نفذ الأمر <code>ls</code> للتأكد من إنشاء الملفات والمجلدات الضرورية داخل مجلد المشروع:
</p>

<pre class="ipsCode">(env) sammy@ubuntu:$ ls
</pre>

<p>
	عند تنفيذ هذا الأمر، ستلاحظ في الخرج ظهور مجلد blog وملف الإدارة manage.py:
</p>

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

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

<h2>
	الخطوة الرابعة - تثبيت موصل قاعدة البيانات MySQL Database Connector
</h2>

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

<p>
	ثبت أولًا بعض المكتبات الضرورية في MySQL:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_65" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ sudo apt install libmysqlclient</span><span class="pun">-</span><span class="pln">dev default</span><span class="pun">-</span><span class="pln">libmysqlclient</span><span class="pun">-</span><span class="pln">dev</span></pre>

<p>
	ثبت بعد ذلك حزمة <code>wheel</code> باستخدام مدير الحزم <code>pip</code>. وهي حزمة تستخدم في بايثون لتثبيت الوحدات modules من فهرس حزم بايثون Python Package Index. إن تثبيت برامج بايثون من خلال حزمة <code>wheel</code> يكون أسرع وأكثر كفاءة في استخدام الموارد من تثبيتها عن طريق بناء الحزم من الشيفرة المصدر. لتثبيت حزمة <code>wheel</code>، نفذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_67" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ pip install wheel</span></pre>

<p>
	بعد ذلك ثبت <code>mysqlclient</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_69" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ pip install mysqlclient</span></pre>

<p>
	بعد ذلك يجب أن تحصل على خرج مشابه للتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_71" style=""><span class="pun">...</span><span class="pln">
</span><span class="typ">Successfully</span><span class="pln"> installed mysqlclient</span><span class="pun">-</span><span class="lit">2.1</span><span class="pun">.</span><span class="lit">0</span></pre>

<p>
	بذلك تكون نجحت في تثبيت <code>mysqlclient</code>.
</p>

<h2>
	الخطوة الخامسة - تعديل الإعدادات
</h2>

<p>
	عندما نفذت الأمر <code>django-admin</code> سابقًا أدى ذلك إلى إنشاء ملف ضبط لجانغو يُسمى ملف الإعدادات settings.py. تحتاج إلى تغيير بعض الإعدادات الافتراضية فيه لكي تسير الأمور بنجاح.
</p>

<p>
	افتح الملف لتعديله من خلال محرر النصوص الذي تريده (هنا كالعادة المحرر nano):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_73" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ nano </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

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

<p>
	لإنجاز ذلك، انتقل إلى الحقل <code>TIME_ZONE</code>، والمتواجد ضمن ملف الإعدادات في القسم السفلي <code>‎~/my_blog_app/blog/blog/settings.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_75" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># Internationalization</span><span class="pln">
</span><span class="com"># https://docs.djangoproject.com/en/2.0/topics/i18n/</span><span class="pln">

LANGUAGE_CODE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'en-us'</span><span class="pln">

TIME_ZONE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'UTC'</span><span class="pln">

USE_I18N </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

USE_L10N </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

USE_TZ </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	عدّل <code>TIME_ZONE</code> بحيث يتم ضبطه على منطقتك الزمنية الحالية. سنستخدم المنطقة الزمنية لنيويورك في هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_77" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># Internationalization</span><span class="pln">
</span><span class="com"># https://docs.djangoproject.com/en/2.0/topics/i18n/</span><span class="pln">

LANGUAGE_CODE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'en-us'</span><span class="pln">

TIME_ZONE </span><span class="pun">=</span><span class="pln"> </span><span class="str">'America/New_York'</span><span class="pln">

USE_I18N </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	ستحتاج بعد ذلك إلى إضافة مسار لملفاتك الثابتة static files، لذا لا تغلق ملف الإعدادات الآن. يُقصد بالملفات الثابتة، الملفات المُتعلقة بتطبيقك في جانغو، وقد تكون هذه الملفات أي ملفات ضرورية لعرض صفحة الويب، مثل ملفات <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> و <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> والصور ..إلخ.
</p>

<p>
	انتقل إلى نهاية ملف settings.py وأضف <code>STATIC_ROOT</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_81" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># Static files (CSS, JavaScript, Images)</span><span class="pln">
</span><span class="com"># https://docs.djangoproject.com/en/2.0/howto/static-files/</span><span class="pln">

STATIC_URL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/static/'</span><span class="pln">
STATIC_ROOT </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'static'</span><span class="pun">)</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_83" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># SECURITY WARNING: don't run with debug turned on in production!</span><span class="pln">
DEBUG </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'your_server_IP_address'</span><span class="pun">]</span><span class="pln">

</span><span class="com"># Application definition</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	أضف بعد ذلك وحدة نظام التشغيل <code>OS</code>، التي توفّر وظائف متنوعة للمجلدات. هذه الوحدة ضرورية، فبدونها ستتلقى خطأ عند إنشاء مستخدم مُدير administrative user لكي تتمكن من استخدام واجهة جانغو Django interface من خلاله. لإنجاز ذلك عليك باستيراد وحدة <code>OS</code> التي ستعمل على نظام التشغيل الخاص بك. أضف سطر الاستيراد <code>import os</code> في أعلى ملف الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_85" style=""><span class="pun">...</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> os
</span><span class="kwd">from</span><span class="pln"> pathlib </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Path</span><span class="pln">

</span><span class="com"># Build paths inside the project like this: BASE_DIR / 'subdir'.</span><span class="pln">
</span><span class="pun">...</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_87" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># Database</span><span class="pln">
</span><span class="com"># https://docs.djangoproject.com/en/3.2/ref/settings/#databases</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'django.db.backends.sqlite3'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'NAME'</span><span class="pun">:</span><span class="pln"> BASE_DIR </span><span class="pun">/</span><span class="pln"> </span><span class="str">'db.sqlite3'</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></pre>

<p>
	استبدل خياري <code>ENGINE</code> و <code>NAME</code> في قاموس <code>DATABASES</code> بالأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_89" style=""><span class="pun">...</span><span class="pln">
</span><span class="com"># Database</span><span class="pln">
</span><span class="com"># https://docs.djangoproject.com/en/3.0/ref/settings/#databases</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'django.db.backends.mysql'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'OPTIONS'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">'read_default_file'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/etc/mysql/my.cnf'</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></pre>

<p>
	يُقصد بالسطر "ENGINE": "django.db.backends.mysql" إخبار جانغو أن يَستخدم الواجهة الخلفية لقاعدة بيانات MySQL المدمجة بينما يشير خيار<code>read_default_file</code> إلى <code>‎/etc/mysql/my.cnf</code>، وهو ملف خيارات MySQL الذي عدلناه سابقًا، وهذا يخبر جانغو أين يمكن العثور على تفاصيل الاتصال اللازمة للاتصال بقاعدة بيانات MySQL التي أنشأتها في الخطوة الأولى.
</p>

<p>
	لاحظ أن جانغو يقرأ إعدادات الاتصال بقاعدة البيانات بالترتيب التالي:
</p>

<ul>
	<li>
		الخيارات OPTIONS
	</li>
	<li>
		الاسم، المستخدم، كلمة المرور، المضيف HOST، المنفذ PORT
	</li>
	<li>
		ملفات الضبط MySQL
	</li>
</ul>

<p>
	بناءً على الترتيب السابق، وبما أنك وضعت ملف خيارات MySQL ضمن الحقل OPTIONS، فسيكون لها الأولوية في التنفيذ على الإعدادات الموجودة في الحقل NAME، وذلك لأن الأولوية تكون للإعدادات الموجودة في الحقل OPTIONS، وبعد ذلك NAME، بينما لو وضعت ملف الضبط في مكان آخر، ستكون الأولوية للإعدادات التي تم تحديدها في الحقل NAME.
</p>

<p>
	يمكنك الآن حفظ وإغلاق الملف. بعد ذلك، تحقق من تغييرات التهجير <code>migration</code> عن طريق تشغيل ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_91" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py makemigrations</span></pre>

<p>
	بعد ذلك نفّذ أمر التهجير<code>migrate</code> لضمان تنفيذ التغييرات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_93" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	الآن بعد أن تم تهجير التغييرات، يمكنك إنشاء مستخدم مُدير لكي تتمكن من استخدام واجهة مُدير جانغو. أنجز ذلك من خلال الأمر <code>Createsuperuser</code>:
</p>

<pre class="ipsCode">(env) sammy@ubuntu:$ python manage.py createsuperuser
</pre>

<p>
	سوف يطلب منك اسم مستخدم وعنوان بريد إلكتروني وكلمة مرور للمستخدم الخاص بك.
</p>

<p>
	بعد إكمال هذه المعلومات، يمكنك الانتقال إلى الخطوة السادسة.
</p>

<h2>
	الخطوة 6 - ضبط إعدادات جدار الحماية
</h2>

<p>
	قبل أن تبدأ باختبار تطبيقك، يجب أن تُنجز بعضًا من عمليات الضبط في إعدادات جدار الحماية الخاص بك. ابدأ بتغيير إعدادات جدار الحماية عبر <a href="https://academy.hsoub.com/devops/security/firewalls/%D9%83%D9%8A%D9%81-%D8%AA%D8%B6%D8%A8%D8%B7-%D8%AC%D8%AF%D8%A7%D8%B1%D8%A7-%D9%86%D8%A7%D8%B1%D9%8A%D8%A7-%D9%81%D9%8A-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ufw-r120/" rel="">UFW</a> للسماح بالوصول إلى المنفذ 8000 على الخادم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_95" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ sudo ufw allow </span><span class="lit">8000</span></pre>

<p>
	للتأكد من أنه أعطيت صلاحيات الوصول إلى المنفذ بنجاح، نفّذ الأمر <code>status</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_97" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ sudo ufw status</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_99" style=""><span class="typ">Status</span><span class="pun">:</span><span class="pln"> active

</span><span class="typ">To</span><span class="pln">                         </span><span class="typ">Action</span><span class="pln">      </span><span class="typ">From</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">OpenSSH</span><span class="pln">                    ALLOW       </span><span class="typ">Anywhere</span><span class="pln">
</span><span class="lit">8000</span><span class="pln">                       ALLOW       </span><span class="typ">Anywhere</span><span class="pln">
</span><span class="typ">OpenSSH</span><span class="pln"> </span><span class="pun">(</span><span class="pln">v6</span><span class="pun">)</span><span class="pln">               ALLOW       </span><span class="typ">Anywhere</span><span class="pln"> </span><span class="pun">(</span><span class="pln">v6</span><span class="pun">)</span><span class="pln">
</span><span class="lit">8000</span><span class="pln"> </span><span class="pun">(</span><span class="pln">v6</span><span class="pun">)</span><span class="pln">                  ALLOW       </span><span class="typ">Anywhere</span><span class="pln"> </span><span class="pun">(</span><span class="pln">v6</span><span class="pun">)</span></pre>

<p>
	كما تلاحظ في الخرج، فإن الصلاحيات تم منحها بنجاح. بهذا تكون قد انتهيت من تعديلات جدار الحماية.
</p>

<h2>
	الخطوة السابعة - اختبار اتصال قاعدة بيانات MySQL بتطبيق جانغو
</h2>

<p>
	يمكنك الآن أن تختبر فيما إذا كانت إعدادات الضبط التي أجريتها في جانغو تنجح في تحقيق الاتصال مع <a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D9%83%D9%8A%D9%81-%D8%AA%D8%B9%D8%A7%D9%84%D8%AC-%D8%A7%D9%86%D9%87%D9%8A%D8%A7%D8%B1-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-mysql-r404/" rel="">خادم MySQL</a>. يمكنك إنجاز ذلك من خلال تشغيل الخادم، فإذا فشل تشغيله، فهذا يعني أن الاتصال لا يعمل بنجاح، وإلا فإن الاتصال نجح. انتقل أولًا إلى المجلد التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_101" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">my_blog_app</span><span class="pun">/</span><span class="pln">blog</span><span class="pun">/</span></pre>

<p>
	نفّذ بعد ذلك الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_103" style=""><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	سيكون الخرج مُشابهًا للتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9603_105" style=""><span class="typ">Performing</span><span class="pln"> system checks</span><span class="pun">...</span><span class="pln">

</span><span class="typ">System</span><span class="pln"> check identified no issues </span><span class="pun">(</span><span class="lit">0</span><span class="pln"> silenced</span><span class="pun">).</span><span class="pln">
</span><span class="typ">October</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2021</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">50</span><span class="pun">:</span><span class="lit">58</span><span class="pln">
</span><span class="typ">Django</span><span class="pln"> version </span><span class="lit">3.2</span><span class="pun">.</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> using settings </span><span class="str">'blog.settings'</span><span class="pln">
</span><span class="typ">Starting</span><span class="pln"> development server at http</span><span class="pun">://</span><span class="pln">your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">
</span><span class="typ">Quit</span><span class="pln"> the server </span><span class="kwd">with</span><span class="pln"> CONTROL</span><span class="pun">-</span><span class="pln">C</span><span class="pun">.</span></pre>

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

<p>
	اتبع التعليمات الواردة في الخرج واتبع الرابط المُقترح http://your-server-ip:8000، لعرض تطبيق الويب الخاص بك والتحقق من أنه يعمل بشكل صحيح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102749" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-3-testsite01.png.490f1a67666f1c249b99802bf94b9d59.png" rel="" data-fileext="png"><img alt="django-3-testsite01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102749" data-unique="rnt7d561s" style="width: 650px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-3-testsite01.thumb.png.02a30e6e1bda14b89f88eb630e72f3fc.png"></a>
</p>

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

<p>
	عند الانتهاء من اختبار تطبيقك، اضغط على CTRL + C لإيقاف تشغيل الخادم والعودة إلى بيئة البرمجة الخاصة بك.
</p>

<p>
	للخروج بعد ذلك من بيئة بايثون الخاصة بك، يجب أن تنفّذ أمر إلغاء تنشيط البيئة:
</p>

<pre class="ipsCode">(env) sammy@ubuntu:$ deactivate
</pre>

<p>
	ستُنقل بعد ذلك إلى الموقع الافتراضي في سطر الأوامر.
</p>

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

<p>
	تعلمت في هذا المقال بناء الهيكل الأولي لمدونتك عن طريق جانغو؛ أكملت عملية تثبيت وتهيئة وتوصيل قاعدة بيانات MySQL مع تطبيق جانغو، وأضفت بعض المعلومات المهمة إلى ملف الإعدادات <code>settings.py</code> الخاص بتطبيقك، مثل توقيت منطقتك <code>TIME_ZONE</code> وتعديل قائمة <code>ALLOWED_HOSTS</code> واستيراد وحدة نظام التشغيل <code>OS</code> وبيانات اعتماد قاعدة البيانات لربط تطبيق جانغو بقاعدة بيانات MySQL، كما ضبطت إعدادات جدار الحماية لضمان إجراء الاختبار بنجاح. أصبح بإمكانك الآن البدء في تطوير النماذج وتطبيق عمليات التهجير في تطبيق جانغو الخاص بك وهذا ما سنتحدث عنه في المقال التالي.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-django-app-and-connect-it-to-a-database" rel="external nofollow">How To Create a Django App and Connect it to a Database</a> لصاحبه Jeremy Morris.
</p>

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

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%B9%D8%A7%D8%AA-%D9%88%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D8%A3%D9%88%D9%84-%D8%B9%D9%84%D9%89-django-r384/" rel="">إنشاء تطبيق الاقتراعات وكتابة العرض الأول على Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">مقدمة عن قواعد البيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1626</guid><pubDate>Wed, 20 Jul 2022 16:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x628;&#x62F;&#x621; &#x645;&#x639; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x644;&#x625;&#x646;&#x634;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x648;&#x64A;&#x628;</title><link>https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c802146f16c_--------.png.3102446fbd231905ba744b9767252ae7.png" /></p>

<p>
	<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو Django</a> هو إطار عمل يُستعمَل في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تطوير مواقع الويب</a> كُتبَ <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>

<p>
	يعتمد جانغو على النمط البنائي للبرمجيات نموذج-قالب-عرض Model-Template-View -تختصر إلى MTV- والمُستمد من النمط البنائي نموذج-عرض-متحكم model–view–controller -تختصر إلى MVC- . يتم تعريف النموذج Model على أنه مصدر مفرد ومحدد من البيانات، والعرض View على أنه عبارة عن البيانات التي يتم إظهارها للمستخدم، والقالب Template على أنه عبارة عن الآلية التي يستخدمها جانغو لتوليد صفحات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>.
</p>

<p>
	إن اعتماد جانغو على بنية نموذج-قالب-عرض تشجع على مبدأ عدم التكرار DRY programming وهو مبدأ يهدف إلى الحد من تكرار المعلومات من جميع الأنواع، وينص على أن "أي جزء في النظام ينبغي أن يكون معرّفاً في مكان واحد واضح مسؤول عن هذا الجزء".
</p>

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

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

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

<ul>
<li>
		البدء مع إطار العمل جانغو لإنشاء تطبيق ويب
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-django-models-%D9%88%D8%B1%D8%A8%D8%B7%D9%87%D8%A7-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1627/" rel="">إنشاء نماذج جانغو Django Models وربطها بقاعدة البيانات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B4%D9%8A%D8%B7-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D9%85%D8%AF%D9%8A%D8%B1-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D9%87%D8%A7-r1628/" rel="">تنشيط واجهة مدير جانغو والاتصال بها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A9-%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-views-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-r1629/" rel="">معالجة طلبات الويب عبر العروض views في تطبيق جانغو</a>
	</li>
</ul>
<h2>
	المتطلبات الأساسية
</h2>

<p>
	قبل البدء بعمليات التثبيت والتهيئة، سوف تحتاج إلى:
</p>

<ul>
<li>
		حساب مستخدم عادي مع صلاحيات sudo، مُهيّأ مسبقًا على خادم أبونتو 20.04، انظر مقال <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">التهيئة الأولية لخادم أوبونتو</a>.
	</li>
	<li>
		تثبيت بايثون 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%AA%D9%87-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1804-r709/" rel="">كيفية تثبيت بايثون 3 وإعداد بيئته البرمجية على خادم أوبنتو</a>.
	</li>
</ul>
<h2>
	الخطوة الأولى - تثبيت جانغو
</h2>

<p>
	هناك عدة طرق لتثبيت جانغو، ومدير حزم بايثون <code>pip</code> داخل بيئة افتراضية، إذ البيئة الافتراضية <a href="https://virtualenv.pypa.io" rel="external nofollow"><code>virtualenv</code></a> هي عبارة عن بيئة تطوير برمجية معزولة عما حولها، والتي تسمح لنا بتثبيت البرامج <a href="https://academy.hsoub.com/programming/python/django/%D8%AD%D8%B2%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B3%D9%87%D9%84-%D8%AA%D8%B9%D8%A7%D9%85%D9%84%D9%83-%D9%85%D8%B9-django-r656/" rel="">وحزم بايثون</a> بداخلها، وبالتالي تمنع تفاعل هذه البرامج والحزم مع البيئة العامة للخاد
</p>

<p>
	سننشئ الآن المجلد الذي سيحتوي على تطبيق جانغو بداخل المجلد الرئيسي للخادم، وذلك من خلال الأمر <code>mkdir</code>، وسنعطيه اسمًا (يمكنك وضع اسم آخر)، ثم سننتقل إليه من خلال الأمر <code>cd</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_9" style="">
<span class="pln">$ mkdir django</span><span class="pun">-</span><span class="pln">apps
$ cd django</span><span class="pun">-</span><span class="pln">apps </span></pre>

<p>
	الآن، بعد أن تنتقل إلى المجلد الذي أنشأته django-apps، أنشئ بيئتك الافتراضية، وهنا سنسميها البيئة العامة env (الاسم اختياري، لكن يُفضل أن يكون ذو معنى).
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_11" style="">
<span class="pln">$ virtualenv env</span></pre>

<p>
	إن لم تكن أداة <code>virtualenv</code> مثبتة لديك، فثبتها باتباع <a href="https://virtualenv.pypa.io/en/latest/installation.html" rel="external nofollow">توثيق خطوات التثبيت</a> من الموقع الرسمي.
</p>

<p>
	الآن، نشّط البيئة الافتراضية باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_13" style="">
<span class="pln">$ </span><span class="pun">.</span><span class="pln"> env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	في حال تغيرت البادئة في سطر الأوامر إلى <code>(env)</code>، فهذا يعني أن بيئتك تم تنشيطها، وستظهر لك في <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> مشابهةً لما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_15" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$</span></pre>

<p>
	بعد أن أصبحنا في داخل البيئة، نُثبت حزمة جانغو من خلال مُدير الحزم <code>pip</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_19" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ pip install django</span></pre>

<p>
	تحقق الآن من نجاح التثبيت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_22" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin </span><span class="pun">--</span><span class="pln">version</span></pre>

<p>
	يجب أن تحصل على خرج مُشابه للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_24" style="">
<span class="lit">3.0</span><span class="pun">.</span><span class="lit">6</span></pre>

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

<h2>
	الخطوة الثانية - ضبط إعدادات جدار الحماية
</h2>

<p>
	إذا كان لديك خادم تمت تهيئته أو كان لديك جدار حماية firewall يعمل على خادمك، فسنحتاج إلى فتح المنفذ الذي سنستخدمه في جدار الحماية الخاص بخادمنا. بالنسبة لجدار حماية UFW، يمكنك فتح المنفذ بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_26" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ sudo ufw allow </span><span class="lit">8000</span></pre>

<p>
	لمزيد من التفاصيل، انظر مقال <a href="https://academy.hsoub.com/devops/security/firewalls/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-ufw-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D9%88%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r121/" rel="">أساسيات UFW: قواعد وأوامر شائعة للجدار الناري</a>.
</p>

<p>
	إذا كنت تستخدم جدران حماية DigitalOcean، فيمكنك اختيار <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">بروتوكول HTTP</a> من قواعد جدار الحماية الداخلي Inbound firewall rules (تحدد قواعد جدار الحماية الداخلي حركة المرور المسموح بها للخادم على أي منافذ ومن أي مصادر).
</p>

<h2>
	الخطوة الثالثة - بدء المشروع
</h2>

<p>
	بإمكانك الآن إنشاء تطبيق باستخدام مُدير-جانغو <code>django-admin</code> وهو أمر يُستخدَم لإنجاز المهام الإدارية في بايثون، ثم يمكنك استخدام الأمر <code>startproject</code> لإنشاء بنية مجلد المشروع من أجل موقع الويب الذي سنُنشئه.
</p>

<p>
	نفّذ الأمر التالي (اسم المشروع <code>testsite</code> اختياري) داخل مجلد django-apps:
</p>

<pre class="ipsCode">
 (env) sammy@ubuntu:$ django-admin startproject testsite
</pre>

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

<p>
	بعد ذلك يمكنك الإطلاع على ملفات المشروع التي تم إنشاؤها من خلال الانتقال إلى مجلد المشروع <code>testsite</code>، ثم تنفيذ الأمر <code>ls</code> لعرض قائمة الملفات الموجودة فيه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_29" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd testsite
</span><span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ ls</span></pre>

<p>
	الخرج:
</p>

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

<p>
	ستلاحظ أن المجلد يحتوي على ملف الإدارة manage.py، والثاني هو مجلد باسم testsite يشبه ملف الإدارة ملف مُدير- جانغو، إذ أنه يضع حزمة المشروع في متغير البيئة <code>sys.path</code>. يؤدي ذلك أيضًا إلى تحديد متغير البيئة <code>DJANGO_SETTINGS_MODULE</code> للإشارة إلى ملف الإعدادات settings.py الخاص بالمشروع.
</p>

<p>
	يمكنك استعراض محتويات ملف الإدارة في الطرفية terminal عن طريق استخدام الأمر <code>less</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_33" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ less manage</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	عندما تنتهي من الاطلاع عليه، اضغظ على المفتاح <code>q</code> لإنهاء عرض الملف.
</p>

<p>
	بعد ذلك انتقل إلى مجلد testsite لرؤية الملفات التي تم إنشاؤها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_35" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ cd testsite</span><span class="pun">/</span></pre>

<p>
	نفذ الآن الأمر <code>ls</code> لعرض قائمة الملفات الموجودة في المجلد الحالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_38" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$ ls</span></pre>

<p>
	سترى أربعة ملفات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_40" style="">
<span class="pln">__init__</span><span class="pun">.</span><span class="pln">py  asgi</span><span class="pun">.</span><span class="pln">py  settings</span><span class="pun">.</span><span class="pln">py  urls</span><span class="pun">.</span><span class="pln">py  wsgi</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	سنتحدث الآن عن كل ملف من هذه الملفات:
</p>

<ul>
<li>
		ملف التهيئة ‎<strong>init</strong>.py: تمثل نقطة الدخول لمشروع بايثون الخاص بك.
	</li>
	<li>
		ملف <code>asgi.py</code>: يحتوي على إعدادات التهيئة للنشر الاختياري optional deployment لواجهة بوابة الخادم غير المتزامن Asynchronous Server Gateway Interface (تختصر إلى ASGI)، ويعتبر معيارًا للتطبيقات التي تكون متزامنة أو غير متزامنة.
	</li>
	<li>
		ملف الإعدادات settings.py: يحتوي على جميع قيم التهيئة التي يحتاجها تطبيق الويب الخاص بك لكي يعمل، مثل إعدادات قاعدة البيانات، وإعدادات التسجيل logging، ومكان العثور على الملفات الثابتة static files، ومفاتيح <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel="">واجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> إذا كنت تعمل مع إحداها …إلخ. ويتيح لجانغو معرفة هذه الإعدادات.
	</li>
	<li>
		ملف العناوين urls.py: يمكن تشبيه هذا الملف بدفتر عناوين لموقع الويب الخاص بك، حيث يخزن كل عناوين الويب لموقعك، ويربطها بعروض views أو أي ملف urls-conf آخر لتطبيق معين.
	</li>
	<li>
		ملف wsgi.py: يحتوي على تهيئة واجهة بوابة خادم الويب Web Server Gateway Interface (تختصر إلى WSGI)، والذي يعتبر معيارًا لتطبيقات بايثون المتزامنة.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: بإمكانك تعديل ملفات asgi.py أو wsgi.py في أي وقت لتناسب احتياجات النشر الخاصة بك.
		</p>
	</div>
</blockquote>

<p>
	الآن، يمكنك استخدام أمر التهجير <code>migrate</code> مع ملف manage.py لتهجير قاعدة البيانات (في هذا المثال نستخدم SQLite)، إذ يُطبق التهجير أي تغييرات أجريتها في نماذج جانغو على مخطط قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_43" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<h2>
	الخطوة الرابعة - ضبط إعدادات جانغو
</h2>

<p>
	يمكنك الآن تشغيل الخادم وعرض موقع الويب على مضيف معين ومنفذ من خلال تنفيذ الأمر <code>runserver</code>. ستحتاج إلى إضافة عنوان IP للخادم الخاص بك إلى قائمة <code>ALLOWED_HOSTS</code> في ملف الإعدادات settings.py.
</p>

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

<p>
	يمكنك استخدام أي محرر نصوص تُفضله لإضافة عنوان IP الخاص بك. مثلًا، إذا كنت تستخدم المحرر نانو nano، يمكنك تنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_46" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$  nano </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">apps</span><span class="pun">/</span><span class="pln">testsite</span><span class="pun">/</span><span class="pln">testsite</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_48" style="">
<span class="str">"""
Django settings for testsite project.

Generated by 'django-admin startproject' using Django 2.0.
...
"""</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="com"># SECURITY WARNING: don't run with debug turned on in production!</span><span class="pln">
DEBUG </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">

</span><span class="com"># Edit the line below with your server IP address</span><span class="pln">
ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'your-server-ip'</span><span class="pun">]</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	يمكنك حفظ التغيير والخروج من المحرر nano بالضغط مع الاستمرار على الاختصار CTRL + x ثم الضغط على الزر y. بعد ذلك، سنتمكن لاحقًا من الوصول إلى تطبيق الويب الخاص بنا عبر المتصفح.
</p>

<p>
	الآن، سننشئ مُستخدمًا بصفة مُدير (مسؤول) administrative user، لكي تتمكن من استخدام واجهة المُدير admin interface وسننجز ذلك من خلال الأمر <code>createuperuser</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_50" style="">
<span class="pln"> </span><span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $  python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

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

<h2>
	الخطوة الخامسة - الوصول إلى تطبيق الويب
</h2>

<p>
	بعد الانتهاء من التهيئة، انتقل إلى المجلد الذي يوجد فيه ملف الإدارة manager.py:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_52" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$  cd </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">apps</span><span class="pun">/</span><span class="pln">testsite</span><span class="pun">/</span></pre>

<p>
	بعد ذلك، نفذ الأمر التالي (استبدل "server-ip text" بعنوان IP الخادم الخاص بك):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_54" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$  python manage</span><span class="pun">.</span><span class="pln">py runserver your</span><span class="pun">-</span><span class="pln">server</span><span class="pun">-</span><span class="pln">ip</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	بعد ذلك، يمكنك الانتقال إلى الرابط التالي لمعرفة الشكل الذي يبدو عليه موقعك (لا تنسى استبدال "server-ip text" بعنوان IP الخادم الخاص بك).
</p>

<pre class="ipsCode">
http://your-server-ip:8000/
</pre>

<p>
	<b>و</b>إن كنت تعمل محليًا على حاسوبك، فيمكنك تشغيل الخادم للعمل محليًا بتمرير رقم المنفذ فقط بالشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_63" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">8000</span></pre>

<p>
	وبذلك، يمكنك الانتقال إلى العنوان localhost:8000 أو http://127.0.0.1:8000 للوصول للتطبيق من أي متصفح على حاسوبك.
</p>

<p>
	بعد تحميل الصفحة، سترى ما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102746" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-3-testsite01.png.d403a2adebf04b05ebae2498e47de122.png" rel=""><img alt="django-3-testsite01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102746" data-unique="2amzzsbw2" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-3-testsite01.thumb.png.bb69f14e3ec0b9f43a32623a6a3f2f6e.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	هذا يؤكد أنه تم تثبيت جانغو بنجاح وأن مشروع الاختبار لدينا يعمل بنجاح.
</p>

<p>
	للوصول إلى واجهة المُدير admin interface، أضف <code>/admin/</code> إلى نهاية عنوان URL الخاص بك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_57" style="">
<span class="pln">http</span><span class="pun">://</span><span class="pln">your_server_ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span><span class="pln">
</span><span class="pun">أو</span><span class="pln">
http</span><span class="pun">://</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span></pre>

<p>
	بالتالي سيتم نقلك إلى شاشة تسجيل الدخول:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102747" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login.png.a79bd5e14e7fe5f5ea5d078ccdb203d6.png" rel=""><img alt="django-admin-login.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102747" data-unique="wwmgmvavx" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login.thumb.png.ce75ddaef9c90c7bda2c1e6c92ced8ed.png" style="width: 650px; height: auto;"></a>
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102748" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel.png.0a47c6ccc51f77a0fc8955b5122a28b6.png" rel=""><img alt="django-admin-panel.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102748" data-unique="7bca6wcyl" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel.thumb.png.1d39ca9ed1dae993cb6aa14104f55a22.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	عند الانتهاء من اختبار التطبيق، يمكنك الضغط على CTRL + C لإيقاف تنفيذ الأمر <code>runserver</code>.
</p>

<p>
	وأخيرًا للخروج من بيئة بايثون التي أنشأتها، يجب عليك إلغاء تنشيطها من خلال أمر <code>deactivate</code>.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4231_68" style="">
<span class="pun">(</span><span class="pln">env</span><span class="pun">)</span><span class="pln"> sammy@ubuntu</span><span class="pun">:</span><span class="pln">$  deactivate</span></pre>

<p>
	سيؤدي إلغاء تنشيط البيئة إلى إعادتك إلى الموقع الافتراضي في الطرفية.
</p>

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-django-and-set-up-a-development-environment-on-ubuntu-20-04" rel="external nofollow">How To Install Django and Set Up a Development Environment on Ubuntu 20.04</a> لصاحبه Lisa Tagliaferri.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AE%D8%B5%D9%8A%D8%B5-%D9%84%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D9%81%D9%82%D8%A9-%D9%85%D8%B9-django-r479/" rel="">تخصيص لوحة التحكم المرفقة مع Django</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/" rel="">تثبيت إطار العمل جانغو على أوبنتو </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1625</guid><pubDate>Sun, 17 Jul 2022 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648;</title><link>https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r1624/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62c7f8dead1c7_------.png.d99697feb7fc9ac50fdb87242a4acaa5.png" /></p>

<p>
	<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">جانغو Django</a> هو إطار عمل ويب في <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> مجاني ومفتوح المصدر ويستخدم في <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">تطوير مواقع الويب</a> أُصدرَ في شهر تموز من عام 2005، وهو مشهور ببُنيته المُعتمدة على المكونات، إذ تُركز على تحليل التصميم إلى مكونات وظيفية أو منطقية مُفردة (استقلالية المكونات) مما يجعل التطبيقات أكثر مرونة وقابلية للتوسع والنمو وإعادة الاستخدام كما أنه يتسم بسرعة التطوير المعززة بميزات أمان مُدمجة.
</p>

<p>
	يعتمد جانغو على النمط البنائي للبرمجيات نموذج-قالب-عرض Model-Template-View -تختصر إلى MTV- والمُستمد من النمط البنائي نموذج-عرض-متحكم model–view–controller -تختصر إلى MVC- . يتم تعريف النموذج Model على أنه مصدر مفرد ومحدد من البيانات، والعرض View على أنه عبارة عن البيانات التي يتم إظهارها للمستخدم، والقالب Template على أنه عبارة عن الآلية التي يستخدمها جانغو لتوليد صفحات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>.
</p>

<p>
	إن اعتماد جانغو على بنية نموذج-قالب-عرض تشجع على مبدأ عدم التكرار DRY programming وهو مبدأ يهدف إلى الحد من تكرار المعلومات من جميع الأنواع، وينص على أن "أي جزء في النظام ينبغي أن يكون معرّفاً في مكان واحد واضح مسؤول عن هذا الجزء".
</p>

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

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

<p>
	حساب مستخدم عادي بصلاحيات sudo <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">مُهيّأ مسبقًا على خادم أبونتو 20.04</a>.
</p>

<h2>
	تثبيت جانغو
</h2>

<p>
	بإمكانك تثبيت جانغو بطرق مختلفة وفقًا لاحتياجاتك والطريقة التي تريد بها تهيئة بيئة التطوير.
</p>

<h3>
	1. تثبيت عام من خلال الحزم
</h3>

<p>
	مستودعات أبونتو الرسمية تحتوي على حزم جانغو التي يمكن تثبيتها باستخدام <a href="https://academy.hsoub.com/devops/linux/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-apt-%D8%8Cyum-%D8%8Cdnf-%D8%8Cpkg-r231/" rel="">أداة الحزم المتقدمة APT package manager</a>. تعتبر هذه الطريقة بسيطة، لكنها غير مرنة كباقي الطرق، كما أن الإصدار الموجود في المستودعات ربما يكون مختلفًا عن الإصدارات الرسمية المتوفرة. الآن، سنتحدث عن كيفية تثبيت جانغو باستخدام هذه الطريقة.
</p>

<p>
	أولاً، يجب تحديث فهرس الحزمة المحليّة لديك local package index باستخدام <code>apt</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_8" style="">
<span class="pln">$ sudo apt update</span></pre>

<p>
	الآن تحقق من إصدار بايثون الذي ثبَّته، مع ملاحظة أن الإصدار 3.8 من <a href="https://wiki.hsoub.com/Python" rel="external">بايثون </a>يكون افتراضيًا متوفرًا في الإصدار 20.04 من أبونتو وما فوق. عمومًا، يمكنك التحقق من إصدار بايثون المُثبت على جهازك عن طريق كتابة الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_10" style="">
<span class="pln">$ python </span><span class="pun">-</span><span class="pln">V</span></pre>

<p>
	يجب أن يكون الخرج مُشابه للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_14" style="">
<span class="typ">Python</span><span class="pln"> </span><span class="lit">3.8</span><span class="pun">.</span><span class="lit">2</span></pre>

<p>
	الآن نثبت جانغو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_16" style="">
<span class="pln">$ sudo apt install python3</span><span class="pun">-</span><span class="pln">django</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_18" style="">
<span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin </span><span class="pun">--</span><span class="pln">version</span></pre>

<p>
	يجب أن يكون الخرج مُشابهًا للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_20" style="">
<span class="lit">2.2</span><span class="pun">.</span><span class="lit">12</span></pre>

<p>
	هذا يعني أن عملية التثبيت تمت بنجاح، وربما تلاحظ أيضًا أن إصدار جانغو الذي حصلت عليه ليس أحدث إصدار مستقر stable version.
</p>

<h3>
	2. تثبيت جانغو باستخدام مدير حزم بايثون pip ضمن بيئة افتراضية
</h3>

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

<p>
	سنبيّن الآن كيفية تثبيت جانغو ضمن بيئة افتراضية سننشئها باستخدام الأداة venv وهي أداة تأتي مثبتة افتراضيًّا مع <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-modules-%D9%88%D8%A7%D9%84%D8%AD%D8%B2%D9%85-packages-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r329/" rel="">حزمة بايثون</a>. تمكنك هذه الأداة من إنشاء بيئات بايثون افتراضية، وتثبيت حزم بايثون دون التأثير على باقي أجزاء النظام (بأمان)، لذلك يمكنك اختيار حزم بايثون بإصدارات محددة لكل مشروع، بصرف النظر عن التعارضات التي قد تحدث مع متطلبات المشاريع الأخرى.
</p>

<p>
	أولاً، يجب تحديث فهرس الحزمة المحليّة لديك local package index باستخدام <code>apt</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_24" style="">
<span class="pln">$ sudo apt update</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_26" style="">
<span class="pln">$ python </span><span class="pun">-</span><span class="pln">V</span></pre>

<p>
	يجب أن يكون الخرج مُشابه للخرج التالي:
</p>

<pre class="ipsCode">
Python 3.8.2
</pre>

<p>
	بعد ذلك، نثبت <code>pip</code> و <code>venv</code> من مستودعات أبونتو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_28" style="">
<span class="pln">$ sudo apt install python3</span><span class="pun">-</span><span class="pln">pip python3</span><span class="pun">-</span><span class="pln">venv</span></pre>

<p>
	الآن، عندما تبدأ مشروعًا جديدًا، يمكنك إنشاء بيئة افتراضية له. ابدأ بإنشاء مجلد للمشروع الجديد وانتقل إليه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_31" style="">
<span class="pln">$ mkdir </span><span class="pun">~/</span><span class="pln">newproject
$ cd </span><span class="pun">~/</span><span class="pln">newproject</span></pre>

<p>
	بعد ذلك، أنشئ بيئة افتراضية داخل مجلد المشروع باستخدام أمر بايثون المتوافق مع اصدار بايثون المُثبت لديك. سنطلق على بيئتنا الافتراضية اسم my_env، ويُفضل دومًا أن تسميها اسمًا يَصِفَها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_33" style="">
<span class="pln">$ python </span><span class="pun">-</span><span class="pln">m venv my_env</span></pre>

<p>
	بعد ذلك، سيتم تثبيت إصدارات مستقلة من بايثون ومدير الحزم <code>pip</code> ضمن بنية مجلد معزولة isolated directory structure (طريقة لإظهار الملفات بشكل معين، وتظهر الملفات بشكل شجري هرمي) داخل مجلد مشروعك. سيتم إنشاء مجلد بالاسم الذي تحدده، والذي يحتوي على التسلسل الهرمي للملفات في المكان الذي سيتم فيه تثبيت الحزم الخاصة بك.
</p>

<p>
	لتثبيت الحزم ضمن البيئة المعزولة التي أنشأناها، يجب تنشيطها عن طريق كتابة الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_38" style="">
<span class="pln">$ source my_env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	يُفترض آنذاك أن يتغير موجه <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a> لديك ليشير إلى بيئتك الافتراضية، أي يجب أن يكون مشابه لهذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_35" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">username@hostname</span><span class="pun">:~/</span><span class="pln">newproject$</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_44" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ pip install </span><span class="typ">Django</span></pre>

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

<pre class="ipsCode">
(my_env) $ django-admin --version
3.0.8
</pre>

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

<p>
	أخيرًا لمغادرة البيئة الافتراضية، يجب أن تُلغي تنشيط البيئة الافتراضية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_46" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ deactivate</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_48" style="">
<span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">newproject
$ source my_env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<h3>
	3. تثبيت أحدث إصدار من جانغو من خلال جيت git
</h3>

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

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

<p>
	أولاً، نُحدث فهرس الحزمة المحلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_50" style="">
<span class="pln">$ sudo apt update</span></pre>

<p>
	تحقق الآن من إصدار بايثون المُثبَّت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_52" style="">
<span class="pln">$ python </span><span class="pun">-</span><span class="pln">V</span></pre>

<p>
	يجب أن يكون الخرج مُشابه للخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_55" style="">
<span class="typ">Python</span><span class="pln"> </span><span class="lit">3.8</span><span class="pun">.</span><span class="lit">2</span></pre>

<p>
	ثم ثبّت <code>pip</code> و <code>venv</code> من المستودعات الرسمية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_57" style="">
<span class="pln">$ sudo apt install python3</span><span class="pun">-</span><span class="pln">pip python3</span><span class="pun">-</span><span class="pln">venv</span></pre>

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

<p>
	يمكنك نسخ المستودع إلى مجلد يُسمى <code>‎~/django-dev</code> داخل المجلد الرئيسي <code>home</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_59" style="">
<span class="pln">$git clone git</span><span class="pun">://</span><span class="pln">github</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">django</span><span class="pun">/</span><span class="pln">django </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">dev</span></pre>

<p>
	الآن انتقل إلى هذا المجلد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_62" style="">
<span class="pln">$ cd </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">dev</span></pre>

<p>
	أنشئ بيئة افتراضية باستخدام أمر بايثون المتوافق مع إصدار بايثون المثبَّت لديك:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_64" style="">
<span class="pln">$ python3 </span><span class="pun">-</span><span class="pln">m venv my_env</span></pre>

<p>
	ثم نشطها بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_66" style="">
<span class="pln">$ source my_env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	الآن، يمكنك تثبيت المستودع باستخدام <code>pip</code>، وكما تلاحظ استخدمنا الراية <code>e-</code>، لكي تتم عملية التثبيت مع صلاحية قابلية التعديل editable، وهذا ضروري عندما نُنجز عملية التثبيت من جيت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_68" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ pip install </span><span class="pun">-</span><span class="pln">e </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">dev</span></pre>

<p>
	كما هي العادة، تحقق من نجاح التثبيت:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_71" style="">
<span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin </span><span class="pun">--</span><span class="pln">version
</span><span class="lit">3.2</span></pre>

<h2>
	إنشاء أول مشروع لك
</h2>

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

<p>
	بدايًة، أنشئ مجلد مشروعك، وانتقل إليه.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_75" style="">
<span class="pln">$mkdir </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">test
$cd </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">test</span></pre>

<p>
	ثم أنشئ بيئتك الافتراضية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_77" style="">
<span class="pln">$ python3 </span><span class="pun">-</span><span class="pln">m venv my_env</span></pre>

<p>
	ونشطها بالأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_79" style="">
<span class="pln">$ source my_env</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	ثبت جانغو:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_81" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ pip install django</span></pre>

<p>
	الآن، يمكنك استخدام <code>django-admin</code> لبناء مشروعك مع استخدام الأمر <code>startproject</code>، سنسمي المشروع djangoproject، لكن يمكنك اختيار أي اسم تريده. سيُنشئ الأمر <code>startproject</code> مجلدً داخل مجلد العمل الحالي لديك، والذي يتضمن:
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_83" style="">
<span class="pun">(</span><span class="pln">my _env</span><span class="pun">)</span><span class="pln">$ django</span><span class="pun">-</span><span class="pln">admin startproject djangoproject </span><span class="pun">.</span></pre>

<p>
	الآن، يمكنك استخدام أمر التهجير <code>migrate</code> مع ملف <code>manage.py</code> لتهجير قاعدة البيانات (في هذا المثال نستخدم SQLite)، إذ يُطبق التهجير أي تغييرات أجريتها في نماذج جانغو على مخطط قاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_85" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ python manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	ستشاهد خرجًا يشبه الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_87" style="">
<span class="typ">Operations</span><span class="pln"> to perform</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Apply</span><span class="pln"> all migrations</span><span class="pun">:</span><span class="pln"> admin</span><span class="pun">,</span><span class="pln"> auth</span><span class="pun">,</span><span class="pln"> contenttypes</span><span class="pun">,</span><span class="pln"> sessions
</span><span class="typ">Running</span><span class="pln"> migrations</span><span class="pun">:</span><span class="pln">
  </span><span class="typ">Applying</span><span class="pln"> contenttypes</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> admin</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> admin</span><span class="pun">.</span><span class="lit">0002</span><span class="pln">_logentry_remove_auto_add</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> admin</span><span class="pun">.</span><span class="lit">0003</span><span class="pln">_logentry_add_action_flag_choices</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> contenttypes</span><span class="pun">.</span><span class="lit">0002</span><span class="pln">_remove_content_type_name</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0002</span><span class="pln">_alter_permission_name_max_length</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0003</span><span class="pln">_alter_user_email_max_length</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0004</span><span class="pln">_alter_user_username_opts</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0005</span><span class="pln">_alter_user_last_login_null</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0006</span><span class="pln">_require_contenttypes_0002</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0007</span><span class="pln">_alter_validators_add_error_messages</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0008</span><span class="pln">_alter_user_username_max_length</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> auth</span><span class="pun">.</span><span class="lit">0009</span><span class="pln">_alter_user_last_name_max_length</span><span class="pun">...</span><span class="pln"> OK
  </span><span class="typ">Applying</span><span class="pln"> sessions</span><span class="pun">.</span><span class="lit">0001</span><span class="pln">_initial</span><span class="pun">...</span><span class="pln"> OK</span></pre>

<p>
	وأخيرًا، نُنشئ مُستخدم مدير (مسؤول) administrative user لتتمكن من استخدام واجهة مدير جانغو Django admin interface، من خلال الأمر <code>createsuperuser</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_89" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

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

<h2>
	تعديل قائمة ALLOWED_HOSTS في ملف إعدادات جانغو
</h2>

<p>
	لاختبار تطبيقك بنجاح، ستحتاج إلى تعديل أحد التوجيهات directives في إعدادات جانغو. افتح ملف الإعدادات من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_91" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ nano </span><span class="pun">~/</span><span class="pln">django</span><span class="pun">-</span><span class="pln">test</span><span class="pun">/</span><span class="pln">djangoproject</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

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

<p>
	إذًا ضمن القائمة <code>ALLOWED_HOSTS</code> حدِّد عناوين IP أو أسماء النطاقات المرتبطة مع خادم جانغو الخاص بك، وضع كل واحدٍ منهم ضمن علامتي اقتباس، وافصل بين كل واحدة بفاصلة. أخيرًا، إذا كنت تريد السماح بطلبات لنطاق بأكمله أو لأي نطاق جزئي، فأضف نقطة في بدايته.
</p>

<p>
	تذكر أن <code>ALLOWED_HOST</code> موجود ضمن الملف <code>settings.py</code> وفي مثالنا هو موجود في المسار:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_93" style="">
<span class="pln">ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'your_server_ip_or_domain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'your_second_ip_or_domain'</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></pre>

<p>
	عندما تنتهي احفظ الملف وأغلق المحرر.
</p>

<h2>
	اختبار خادم التطوير
</h2>

<p>
	يكفي أن يكون لديك حساب مستخدم، حتى تتمكن من تشغيل خادم تطوير جانغو development server لترى كيف تعمل الأمور في مشروعك، كما يجب أن تدرك أن استخدامه يجب أن يكون فقط لأغراض التطوير. أخيرًا، عندما تكون جاهزًا لنشر مشروعك، تأكد من اتباع إرشادات جانغو من <a href="https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/" rel="external nofollow">توثيقه</a> الرسمي، وذلك لضمان نشره بطريقة سليمة.
</p>

<p>
	قبل استخدام خادم التطوير، تأكد من فتح المنفذ المناسب في جدار الحماية firewall الخاص بك.
</p>

<p>
	إذا اتبعت دليل إعداد الخادم الأولي وكنت تستخدم <a href="https://academy.hsoub.com/devops/security/firewalls/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-ufw-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D9%88%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r121/" rel="">UFW</a>، فيمكنك فتح المنفذ 8000 من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_96" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln"> $ sudo ufw allow </span><span class="lit">8000</span></pre>

<p>
	لمزيد من التفاصيل انظر مقال <a href="https://academy.hsoub.com/devops/security/firewalls/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-ufw-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D9%88%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r121" rel="">أساسيات UFW: قواعد وأوامر شائعة للجدار الناري</a>.
</p>

<p>
	شغّل خادم التطوير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_98" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver your_server_ip</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	الآن، ضمن متصفح الويب، حاول الانتقال إلى الخادم الخاص بك من خلال عنوان IP المربوط به، متبوعًا بالمنفذ 8000.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_100" style="">
<span class="pln">http</span><span class="pun">://</span><span class="pln">your_server_ip</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	إن كنت تعمل محليًا على حاسوبك، فيمكنك تشغيل الخادم للعمل محليًا بتمرير رقم المنفذ فقط بالشكل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_102" style="">
<span class="pun">(</span><span class="pln">my_env</span><span class="pun">)</span><span class="pln">$ python manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">8000</span></pre>

<p>
	وبذلك، يمكنك الانتقال إلى العنوان localhost:8000 أو http://127.0.0.1:8000.
</p>

<p>
	يجب أن ترى شيئًا يشبه هذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102745" href="https://academy.hsoub.com/uploads/monthly_2022_07/django_landing_page_00.png.963d544dcbf1fd667f44d77d4e86b27e.png" rel=""><img alt="django_landing_page_00.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102745" data-unique="sza88gg52" src="https://academy.hsoub.com/uploads/monthly_2022_07/django_landing_page_00.thumb.png.8e5161a7c74041ac68106eda75c105b2.png" style="width: 600px; height: auto;"></a>
</p>

<p>
	للوصول إلى واجهة المُدير admin interface، أضف <code>/admin/</code> إلى نهاية <a href="https://academy.hsoub.com/devops/security/firewalls/%D9%85%D8%A7-%D9%87%D9%88-%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-%D9%88%D9%83%D9%8A%D9%81-%D9%8A%D8%B9%D9%85%D9%84%D8%9F-r114/" rel="">عنوان URL</a> الخاص بك.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_8896_106" style="">
<span class="pln">http</span><span class="pun">://</span><span class="pln">your_server_ip</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span><span class="pln">
</span><span class="pun">أو</span><span class="pln">
http</span><span class="pun">://</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">8000</span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span></pre>

<p>
	سينقلك ذلك إلى شاشة تسجيل الدخول:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102743" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login_01.png.7438dd7f9fa2e405baaa579d37e3f08d.png" rel=""><img alt="django-admin-login_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102743" data-unique="odgu62xgt" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-login_01.thumb.png.c673170c9f9701ca4826966ce0970e25.png" style="width: 650px; height: auto;"></a>
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="102744" href="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel_02.png.7b3265e8d741a42e2d15ad9aa96ad940.png" rel=""><img alt="django-admin-panel_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="102744" data-unique="gmltzc3ui" src="https://academy.hsoub.com/uploads/monthly_2022_07/django-admin-panel_02.thumb.png.7737c48d4b28ef0c8ec411c10c93e602.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	عندما تنتهي من الاطلاع على الموقع الافتراضي، يمكنك إيقاف خادم التطوير من خلال الضغط على الاختصار CTRL-C في الطرفية terminal.
</p>

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

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

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

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

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-the-django-web-framework-on-ubuntu-20-04" rel="external nofollow">How To Install the Django Web Framework on Ubuntu 20.04</a> لصاحبه Brian Boucheron.
</p>

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

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django-%D9%88%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%AA%D9%87-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-ubuntu-1604-r643/" rel="">تنصيب إطار العمل Django وتهيئة بيئته البرمجية على Ubuntu 16.04</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">مدخل إلى إطار العمل Django </a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%AD%D8%B2%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B3%D9%87%D9%84-%D8%AA%D8%B9%D8%A7%D9%85%D9%84%D9%83-%D9%85%D8%B9-django-r656/" rel="">حزم بايثون الثمانية التي تسهل تعاملك مع Django</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1624</guid><pubDate>Thu, 14 Jul 2022 16:04:00 +0000</pubDate></item><item><title>&#x62D;&#x632;&#x645; &#x628;&#x627;&#x64A;&#x62B;&#x648;&#x646; &#x627;&#x644;&#x62B;&#x645;&#x627;&#x646;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x64A; &#x62A;&#x633;&#x647;&#x644; &#x62A;&#x639;&#x627;&#x645;&#x644;&#x643; &#x645;&#x639; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%AD%D8%B2%D9%85-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-%D8%A7%D9%84%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B3%D9%87%D9%84-%D8%AA%D8%B9%D8%A7%D9%85%D9%84%D9%83-%D9%85%D8%B9-django-r656/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_01/django.png.321901a5e9a14cf6ae6121ed3bae74b7.png" /></p>

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

<p>
	سنتكلم في هذا المثال عن ستة حزم لبرامج Django واثنين لهيكلية Django REST، حيث تظهر هذه الحزم في غالبية المشاريع التي نعمل عليها.
</p>

<h2>
	إضافات جانغو الموفرة للوقت: Django-extensions
</h2>

<p>
	تعتبر Django-extensions من الحزم المليئة بالأدوات المفيدة مثل أوامر الإدارة التالية:
</p>

<ul>
<li>
		shell_plus: تفتح Django shell مع جميع النماذج الخاصة بقاعدة البيانات والمُحمَّلة بشكل مُسبق، وبالتالي لاتحتاج إلى عمل أي استيراد من التطبيقات المختلفة والتي تحتاجها لعمل اختبار لعلاقة معقدة
	</li>
	<li>
		clean_pyc: تعمل على محي جميع المشاريع ذات اللاحقة .pyc في جميع الأماكن التي تظهر بها داخل مسار المشروع.
	</li>
	<li>
		create_tamplate_tags: تنشئ بنية مجلد خاص بالقوالب داخل التطبيق الذي تحدده.
	</li>
	<li>
		describe_form: تظهر تعريف الواجهة للنموذج ويمكن نسخه فيما بعد إلى forms.py (ولكن من المهم الانتباه إلى أن هذا الأمر ينشئ واجهة جانغو عادية وليست من نوع ModelForm).
	</li>
	<li>
		notes: يظهر هذا الأمر جميع التعليقات من نوع  TODO أو FIXME وغيرها خلال المشروع.
	</li>
	<li>
		كما تحوي حزمة Django-extensions على أصناف مجردة مفيدة تستخدم للنماذج الشائعة، حيث تستطيع توريث هذه الأصناف الأساسية عند إنشاء نماذج خاصة بك:
	</li>
	<li>
		TimeStampeModel: يحوي هذه الصنف على حقول created و modified بالإضافة للتابع ()save الذي يحدث هذه الحقول تلقائيًّا.
	</li>
	<li>
		ActivatorModel: في حال كان النموذج الخاص بك يحتاج إلى حقول مثل activate_state، status و deactivate_date عندها يمكنك استخدام هذا الصنف حيث أنه يحوي أيضًا على مدير يوفر لك استعلامات ()active. و ()inactive.
	</li>
	<li>
		TitleSlugDescriptionModel و TitleDescriptionModel: يحوي الصنفان على حقول title، description كما يحوي الصنف الأول على حقل إضافي هو slug الذي يُحدَّث  تلقائيًّا بالاعتماد على حقل title.
	</li>
</ul>
<h2>
	حزمة Django-environ
</h2>

<p>
	تتيح Django-environ تطبيق المنهجية 12-factor app لإدارة إعداداتك في مشروع جانغو الذي تنشئه، وتجمع هذه الحزمة مكتبات أخرى مثل envparse و honcho
</p>

<p>
	والآن وبعد تحميلك لحزمة Django-environ تستطيع إنشاء ملف .env في جذر مشروعك وتعرف في داخله متغيرات الإعدادات التي من الممكن أن تتغير بين البيئات أو التي يجب أن تبقى سرية مثل مفاتيح <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> أو حالة Debug أو عناوين قاعدة البيانات.
</p>

<p>
	بعد ذلك في الملف الخاص بإعدادات المشروع setting.py يمكنك عمل استيراد للبيئة ثم ضبط المتغيرات المتعلقة بـ ()environ.PATH و ()environ.Env  كما ورد في المثال.
</p>

<p>
	مع العلم أنه يمكن الوصول إلى المتغيرات المُعرّفة في ملف .env باستخدام (’env(‘VARIABLE_NAME
</p>

<h2>
	إنشاء أوامر الإدارة: Django-click
</h2>

<p>
	أُنشِئت حزمة Django-click بالاعتماد على حزمة click وهي تساعدك لكتابة أوامر الإدارة جانغو، لكن لاتمتلك هذه الحزمة الكثير من التوثيقات وإنما لديها مجلد من الأوامر التجريبية test commands.
</p>

<p>
	لنتعرف على طريقة كتابة الأمر Hello World باستخدام هذه الحزمة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" style="">
<span class="com"># app_name.management.commands.hello.py</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> djclick </span><span class="kwd">as</span><span class="pln"> click

</span><span class="lit">@click</span><span class="pun">.</span><span class="pln">command</span><span class="pun">()</span><span class="pln">
</span><span class="lit">@click</span><span class="pun">.</span><span class="pln">argument</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> command</span><span class="pun">(</span><span class="pln">name</span><span class="pun">):</span><span class="pln">
    click</span><span class="pun">.</span><span class="pln">secho</span><span class="pun">(</span><span class="pln">f</span><span class="str">'Hello, {name}'</span><span class="pun">)</span></pre>

<p>
	ثم نكتب سطر التشغيل الذي يعطي أمر التنفيذ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" style="">
<span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="pun">./</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py hello </span><span class="typ">Lacey</span><span class="pln">
</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Lacey</span>
</pre>

<h2>
	التعامل مع آلة ذات حالات منتهية : Django-fsm
</h2>

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

<p>
	توفر Django-fsm مايدعى FSMField والذي يستخدم كصفة التي تعرف حالة النموذج وبعد ذلك تستطيع استخدام transition@ من هذه الحزمة من أجل تعريف التوابع التي تحرك النموذج من حالة إلى أخرى وللتعامل مع أي تأثيرات جانبية لذلك الانتقال.
</p>

<p>
	وعلى الرغم من أن حزمة Django-fsm لا تملك توثيقات التي تعرفها بشكل جيد ولكن تحوي workflows(states) in Django الذي يمكن أن يعتبر مقدمة جيدة لتعريف مفهومي آلة ذات حالات منتهية وحزمة django-fsm.
</p>

<h2>
	استمارات التواصل: #django-contact-form
</h2>

<p>
	إن استمارات التواصل أمر أساسي يتواجد في مواقع الويب، ولكن لا داع لتكتب ترميزها بنفسك إذ يمكن إنشاؤها بدقائق من خلال استخدام الحزمة django-contact-form والتي يأتي معه صنف اختياري spam-filtering contact form (و صنف نظامي، و non-filtering) بالإضافة إلى صنف ContactFormView الذي يحوي على توابع يمكن تخصيصها وإعادة كتابتها وذلك لإنشاء النموذج الخاص بك.
</p>

<h2>
	تسجيل واستيثاق المستخدمين: django-allauth
</h2>

<p>
	إن Django-allauth هو برنامج يوفر الواجهات، والروابط لتسجيل المستخدمين، ولتسجيل الدخول والخروج، وإعادة تعيين كلمات السر و استيثاق المستخدمين مع مواقع خارجية مثل GitHub و Twitter. كما أنه يدعم الاستيثاق عن طريق email-as-username وهو مُوثَّق بشكل كبير، لأنه قد يكون مربك قليلًا التعامل معه لأول مرة لذلك يمكنك اتباع تعليمات التثبيت (installation instructions)بحرص، ومن الممكن أن تفيدك أيضًا مقالة تخصيص إعداداتك
</p>

<p>
	(customize your setting) للتأكد من أنك قد استخدمت كل الإعدادات التي تحتاجها لتفعيل ميزة محددة.
</p>

<h2>
	التعامل مع استيثاق المستخدمين ضمن هيكيلية REST Framework: django-rest-auth
</h2>

<p>
	في حال كان عملك كمطور جانغو يتطلب منك كتابة تطبيقات APIs فإنك على الأرجح تستخدم هيكلية Django REST Framework (DRF)، وعلى الأغلب تعاملت مع حزمة django-rest-auth وهي حزمة تمكننا من تسجيل المستخدمين، تسجيل عمليات الدخول والخروج، إعادة تعيين كلمات المرور، استيثاق وسائل التواصل الاجتماعي (وذلك من خلال إضافة django-allauth والتي تعمل بشكل جيد مع django-rest-auth).
</p>

<h2>
	تطبيقات الإظهار ضمن هيكلية Django REST Framework <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>: django-rest-swagger
</h2>

<p>
	يوفر Django REST Swagger واجهة تعامل بالميزات للتفاعل مع Django REST Framework <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>، فبعد تثبيت Django REST Swagger وإضافته للبرنامج المثبت مسبقًا يمكنك إضافة Swagger View بالإضافة إلى نمط عنوان URL pattern للملف ruls.py الخاص بـواجهتك البرمجية.
</p>

<p>
	<img alt="1 (1).png" class="ipsImage ipsImage_thumbnailed" data-fileid="28789" data-unique="xjj6wfou1" src="https://academy.hsoub.com/uploads/monthly_2019_01/5c4ef15ece4b3_1(1).png.d7dfcdff5f6ce72dda564c9964165941.png"></p>

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

<p>
	ترجمة –وبتصرّف– للمقال 8 <a href="https://opensource.com/article/18/9/django-packages" rel="external nofollow">Python packages that will simplify your life with Django</a>  لصاحبيه Lacey Williams Henschel و Jeff Triplett
</p>
]]></description><guid isPermaLink="false">656</guid><pubDate>Tue, 26 Feb 2019 11:08:00 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x635;&#x64A;&#x628; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Django &#x648;&#x62A;&#x647;&#x64A;&#x626;&#x629; &#x628;&#x64A;&#x626;&#x62A;&#x647; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x639;&#x644;&#x649; Ubuntu 16.04</title><link>https://academy.hsoub.com/programming/python/django/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django-%D9%88%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A8%D9%8A%D8%A6%D8%AA%D9%87-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-ubuntu-1604-r643/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_09/11111.png.747d89fe430435f0abaf347493704c8b.png" /></p>

<h3>
	مقدمة:
</h3>

<p>
	إن Django هو عبارة عن إطار عمل برمجي مفتوح المصدر لتطوير تطبيقات الويب مكتوب بلغة البرمجة Python، ويقوم على النمط البنائي للبرمجيات model template view (MTV) أي النموذج-القالب-العرض، والمُستمد من النمط البنائي <a href="https://ar.wikipedia.org/wiki/%D9%86%D9%85%D8%B7_%D9%88%D8%B9%D8%B1%D8%B6_%D9%88%D9%85%D8%AA%D8%AD%D9%83%D9%85" rel="external nofollow">model–view–controller</a> (MVC) أي النمط والعرض والمتحكم. حيث قامت مؤسسة إطار العمل Django البرمجية بتعريف النمط model على أنه مصدر مفرد ومحدد من البيانات، والعرض view على أنه عبارة عن البيانات التي يتم إظهارها للمستخدم والناتجة عن استدعاء دالة لغة البرمجة Python الخاصة بالاستجابة لطلب العناوين الالكترونية URL، والقالب على أنه عبارة عن الآلية التي يستخدمها Django لتوليد صفحات HTML.
</p>

<p>
	إن مبادئ إطار العمل البرمجي Django هي: قابلية التوسُّع وإعادة الاستخدام وسرعة التطوير، كما يمتاز بالتماسك واستقلالية مكوناته عن بعضها. أي أن إطار العمل Django يقوم على المبدأ البرمجي لا تكرر نفسك <a href="https://ar.wikipedia.org/wiki/%D9%84%D8%A7_%D8%AA%D9%83%D8%B1%D8%B1_%D9%86%D9%81%D8%B3%D9%83" rel="external nofollow">DRY programming</a> .
</p>

<p>
	سنشرح في هذه المقالة طريقة تهيئة البيئة البرمجية لإطار العمل Django، كما سيتم شرح طريقة تنصيب Python 3 وpip 3 وDjango وvirtualenv لتزويدك بالأدوات الضرورية لتطوير تطبيقات الويب باستخدام إطار العمل Django.
</p>

<h3>
	المتطلبات:
</h3>

<p>
	حساب مستخدم عادي (غير جذر "root") بصلاحيات <u>sudo</u> مُهيّأ مسبقًا على خادم لينكس Debian أو Ubuntu.
</p>

<h3>
	الخطوة الأولى- تنصيب Python ومدير الحزم pip:
</h3>

<p>
	قبل البدء بتنصيب لغة البرمجة Python، يجب القيام بتحديث نظام التشغيل عن طريق تنفيذ الأمر التالي في موجه أوامر لينكس:
</p>

<pre class="ipsCode" id="ips_uid_3083_14">
sudo apt-get update &amp;&amp;  sudo apt-get -y upgrade</pre>

<p>
	حيث تم استخدم العلم -y من أجل تأكيد موافقتنا على تنصيب جميع البرامج والحزم البرمجية المحدَّثة (كي لا نقوم بتأكيد الموافقة يدويًا أثناء عملية التحديث). وعند السؤال عن إعداد grub-pc نضغط المفتاح ENTER لقبول الإعدادات الافتراضية، أو نُعدّه كما نريد.
</p>

<p>
	تنصح مؤسسة إطار العمل Django البرمجية باستخدام الإصدار Python 3 من لغة البرمجة Python، لذا بعد انتهاء عملية تحديث النظام سنقوم بتنصيب Python 3، وذلك بتنفيذ الأمر التالي في موجه أوامر لينكس:
</p>

<pre class="ipsCode" id="ips_uid_3083_16">
sudo apt-get install python3</pre>

<p>
	وللتأكّد من أنه تم تنصيب Python 3 بنجاح، ننفذ أمر عرض إصدارها في موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_18">
python3 –V</pre>

<p>
	فنحصل على الخرج التالي في نافذة موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_20">
Output
Python 3.5.2</pre>

<p>
	بعد تنصيب Python 3، سنقوم بتنصيب الأداة pip الخاصة بإدارة وتنصيب حزم Python البرمجية، وذلك بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_3083_22">
sudo apt-get install -y python3-pip</pre>

<p>
	وللتأكد من نجاح عملية تنصيب الأداة pip، ننفذ أمر عرض إصدارها في موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_24">
pip –V</pre>

<p>
	فنحصل على الخرج التالي في نافذة موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_26">
Output
pip 8.1.1 from /usr/lib/python3/dist-packages (python 3.5)
</pre>

<p>
	الآن وبعد أن تم الانتهاء من تنصيب أداة تنصيب وإدارة الحزم pip، نستطيع استخدامها لتنصيب الحزم الضرورية لبيئة Python البرمجية.
</p>

<h3>
	الخطوة الثانية- تنصيب البيئة الافتراضية Virtualenv
</h3>

<p>
	البيئة الافتراضية virtualenv هي عبارة عن بيئة تطوير برمجية معزولة عما حولها، والتي تسمح لنا بتنصيب البرامج وحزم Python بشكل مضمَّن فيها، وبالتالي تمنع تفاعل هذه البرامج والحزم مع البيئة العامة للخادم. هذا ويتم تنصيب البيئة الافتراضية باستخدام أداة تنصيب وإدارة الحزم كما يلي: 
</p>

<pre class="ipsCode" id="ips_uid_3083_28">
pip3 install virtualenv</pre>

<p>
	وللتأكد من أنه تم تنصيب virtualenv بنجاح، ننفذ أمر عرض إصدارها كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_32">
virtualenv –-version</pre>

<p>
	فنحصل على الخرج التالي في نافذة موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_35">
Output
15.1.0</pre>

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

<h3>
	الخطوة الثالثة- تنصيب إطار العمل البرمجي Django:
</h3>

<p>
	هناك ثلاث طرق لتنصيب إطار العمل البرمجي Django هي:<br>
	 
</p>

<ul>
<li>
		الخيار الأول: تنصيب إطار Django ضمن البيئة الافتراضية virtualenv. وتعد هذه الطريقة مثالية عند الرغبة بعزل Django عن بيئة الخادم العامة.
	</li>
	<li>
		الخيار الثاني: تنصيب إطار Django من المصدر، تُستخدم هذه الطريقة عند الرغبة بتنصيب آخر إصدار Django مباشرةً من مصدره، في حال لم يتوفرا في مخزن Ubuntu APT. غير أن طريقة التّنصيب هذه تتطلب الانتباه والترقية المستمرة عند الرغبة بالمحافظة على Django محدثًا بشكل مستمر.
	</li>
	<li>
		الخيار الثالث: تنصيب إطار Django بشكل عام باستخدام أداة تنصيب الحزم pip.
	</li>
</ul>
<p>
	سنستخدم في هذه المقالة الخيار الثالث في تنصيب إطار العمل Django ضمن البيئة الافتراضية، لكن علينا في البّداية إنشاء مجلد جديد باسم<br>
	django-apps (أو أي اسم آخر) ضمن المسار home على الخّادم، من أجل احتواء تطبيق Django الخّاص بنا، وذلك بتنفيذ الأوامر التالية في موجه أوامر النّظام:
</p>

<pre class="ipsCode" id="ips_uid_3083_37">
mkdir django-apps
cd django-apps</pre>

<p>
	ثم نقوم بإنشاء بيئتنا الافتراضية باسم env ضمن المجلد django-apps، وذلك بتنفيذ الأمر التالي في موجه أوامر النظام:  
</p>

<pre class="ipsCode" id="ips_uid_3083_39">
virtualenv env</pre>

<p>
	ثم نقوم بتفعيل بيئتنا الافتراضية env، وذلك بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_3083_41">
. env/bin/activate</pre>

<p>
	فيتحول موجه الأوامر من النظام إلى البيئة الافتراضية كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_43">
(env) sammy@ubuntu:$</pre>

<p>
	والآن سنقوم بتنصيب django ضمن البيئة الافتراضية env، عن طريق الأداة pip كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_45">
(env) sammy@ubuntu:$ pip install django</pre>

<p>
	وللتأكد من أنه تم تنصيب إطار العمل django بنجاح، ننفذ أمر عرض إصداره كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_47">
(env) sammy@ubuntu:$ django-admin –-version</pre>

<p>
	فنحصل على الخرج التالي في نافذة موجه الأوامر:
</p>

<pre class="ipsCode" id="ips_uid_3083_49">
Output
2.0.1</pre>

<p>
	الآن وبعد أن تم تنصيب إطار العمل django بنجاح، نستطيع الانتقال لإنشاء مشروع تجريبي للتأكد من أن كل شيء يعمل بشكل سليم.
</p>

<h3>
	الخطوة الرابعة- إنشاء مشروع تجريبي بإطار العمل Django:
</h3>

<p>
	سنقوم باختبار إطار العمل البرمجي Django المُنصَّب من خلال إنشاء هيكل تطبيق الويب.
</p>

<h4>
	ضبط إعدادات جدار الحماية:
</h4>

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

<pre class="ipsCode" id="ips_uid_3083_51">
(env) sammy@ubuntu:$ sudo ufw allow 8000</pre>

<p>
	وفي حال كُنت تَستخدم جدار حماية DigitalOcean، قم باختيار HTTP من بين قواعد دخل جدار الحماية.
</p>

<h4>
	بدء المشروع:
</h4>

<p>
	نستطيع الآن توليد مشروع جديد عن طريق الأداة django-admin والمستخدمة في إدارة المهام في Python، وذلك باستخدام الأمر startproject من أجل إنشاء بنية مسار المشروع (الملفات والمجلدات الأساسية) لموقع الويب التجريبي، وذلك كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_53">
(env) sammy@ubuntu:$ django-admin startproject testsite</pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: يؤدي تنفيذ الأمر السابق إلى تسمية مسار وحزمة المشروع بنفس الاسم والذي هو testsite، كما يقوم بإنشاء المشروع في نفس مسار تنفيذ الأمر، أما إذا أردنا إنشاء المشروع في مسار آخر فإنه يجب علينا إضافة هذا المسار إلى الأمر السابق بعد اسم المشروع، حيث يقوم Django بإنشاء الملف manage.py وحزمة المشروع في المسار المُحدد.  
		</p>
	</div>
</blockquote>

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

<pre class="ipsCode" id="ips_uid_3083_59">
(env) sammy@ubuntu:$ cd testsite
</pre>

<pre class="ipsCode" id="ips_uid_3083_71">
(env) sammy@ubuntu:$ ls</pre>

<pre class="ipsCode" id="ips_uid_3083_69">
Output
manage.py  testsite
</pre>

<p>
	نلاحظ أن هذا المسار يحتوي على الملف manage.py والمجلد testsite. إن الملف manage.py مشابه للأداة django-admin حيث يقوم بوضع حزمة المشروع في sys.path، كما يقوم بإعداد متغيرات البيئة ل DJANGO_SETTINGS_MODULE بحيث تشير إلى ملف المشروع settings.py. هذا ويمكن عرض محتويات الملف manage.py باستخدام الأمر less كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_3083_73">
(env) sammy@ubuntu:$ less manage.py</pre>

<p>
	وعند الانتهاء من قراءته نضغط المفتاح q للخروج منه.
</p>

<p>
	والآن سننتقل إلى المجلد testsite لتصفح باقي الملفات التي تم إنشائها وذلك بتنفيذ الأوامر التالية:
</p>

<pre class="ipsCode" id="ips_uid_3083_75">
(env) sammy@ubuntu:$ cd testsite/
(env) sammy@ubuntu:$ ls

Output
__init__.py  settings.py  urls.py  wsgi.py</pre>

<p>
	نلاحظ أنه يحتوي على مجموعة من الملفات هي:
</p>

<ul>
<li>
		<strong>__init__.py:</strong> يلعب هذا الملف كنقطة دخول إلى مشروع Python.
	</li>
	<li>
		<strong>settings.py:</strong> يصف هذا الملف إعدادات الإطار Django الذي تم تنصيبه، كما يسمح للإطار Django بمعرفة الخيارات المتاحة.
	</li>
	<li>
		<strong>urls.py:</strong> ويتضمن هذا الملف على اللائحة urlpatterns والتي تُستخدم لتوجيه العناوين الالكترونية URLs إلى العروض الموافقة لها views.
	</li>
	<li>
		<strong>wsgi.py:</strong> ويتضمن على إعدادات واجهة مدخل خادم الويبWeb Server Gateway Interface (WSGI)، والتي هي منصة Python القياسية المستخدمة في نشر خوادم وتطبيقات الويب على استضافة الويب.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة:</strong> لا يزال لديك القدرة بعد الانتهاء من إنشاء ملفات المشروع الافتراضية، في التعديل على الملف wsgi.py وذلك في أي وقت تريد فيه نشر تطبيقك على استضافة الويب.  
		</p>
	</div>
</blockquote>

<h4>
	بدء وعرض موقع الويب الذي تم إنشائه:
</h4>

<p>
	نستطيع الآن تشغيل الخادم runserver وعرض الموقع على المضيف والمنفذ المخصص، وذلك بتنفيذ الأمر:
</p>

<pre class="ipsCode" id="ips_uid_3083_77">
(env) sammy@ubuntu:$ runserver</pre>

<p>
	يجب إضافة عنوان IP الخادم إلى لائحة ALLOWED_HOSTS ضمن الملف settings.py الموجود في المسار: ~/test_django_app/testsite/testsite/.<br>
	يتضمن المتغير ALLOWED_HOSTS لائحة من السلاسل النصية التي تمثل أسماء المضيف والنطاق host/domain التي يستطيع Django خدمتها، حيث تم وضع معيار الأمان هذا لمنع اختراقات الترويسة والتي يمكن أن تتم حتى ولو تم مراعاة الكثير من إعدادات الأمان لخادم الويب.<br>
	يمكنك استخدم أي محرر نصوص من أجل إضافة عنوان IP الخادم الخاص بك إلى الملف settings.py، فمثلا يمكنك استخدام محرر نصوص موجه الأوامر nano بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_3083_79">
(env) sammy@ubuntu:$ nano ~/django-apps/testsite/testsite/settings.py</pre>

<p>
	فبعد أن يُفتح الملف عليك الانتقال إلى قسم ALLOWED_HOSTS ثم إضافة عنوان IP الخادم الخاص بك ضمن القوسين وبين علامة أو علامتي تنصيص كما هو موضح في الملف التالي:
</p>

<p style="text-align: center;">
	<img alt="settings.py" class="ipsImage ipsImage_thumbnailed" data-fileid="28142" data-unique="eq0fu4lol" src="https://academy.hsoub.com/uploads/monthly_2018_09/Screenshot_2.jpg.337cf7aad55afc2f7a157515d790be60.jpg" style="width: 747px; height: auto;"></p>

<p>
	ثم قم بحفظ التعديل وإنهاء المحرر nano وذلك بالضغط على المفاتيح CONTROL وX ثم ضغط المفتاح y (نعم) عند سؤال المحرر عن الرغبة بحفظ التعديلات على الملف، ثم العودة إلى مسار المشروع بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_3083_83">

(env) sammy@ubuntu:$ cd ~/django-apps/testsite/</pre>

<p>
	بعد العودة لمسار المشروع، ننفذ الأمر التالي بعد استبدال your-server-ip بعنوان IP الخادم الذي قمنا بتخصيصه في الخطوة السابقة:
</p>

<pre class="ipsCode" id="ips_uid_3083_85">
(env) sammy@ubuntu:$ python3 manage.py runserver your-server-ip:8000</pre>

<p>
	ثم نقوم بإدخال العنوان http://your-server-ip:8000/ طبعاً بعد استبدال your-server-ip بعنوان IP الخادم، في المتصفح من أجل عرض موقع الويب التجريبي الذي قمنا بإنشائه فيظهر كما يلي:<br><a class="ipsAttachLink ipsAttachLink_image" data-fileid="28143" href="https://academy.hsoub.com/uploads/monthly_2018_09/django-2-testsite.png.b297c6a8518e16fa0e8112c750220d99.png" rel=""><img alt="django-2-testsite.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28143" data-unique="fa1bhw9ls" src="https://academy.hsoub.com/uploads/monthly_2018_09/django-2-testsite.thumb.png.fdb8eb0f98e279cf0edfefae71fe6b3a.png"></a>
</p>

<p>
	وهذا يؤكد على أنه تم تنصيب إطار العمل البرمجي Django بشكل صحيح، وعلى أن مشروعنا التجريبي يعمل بشكل صحيح أيضًا.
</p>

<p>
	بعد الانتهاء من تصفح الموقع نقوم بإيقاف الأمر runserver وذلك بالضغط على المفاتيح CTRL وC، فنعود إلى موجه أوامر بيئتنا الافتراضية.
</p>

<p>
	ثم نقوم بالخروج من البيئة الافتراضية والرجوع إلى موجه أوامر النظام وذلك بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_3083_89">

(env) sammy@ubuntu:$ deactivate</pre>

<h3>
	ملخص:
</h3>

<p>
	تم في هذه المقالة شرح طريقة تحديث Python 3 لآخر إصدار لها من مخزن Ubuntu APT، كما تم شرح طريقة تنصيب أداة تنصيب وإدارة الحزم pip 3، والبيئة الافتراضية virtualenv، والإطار البرمجي Django.
</p>

<p>
	 
</p>

<p>
	ترجمة بتصرف للمقال:  [<a href="https://www.digitalocean.com/community/tutorials/how-to-install-django-and-set-up-a-development-environment-on-ubuntu-16-04" rel="external nofollow">How To Install Django and Set Up a Development Environment on Ubuntu 16.04</a>] لصاحبه Jeremy Morris
</p>
]]></description><guid isPermaLink="false">643</guid><pubDate>Sat, 22 Sep 2018 14:08:00 +0000</pubDate></item><item><title>&#x62A;&#x62E;&#x635;&#x64A;&#x635; &#x644;&#x648;&#x62D;&#x629; &#x627;&#x644;&#x62A;&#x62D;&#x643;&#x645; &#x627;&#x644;&#x645;&#x631;&#x641;&#x642;&#x629; &#x645;&#x639; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%AA%D8%AE%D8%B5%D9%8A%D8%B5-%D9%84%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D8%A7%D9%84%D9%85%D8%B1%D9%81%D9%82%D8%A9-%D9%85%D8%B9-django-r479/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.61599466fbff95d565ffbed4720ddd4e.png" /></p>

<p id="تخصيص-لوحة-التحكم-المرفقة-مع-django">
	وصلنا إلى ختام هذه السلسلة وفي الدرس الأخير منها سنتحدث عن لوحة التحكم التي يقدّمها إطار العمل Django بشكل جاهز مع كل مشروع تقوم بإنشائه، ويمكن الاستفادة من لوحة التحكم هذه في إدارة النماذج Models المستخدمة في المشروع إضافة إلى إدارة مجموعات المستخدمين وصلاحياتهم في إجراء التعديلات على الموقع اﻹلكتروني.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23158" data-unique="ar4whmmfz" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.462c16446ce8da65c0ec25120376eb6c.png"></p>

<h2 id="الولوج-إلى-لوحة-التحكم">
	الولوج إلى لوحة التحكم
</h2>

<p>
	لنستعرض المسارات الموجودة في ملف <code>mysite/urls.py</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<span class="pln">urlpatterns </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">r</span><span class="str">'^admin/'</span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^polls/'</span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="pln">polls_urls</span><span class="pun">)),</span><span class="pln">
</span><span class="pun">]</span></pre>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs cs"><span class="pln">http</span><span class="pun">:</span><span class="hljs-comment"><span class="com">//127.0.0.1:8000/admin</span></span></code></pre>

<p>
	ستظهر الشاشة التالية:
</p>

<p style="text-align: center;">
	<img alt="pic-001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23140" data-unique="91jge39oa" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-001.png.d94eb10f4e6223dad6f7c48875685995.png"></p>

<p>
	ما تراه على متصفحك هو صفحة الولوج log-in إلى لوحة التحكم الخاصة بالمشروع، ومن الواضح أننا نحتاج إلى اسم مستخدم وكلمة مرور لنتمكن من الدخول إلى لوحة التحكم. لإنشاء حساب مستخدم يمكنه الولوج إلى لوحة التحكم توجّه إلى سطر اﻷوامر ونفذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs avrasm"><span class="pln">python manage</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">py</span></span><span class="pln"> createsuperuser</span></code></pre>

<p>
	سيُطلب منك إدخال اسم المستخدم، ويمكنك استخدام الاسم الذي ترغب به:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs http"><span class="hljs-attribute"><span class="typ">Username</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="pln">admin</span></span></code></pre>

<p>
	ثم سيُطلب منك إدخال عنوان بريدك اﻹلكتروني:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs ruby"><span class="hljs-constant"><span class="typ">Email</span></span><span class="pln"> </span><span class="hljs-symbol"><span class="pln">address</span><span class="pun">:</span></span><span class="pln"> admin</span><span class="hljs-variable"><span class="pln">@example</span></span><span class="pun">.</span><span class="pln">com</span></code></pre>

<p>
	والخطوة اﻷخيرة هي إدخال كلمة المرور مرتين:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs markdown"><span class="typ">Password</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-strong"><span class="pun">*****</span></span><span class="hljs-strong"><span class="pun">*****</span></span><span class="pln">
</span><span class="typ">Password</span><span class="pln"> </span><span class="pun">(</span><span class="pln">again</span><span class="pun">):</span><span class="pln"> </span><span class="hljs-strong"><span class="pun">*****</span></span><span class="hljs-strong"><span class="pun">*****</span></span><span class="pln">
</span><span class="typ">Superuser</span><span class="pln"> created successfully</span><span class="pun">.</span></code></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23141" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-002.png.3d2ab803f9c8b4eef361dc86ed81c652.png" rel=""><img alt="pic-002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23141" data-unique="k1birz4ki" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-002.thumb.png.37774cee8f03fc5f7ed260352a6f1421.png"></a>
</p>

<p>
	نلاحظ في هذه الصفحة إمكانية تعديل بعض اﻷمور الخاصة بالمستخدمين ومجموعات المستخدمين، ولكن لا نرى ذكرًا لتطبيقنا على اﻹطلاق. سنحتاج في الواقع إلى القيام بخطوة إضافية، وهي إخبار لوحة التحكم بأنّ عناصر الصنف <code>Question</code> في ملف النماذج <code>models.py</code> تمتلك واجهة لوحة تحكم، وللقيام بذلك توجّه إلى ملف <code>polls/admin.py</code> وأضف إليه اﻷسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs avrasm"><span class="kwd">from</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">models</span></span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">

admin</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">site</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">register</span></span><span class="pun">(</span><span class="typ">Question</span><span class="pun">)</span></code></pre>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23142" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-003.png.5a7313d0cd225fff048c90f072bf7abf.png" rel=""><img alt="pic-003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23142" data-unique="wyl8lnv06" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-003.thumb.png.52dc3e2d016bb14d22edb755e85ef287.png"></a>
</p>

<p>
	ﻻحظ أن Django قادر على تمييز أسماء النماذج واستخلاص أسماء ذات مدلولات أوضح بالنسبة للمستخدم، فقد تعرّف Django في مثالنا هذا على النموذج Question باعتباره نموذجًا يحتوي على عدد من العناصر المتمثلة باﻷسئلة، لذا أضاف (s) الجمع إلى الاسم المعروض في لوحة التحكم.
</p>

<p>
	واﻵن انقر على <code>Questions</code> وسترى قائمة باﻷسئلة التي أضفناها برمجيًا إلى النموذج <code>Question</code> في الدروس السابقة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23143" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-004.png.bfcf7422aa1ad8d4a0dc1437af66af0d.png" rel=""><img alt="pic-004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23143" data-unique="j53levrmy" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-004.thumb.png.81c8ebaa1a47523f841a978edc4ba82a.png"></a>
</p>

<p>
	يمكنك كذلك النقر على نص السؤال لتتمكن من تعديله أو حذفه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23144" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-005.png.9ea78ad75b7db73e6ad0ad8ba67ef677.png" rel=""><img alt="pic-005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23144" data-unique="pfx3cd6f5" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-005.thumb.png.ef16c2242ac6d6a10ffe6f1efaa45759.png"></a>
</p>

<p>
	ﻻحظ كيف أن Django قد قام بإنشاء استمارة Form خاصة بالسؤال تتضمن جميع الحقول التي أضفناها في الصنف <code>Question</code> في الملف <code>polls/models.py</code>، إضافة إلى ذلك، يستخدم Django عناصر HTML المناسبة لكل نوع من أنواع الحقول. كذلك يضيف Django بعض شيفرات Javascript مع كل حقل من نوع <code>DateTimeField</code> لاختيار الوقت والتاريخ حسب الحاجة.
</p>

<h2 id="تخصيص-لوحة-التحكم">
	تخصيص لوحة التحكم
</h2>

<p>
	رأينا كيف قام Django ببناء لوحة التحكم والاستمارات الخاصة بالنموذج <code>Question</code> بشكل آلي، ولكن سنحتاج غالبًا إلى تخصيص مظهر لوحة التحكم وآلية عملها، ويمكننا القيام بذلك عند تسجيل النموذج في ملف <code>polls/admin.py</code>؛ لذا توجّه إلى هذا الملف وعدّله بالشكل اﻵتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> admin

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Question</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">QuestionAdmin</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">ModelAdmin</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">]</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="kwd">register</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> </span><span class="typ">QuestionAdmin</span><span class="pun">)</span></code></pre>

<p>
	عرفنا في الشيفرة السابقة صنف <code>model admin</code> وقمنا بتمريره كمعامل ثانٍ للدالة <code>register()</code>. ستعمل هذه الشيفرة على تبديل مواقع حقلي تاريخ نشر السؤال ونص السؤال، ليحل أحدهما محل اﻵخر:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23145" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-006.png.bd89893e459c6cd78c72586ab7decf4e.png" rel=""><img alt="pic-006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23145" data-unique="7vcskp0lm" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-006.thumb.png.1eb60fe19e805a0d22d78fbf48df74c3.png"></a>
</p>

<p>
	يمكن كذلك تقسيم الحقول إلى مجموعات <code>fieldsets</code> وذلك بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> admin

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Question</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">QuestionAdmin</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">ModelAdmin</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    fieldsets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-keyword"><span class="kwd">None</span></span><span class="pun">,</span><span class="pln">               </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">]}),</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date information'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">]}),</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="kwd">register</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> </span><span class="typ">QuestionAdmin</span><span class="pun">)</span></code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23146" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-007.png.30faff3cd49abb89c07770c143b07062.png" rel=""><img alt="pic-007.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23146" data-unique="eqf4xv8ud" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-007.thumb.png.5c9da65e97333d0a2a2b7464f0f5f05c.png"></a>
</p>

<h3 id="التعامل-مع-الاختيارات-المرتبطة-بالسؤال">
	التعامل مع الاختيارات المرتبطة بالسؤال؟
</h3>

<p>
	لم نتعامل لحدّ اﻵن مع الاختيارات المرتبطة باﻷسئلة في تطبيق الاقتراعات، وفي الواقع هنا طريقتان للقيام بذلك:<br>
	الطريقة اﻷولى هي اتباع نفس الخطوات التي قمنا باتباعها في تسجيل الصنف Question وذلك بتعديل ملف <code>polls/admin.py</code> ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs avrasm"><span class="kwd">from</span><span class="pln"> </span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">models</span></span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">
</span><span class="hljs-preprocessor"><span class="com"># ...</span></span><span class="pln">
admin</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">site</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">register</span></span><span class="pun">(</span><span class="typ">Choice</span><span class="pun">)</span></code></pre>

<p>
	قمنا في هذا الشيفرة باستيراد الصنف <code>Choice</code> إضافة إلى الصنف <code>Question</code>، بعد ذلك سجّلنا الصنف <code>Choice</code> باستخدام الدالة <code>register()</code>. واﻵن ستظهر الصفحة الرئيسية للوحة التحكم بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23147" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-008.png.b874816d07ade779f198940f12af774a.png" rel=""><img alt="pic-008.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23147" data-unique="v01ugdede" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-008.thumb.png.d12ad4233c2ee64b716c0d02259f6a93.png"></a>
</p>

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

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23148" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-009.png.232275e07a60141d4c30e1d4944adb63.png" rel=""><img alt="pic-009.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23148" data-unique="jz28pdtcy" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-009.thumb.png.a2848ef782c6e0ef8ee46df86f04873f.png"></a>
</p>

<p>
	ﻻحظ أنّه يمكنك اختيار السؤال الذي تودّ ربط الاختيار به وذلك من القائمة المنسدلة المعنونة بـ Question، كما يمكنك إضافة سؤال جديد من هذه الصفحة وذلك بالضغط على علامة (+) الخضراء إلى جانب القائمة المنسدلة، أو تحرير السؤال الذي اخترته بالضغط على أيقونة القلم اﻷصفر.
</p>

<p>
	لا تبدو هذه الطريقة مفيدة من الناحية العملية، إذ يجب إضافة السؤال الجديد، ثم إضافة الاختيارات وربطها واحدًا تلو اﻵخر بالسؤال.
</p>

<p>
	إذًا، أليس من اﻷفضل أن نقوم بإضافة الاختيارات مباشرة عند إضافة السؤال؟ هذه هي الطريقة الثانية.
</p>

<p>
	للقيام بذلك توجّه إلى ملف <code>polls/admin.py</code> ثم عدّله ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> admin

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Question</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">ChoiceInline</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">StackedInline</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Choice</span><span class="pln">
    extra </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">3</span></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">QuestionAdmin</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">ModelAdmin</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    fieldsets </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-keyword"><span class="kwd">None</span></span><span class="pun">,</span><span class="pln">               </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">]}),</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date information'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">],</span><span class="pln"> </span><span class="hljs-string"><span class="str">'classes'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'collapse'</span></span><span class="pun">]}),</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
    inlines </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="typ">ChoiceInline</span><span class="pun">]</span><span class="pln">

admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="kwd">register</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> </span><span class="typ">QuestionAdmin</span><span class="pun">)</span></code></pre>

<p>
	تخبر الشيفرة السابقة Django بأن الاختيارات يتم تحريرها في صفحة التحكم بالسؤال، إضافة إلى تقديم الحقول اللازمة ﻹضافة 3 اختيارات مع كل سؤال. بناء على ذلك ستظهر صفحة إضافة سؤال جديد بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23149" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-010.png.5b2043691f6678f3f6deb3bfa8adbfd5.png" rel=""><img alt="pic-010.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23149" data-unique="funel1d1m" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-010.thumb.png.f7814607e8dabdf163ce6a540c49df15.png"></a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs haskell"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-type"><span class="typ">ChoiceInline</span></span><span class="hljs-container"><span class="pun">(</span><span class="hljs-title"><span class="pln">admin</span></span><span class="pun">.</span><span class="hljs-type"><span class="typ">TabularInline</span></span><span class="pun">)</span></span><span class="pun">:</span></span></code></pre>

<p>
	ستظهر صفحة إضافة سؤال جديد بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23150" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-011.png.d381494574a46e70c38e1a93d2b812e1.png" rel=""><img alt="pic-011.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23150" data-unique="j5j98ah63" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-011.thumb.png.9806948eddd4948a05e719f40426fd37.png"></a>
</p>

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

<p>
	في البداية تظهر هذه الصفحة بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23151" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-012.png.b2d9eaec15bd88209d75915f17121cca.png" rel=""><img alt="pic-012.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23151" data-unique="ech630fyv" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-012.thumb.png.d581e8fc81f747ef6e13bfd34431f155.png"></a>
</p>

<p>
	يستخدم Django بصورة افتراضية مخرجات دالة <code>str()</code> لكل حقل من حقول قاعدة البيانات التي يتم عرضها في الصفحة الرئيسية، ولكننا بحاجة هنا إلى عرض جميع الحقول وليس حقل نصّ السؤال فقط. وللقيام بذلك نستخدم الصف <code>list_display</code> والذي سنضمنه أسماء الحقول التي نرغب في عرضها على شكل أعمدة في الصفحة الرئيسية. توجّه إلى ملف <code>polls/admin.py</code> وعدّل الصنف <code>QuestionAdmin</code> لصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs python"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">QuestionAdmin</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">admin</span><span class="pun">.</span><span class="typ">ModelAdmin</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    fieldsets </span><span class="pun">=[</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-keyword"><span class="kwd">None</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">]}),</span><span class="pln">
        </span><span class="pun">(</span><span class="hljs-string"><span class="str">'Date information'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'fields'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">],</span><span class="pln"> </span><span class="hljs-string"><span class="str">'classes'</span></span><span class="pun">:</span><span class="pln">
            </span><span class="pun">[</span><span class="hljs-string"><span class="str">'collapse'</span></span><span class="pun">]}),</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
    inlines </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="typ">ChoiceInline</span><span class="pun">]</span><span class="pln">
    list_display </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'was_published_recently'</span></span><span class="pun">)</span></code></pre>

<p>
	واﻵن يفترض أن تظهر الصفحة الرئيسية بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23152" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-013.png.30f4fdca538560b7ad2f3a96c772699d.png" rel=""><img alt="pic-013.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23152" data-unique="4izuwnkay" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-013.thumb.png.18a567e2ac592feaaeea4ba585ee7e67.png"></a>
</p>

<p>
	ﻻحظ أن Django قام بتسمية العمود اﻷخير بنفس اسم التابع المستخدم في النموذج <code>Question</code> مع استبدال الشرطات السفلية بفواصل، ويمكننا تغيير هذا الاسم وتحسين طريقة عرض المخرجات في هذا العمود بالتوجه إلى ملف <code>polls/models.py</code> وتعديل الصنف <code>Question</code> ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs python"><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">Question</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">models</span><span class="pun">.</span><span class="typ">Model</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question_text </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">CharField</span><span class="pun">(</span><span class="pln">max_length</span><span class="pun">=</span><span class="hljs-number"><span class="lit">200</span></span><span class="pun">)</span><span class="pln">
    pub_date </span><span class="pun">=</span><span class="pln"> models</span><span class="pun">.</span><span class="typ">DateTimeField</span><span class="pun">(</span><span class="hljs-string"><span class="str">'date published'</span></span><span class="pun">)</span><span class="pln">

    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">__str__</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">question_text

    </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">was_published_recently</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        now </span><span class="pun">=</span><span class="pln"> timezone</span><span class="pun">.</span><span class="pln">now</span><span class="pun">()</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> now </span><span class="pun">-</span><span class="pln"> datetime</span><span class="pun">.</span><span class="pln">timedelta</span><span class="pun">(</span><span class="pln">days</span><span class="pun">=</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">pub_date </span><span class="pun">&lt;=</span><span class="pln"> now
    was_published_recently</span><span class="pun">.</span><span class="pln">admin_order_field </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pln">
    was_published_recently</span><span class="pun">.</span><span class="kwd">boolean</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">True</span></span><span class="pln">
    was_published_recently</span><span class="pun">.</span><span class="pln">short_description </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'Published recently?'</span></span></code></pre>

<p>
	أعد تحميل الصفحة الرئيسية ولاحظ الفرق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23153" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-014.png.c95af1a21ce673a48c52da6039240a03.png" rel=""><img alt="pic-014.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23153" data-unique="2nixbv5c3" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-014.thumb.png.8b5caa2343d1c419f40164a147fe3838.png"></a>
</p>

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

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs bash"><span class="pln">list_filter </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'pub_date'</span></span><span class="pun">]</span></code></pre>

<p>
	سيضيف هذا السطر عمودًا جانبيًا إلى الصفحة الرئيسية يتيح لمدير الصفحة تصفية اﻷسئلة حسب تاريخ النشر.
</p>

<p>
	ولكن ماذا لو أردنا البحث عن نص سؤال معين بدلًا من البحث بحسب تاريخ النشر؟ يمكن القيام بذلك بإضافة السطر التالي إلى الصنف <code>QuestionAdmin</code> والذي سيعمل على إظهار صندوق للبحث في الصفحة الرئيسية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs bash"><span class="pln">search_fields </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="hljs-string"><span class="str">'question_text'</span></span><span class="pun">]</span></code></pre>

<p>
	بعد إجراء التعديلات السابقة ستظهر الصفحة الرئيسية بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23154" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-015.png.3fb06ed301d4f1dbf7beda365f728c99.png" rel=""><img alt="pic-015.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23154" data-unique="tjaf9ocfi" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-015.thumb.png.d7b42cb3ff479d6916d117db395e8710.png"></a>
</p>

<h2 id="تعديل-مظهر-لوحة-التحكم-الخاصة-بالتطبيق">
	تعديل مظهر لوحة التحكم الخاصّة بالتطبيق
</h2>

<p>
	من المؤكّد أننا لا نرغب في ظهور عبارة Django administration في رأس كل صفحة من صفحات لوحة التحكم، ويمكن تغيير هذه العبارة باستخدام نظام قوالب Django، فلوحة التحكم هذه تدار بواسطة Django، وتستخدم الواجهة نظام قوالب Django كذلك.
</p>

<p>
	أنشئ مجلّدًا باسم <code>templates</code> في مجلّد المشروع (المجلد الذي يحتوي على الملف <code>manage.py</code>)، ثم توجّه إلى ملف اﻹعدادات الخاص بالمشروع <code>mysite/settings.py</code> ثم أضف الخيار <code>DIRS</code> إلى إعدادات القالب بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs cs"><span class="pln">TEMPLATES </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-string"><span class="str">'BACKEND'</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">'django.template.backends.django.DjangoTemplates'</span></span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'DIRS'</span></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">path</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">join</span></span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'templates'</span></span><span class="pun">)],</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'APP_DIRS'</span></span><span class="pun">:</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">,</span><span class="pln">
        </span><span class="hljs-string"><span class="str">'OPTIONS'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-string"><span class="str">'context_processors'</span></span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
                </span><span class="hljs-string"><span class="str">'django.template.context_processors.debug'</span></span><span class="pun">,</span><span class="pln">
                </span><span class="hljs-string"><span class="str">'django.template.context_processors.request'</span></span><span class="pun">,</span><span class="pln">
                </span><span class="hljs-string"><span class="str">'django.contrib.auth.context_processors.auth'</span></span><span class="pun">,</span><span class="pln">
                </span><span class="hljs-string"><span class="str">'django.contrib.messages.context_processors.messages'</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="pun">},</span><span class="pln">
</span><span class="pun">]</span></code></pre>

<p>
	يحدّد السطر الذي أضفناه إلى إعدادات قوالب المسارات التي يجب على Django البحث فيها عن القوالب، وهنا أخبرنا Django بأن عليه البحث عن المجلد <code>templates</code> ضمن المجلد الرئيسي للمشروع <code>BASE_DIR</code>.
</p>

<p>
	تعمل الدالة <code>os.path.join</code> على ربط القيمة التي يتم الحصول عليها من <code>BASE_DIR</code> مع اسم المجلد المطلوب وهو <code>templates</code>.
</p>

<p>
	واﻵن أنشئ مجلّدًا جديدًا باسم <code>admin</code> داخل مجلد <code>templates</code> الذي أنشأناه قبل قليل، ثم انسخ إليه القالب <code>base_site.html</code> من مجلد <code>admin</code> الموجود ضمن الملفات المصدرية لـ Django في المسار <code>django/contrib/admin/templates</code>.
</p>

<p>
	إن واجهت صعوبة في العثور على الشيفرة المصدرية الخاصة بـ Django توجّه إلى سطر اﻷوامر ونفّذ اﻷمر التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<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">c </span><span class="hljs-string"><span class="str">"import django; print(django.__path__)"</span></span></code></pre>

<p>
	واﻵن قم بتحرير ملف <code>base_site.html</code> واستبدل الشيفرة <code>{{ site_header|default:_('Django administration') }}</code> بالعبارة التي ترغب في ظهورها في رأس كل صفحة من صفحات لوحة التحكم، يجب أن تكون الشيفرة مقاربة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">block</span></span><span class="pln"> branding </span><span class="pun">%}</span></span><span class="xml"><span class="hljs-tag"><span class="pln">
</span><span class="pun">&lt;</span><span class="hljs-attribute"><span class="pln">h1</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"site-name"</span></span><span class="pun">&gt;</span></span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-template_tag"><span class="str">{% </span><span class="hljs-keyword"><span class="str">url</span></span><span class="str"> 'admin:index' %}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pun">&gt;</span></span><span class="typ">Polls</span><span class="pln"> </span><span class="typ">Administration</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="str">/</span><span class="hljs-title"><span class="str">a</span></span><span class="str">&gt;</span></span><span class="hljs-tag"><span class="str">&lt;/</span><span class="hljs-title"><span class="pln">h1</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endblock</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23155" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-016.png.330c58a5007085c8ce54bf55d4f6b59f.png" rel=""><img alt="pic-016.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23155" data-unique="yrzdx2d2h" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-016.thumb.png.856307a3cc2ea7f69dee4c5a31b06e2d.png"></a>
</p>

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

<p>
	فعلى سبيل المثال، يمكن تخصيص مظهر الصفحة الرئيسية للوحة التحكم وذلك من خلال نسخ الملف <code>template/index.html</code> من الملفات المصدرية لـ Django بنفس الطريقة السابقة، ثم قم بتحرير الملف، وستجد أنّه يستخدم متغيرًا يحمل الاسم <code>app_list</code>. يتضمن هذا المتغير جميع التطبيقات المثبتة في المشروع الذي تعمل عليه. يمكنك اﻵن استبدال هذا المتغير بروابط تأخذ المستخدم إلى مواضع مختلفة من لوحة التحكم، بدلًا من عرض جميع التطبيقات.
</p>

<h2 id="تغيير-لغة-العرض-في-لوحة-التحكم">
	تغيير لغة العرض في لوحة التحكم
</h2>

<p>
	من الخصائص التي يتميّز بها إطار العمل Django دعمه للكثير من اللغات، ومن ضمنها اللغة العربية، ويمكن تغيير لغة واجهة لوحة التحكم إلى اللغة التي نرغب بها من خلال التوجّه إلى ملف اﻹعدادات الخاصّ بالمشروع <code>setteings.py</code> ثم تعديل قيمة المتغير <code>LANGUAGE_CODE</code> الافتراضية <code>'en'</code> إلى رمز اللغة المطلوبة.
</p>

<p>
	فمثلًا لتغيير لغة الواجهة إلى العربية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs bash"><span class="pln">LANGUAGE_CODE </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'ar'</span></span></code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23156" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-017.png.88e57c6b779860a0bfcd8aaff4832059.png" rel=""><img alt="pic-017.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23156" data-unique="ezrr5ijyr" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-017.thumb.png.3f9c676dcebb7247ecf5fb93b9a39468.png"></a>
</p>

<p>
	وللغة الفرنسية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6610_9" style="">
<code class="hljs bash"><span class="pln">LANGUAGE_CODE </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'fr'</span></span></code></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23157" href="https://academy.hsoub.com/uploads/monthly_2017_05/pic-018.png.108e591fc0952200290d966c574a0bbf.png" rel=""><img alt="pic-018.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23157" data-unique="527sn3kbs" src="https://academy.hsoub.com/uploads/monthly_2017_05/pic-018.thumb.png.eb50f2c93d0de233f739605ab5f6ed84.png"></a>
</p>

<p>
	المصدر:<br><a href="https://docs.djangoproject.com/en/1.9" rel="external nofollow">توثيقات Django</a>
</p>
]]></description><guid isPermaLink="false">479</guid><pubDate>Sun, 07 May 2017 21:08:40 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x645;&#x627;&#x631;&#x627;&#x62A; Forms &#x648;&#x627;&#x644;&#x639;&#x631;&#x648;&#x636; &#x627;&#x644;&#x639;&#x627;&#x645;&#x629; &#x648;&#x627;&#x644;&#x645;&#x644;&#x641;&#x627;&#x62A; &#x627;&#x644;&#x633;&#x627;&#x643;&#x646;&#x629; &#x641;&#x64A; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%85%D8%A7%D8%B1%D8%A7%D8%AA-forms-%D9%88%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D8%A9-%D9%88%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D8%B3%D8%A7%D9%83%D9%86%D8%A9-%D9%81%D9%8A-django-r476/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_04/main.png.979907d5a82d2b95f010283f1562d429.png" /></p>

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

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23007" data-unique="t0fcd1tep" src="https://academy.hsoub.com/uploads/monthly_2017_04/main.png.aff54b71009ec5674693a454096b9cb9.png"></p>

<h2 id="إنشاء-استمارة-بسيطة">
	إنشاء استمارة بسيطة
</h2>

<p>
	يفترض أن يكون المستخدم قادرًا على اختيار إحدى الإجابات الخاصة بسؤال معين، ولكن قالب <code>detail</code> بشكله الحالي لا يوفّر هذا اﻷمر، لذا سنحتاج إلى إضافة استمارة إلى هذا القالب. توجّه إلى الملف <code>polls/detail.html</code> في مجلد القوالب <code>templates</code> ثم أضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{{</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">question_text </span><span class="pun">}}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> error_message </span><span class="pun">%}&lt;</span><span class="pln">p</span><span class="pun">&gt;&lt;</span><span class="pln">strong</span><span class="pun">&gt;{{</span><span class="pln"> error_message </span><span class="pun">}}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;&lt;/</span><span class="pln">p</span><span class="pun">&gt;{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">form action</span><span class="pun">=</span><span class="str">"{% url 'polls:vote' question.id %}"</span><span class="pln"> 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"> csrf_token </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"> choice </span><span class="kwd">in</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">choice_set</span><span class="pun">.</span><span class="pln">all </span><span class="pun">%}</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"choice"</span><span class="pln"> id</span><span class="pun">=</span><span class="str">"choice{{ forloop.counter }}"</span><span class="pln"> value</span><span class="pun">=</span><span class="str">"{{ choice.id }}"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">label </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"choice{{ forloop.counter }}"</span><span class="pun">&gt;{{</span><span class="pln"> choice</span><span class="pun">.</span><span class="pln">choice_text </span><span class="pun">}}&lt;/</span><span class="pln">label</span><span class="pun">&gt;&lt;</span><span class="pln">br </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">input type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> value</span><span class="pun">=</span><span class="str">"صوّت"</span><span class="pln"> </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;h1&gt;</code> لعرضه بشكل واضح وكبير.
</p>

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

<p>
	في السطر الثالث أنشأنا استمارة يتم توليد قيمة الحدث <code>action</code> فيه بصورة ديناميكية، وذلك باستخدام الوسم <code>url</code> والمسار <code>vote</code> والمتغير <code>question.id</code> والذي يمثّل الرقم المعرف للسؤال، وستكون طريقة إرسال الحدث هي <code>POST</code>، وبما أننا نعتمد هذه الطريقة، فعلينا الانتباه إلى حماية المعلومات من تزوير الطلب عبر المواقع <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery" rel="external nofollow">Cross-site request forgery</a> والمعروف اختصارًا بـ CSRF. ولكن لا تقلق، يوفّر Django نظامًا سهل الاستخدام لتجنّب هذه المشكلة. باختصار، يجب عليك وضع الوسم <code>{% csrf_tocken %}</code> في أي استمارة تعتمد طريقة <code>POST</code> ﻹرسال اﻷحداث.
</p>

<p>
	تعمل الحلقة for على إضافة زر اختيار Radio button إلى الإجابات الخاصة بالسؤال الذي اختاره المستخدم، ويتم جلب هذه الإجابات من باستخدام العبارة <code>question.choice_set.all</code>.
</p>

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

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

<p>
	وقد قمنا فعلًا بالخطوة الأولى من سلسلة الخطوات هذه في الدرس الرابع من هذه السلسلة عندما بدأنا الحديث عن المسارات، حيث يتضمن ملف <code>polls/urls.py</code> المسار التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/vote/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">vote</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'vote'</span></span><span class="pun">)</span></code></pre>

<p>
	هذا المسار مرتبط بالعرض view والذي قمنا بإنشائه في الدرس نفسه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">vote</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="hljs-string"><span class="str">"أنت تصوت على السؤال %s."</span></span><span class="pln"> </span><span class="pun">%</span><span class="pln"> question_id</span><span class="pun">)</span></code></pre>

<p>
	لنقم الآن بكتابة الشيفرة المسؤولة عن عملية التصويت ضمن هذا العرض، لذا توجّه إلى ملف views.py وأضف الشيفرة التالية في بداية الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">HttpResponseRedirect</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">urlresolvers </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> reverse
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Question</span></code></pre>

<p>
	ثم عدّل دالة <code>vote</code> لتصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">vote</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">try</span></span><span class="pun">:</span><span class="pln">
        selected_choice </span><span class="pun">=</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">choice_set</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">POST</span><span class="pun">[</span><span class="hljs-string"><span class="str">'choice'</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">except</span></span><span class="pln"> </span><span class="pun">(</span><span class="typ">KeyError</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">.</span><span class="typ">DoesNotExist</span><span class="pun">):</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/detail.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'question'</span></span><span class="pun">:</span><span class="pln">question</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"error_message"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"لم تقم بالتصويت على السؤال"</span></span><span class="pun">})</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pun">:</span><span class="pln">
        selected_choice</span><span class="pun">.</span><span class="pln">votes </span><span class="pun">+=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln">
        selected_choice</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponseRedirect</span><span class="pun">(</span><span class="pln">reverse</span><span class="pun">(</span><span class="hljs-string"><span class="str">'polls:results'</span></span><span class="pun">,</span><span class="pln"> args</span><span class="pun">=(</span><span class="pln">question</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,)))</span></code></pre>

<p>
	لنتكلم عن الشيفرة السابقة بشيء من التفصيل، فهناك عدد من الأمور الجديدة فيها:
</p>

<ul>
<li>
		<p>
			<code>request.POST</code> هو عنصر شبيه بالقاموس يتيح الوصول إلى البيانات المرسلة من الاستمارة بواسطة اسم المفتاح، وفي حالتنا هذا فإن <code>request.POST['choice']</code> سوف يرجع قيمة المعرّف الخاص بالجواب الذي اختاره المستخدم، وتكون هذه القيمة على هيئة سلسلة نصية.<br>
			وجدير بالذكر أن Django يقدّم عنصرًا آخر باسم <code>request.GET</code> ويستخدم عندما تكون طريقة إرسال البيانات في الاستمارة هي <code>GET</code>.
		</p>
	</li>
	<li>
		<p>
			يطلق العنصر <code>request.POST['choice]</code> خطأً مفتاحيًا <code>KeyError</code> وهذا النوع من الأخطاء يُطلق عندما لا يكون المفتاح المطلوب (ضمن القاموس) موجودًا ضمن مجموعة المفاتيح المتوفرة، وفي تطبيقنا ينطلق هذا الخطأ عندما ﻻ يختار المستخدم أي إجابة من الإجابات المعروضة أمامه، ويعمل على إعادة المستخدم إلى صفحة التصويت مرة أخرى، ولكن هذه المرة مع إضافة العبارة: “لم تقم بالتصويت على السؤال” إلى المتغير <code>error_message</code>، وبعد أن أصبح هذا المتغير يحمل قيمة معينة، سيقوم قالب <code>detail</code> بعرض الرسالة في المكان المناسب.
		</p>
	</li>
	<li>
		<p>
			إن تمت عملية التصويت بنجاح يتم إضافة صوت واحد إلى الأصوات الخاصة بالإجابة المختارة من قبل المستخدم، وقد استخدمنا الصنف <code>HttpResponseRedirect</code> بدلًا من الصنف <code>HttpResponse</code> لإعادة توجيه المستخدم إلى صفحة النتائج. هذا الصنف في الواقع هو أحد الأصناف الفرعية للصنف <code>HttpResponse</code> ويأخذ معاملًا واحدًا وهو عنوان <code>URL</code> الذي ستتم إعادة التوجيه إليه. والهدف من استخدام هذا الصنف هو تجنّب إرسال البيانات مرتين في حال ضغط المستخدم على زر الرجوع في المتصفح، وينصح باستخدام هذا الصنف في كل مرة يتم فيها التعامل بنجاح مع بيانات <code>POST</code>، وهذا الأمر ليس خاصًا بـ Django فقط، بل هو من الممارسات الجيدة في مجال تطوير الويب باستخدام أي لغة برمجية.
		</p>
	</li>
	<li>
		<p>
			استخدمنا الدالة <code>reverse()</code> في مشيّد الصنف <code>HttpResponseRedirect</code> لنتجنّب الإدخال اليدوي للمسار الذي نرغب بإعادة توجيه المستخدم إليه. يأخذ المعامل الأول في هذه الدالة اسم العرض أو اسم نمط <code>URL</code> المطلوب إعادة التوجيه إليه. في هذا المثال سيتم توجيه المستخدم إلى المسار الذي يحمل اسم <code>polls:results</code>، ولكن هذا المسار يتضمن متغيّرًا، لذا سنخبر Django بأن يأخذ قيمته من المتغيّر <code>question.id</code> وذلك من خلال المعامل <code>args</code>.<br>
			بمعنى أنّه لو اختار المستخدم السؤال الذي يحمل الرقم 3، فإن الصنف <code>HttpResponseRedirect</code> سيعيد السلسلة النصية التالية: <code>polls/3/results/</code> حيث أن قيمة <code>question.id</code> في هذه الحالة هو 3.
		</p>
	</li>
</ul>
<p>
	بعد أن يقوم المستخدم بالتصويت على سؤال معين، تعمل دالة العرض <code>vote()</code> على إعادة توجيهه إلى صفحة النتائج الخاصة بذلك السؤال، فلنقم إذًا بكتابة دالة العرض الخاصّة بالنتائج. توجّه إلى ملف <code>polls/views.py</code> وعدّل الدالة <code>results</code> لتصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">results</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/results.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'question'</span></span><span class="pun">:</span><span class="pln"> question</span><span class="pun">})</span></code></pre>

<p>
	والآن، قم بإنشاء القالب المسؤول عن عرض النتائج. في مجلد <code>templates/polls/</code> أنشئ الملف <code>results.html</code>، وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs django"><span class="xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span></span><span class="hljs-variable"><span class="pln">{{ question.question_text }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">for</span></span><span class="pln"> choice </span><span class="hljs-keyword"><span class="pln">in</span></span><span class="pln"> question.choice_set.all %}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span></span><span class="hljs-variable"><span class="pln">{{ choice.choice_text }}</span></span><span class="xml"><span class="pln"> -- </span></span><span class="hljs-variable"><span class="pln">{{ choice.votes }}</span></span><span class="xml"><span class="pln"> vote</span></span><span class="hljs-variable"><span class="pln">{{ choice.votes</span><span class="hljs-filter"><span class="pln">|</span><span class="hljs-keyword"><span class="pln">pluralize</span></span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> %}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">

</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"</span></span></span></span><span class="hljs-template_tag"><span class="atv">{% </span><span class="hljs-keyword"><span class="atv">url</span></span><span class="atv"> 'polls:detail' question.id %}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="atv">"</span></span><span class="tag">&gt;</span></span><span class="pln">صوّت مرة أخرى</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	والآن توجّه إلى العنوان التالي في متصفحك بعد تشغيل الخادوم الخاص بـ Django:
</p>

<p>
	<a rel="">127.0.0.1:8000/polls/1/</a><br>
	وستحصل على نتيجة مشابهة لهذه:
</p>

<p style="text-align: center;">
	<img alt="pic-001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23004" data-unique="7dda33cue" src="https://academy.hsoub.com/uploads/monthly_2017_04/pic-001.png.e95cc72e5d9888ac0ca15f82d3f636e1.png"></p>

<p>
	وبعد التصويت سيتم توجيهك إلى صفحة النتائج:
</p>

<p style="text-align: center;">
	<img alt="pic-002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23005" data-unique="aapoe8wi2" src="https://academy.hsoub.com/uploads/monthly_2017_04/pic-002.png.44cf292eb1fb7a761c25960e902a2d01.png"></p>

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

<p style="text-align: center;">
	<img alt="pic-003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23006" data-unique="murnutd2w" src="https://academy.hsoub.com/uploads/monthly_2017_04/pic-003.png.04cb0c87ce563c96e5990cf64259ff24.png"></p>

<h2 id="العروض-العامة-generic-views">
	العروض العامة Generic Views
</h2>

<p>
	لنلق نظرة على ملف <code>views.py</code> بعد إضافة جميع الدوال إليه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> render</span><span class="pun">,</span><span class="pln"> get_object_or_404
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">HttpResponseRedirect</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">urlresolvers </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> reverse
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Question</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 class="pln">request</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    latest_question_list </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="hljs-string"><span class="str">'-pub_date'</span></span><span class="pun">)[:</span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">]</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/index.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'latest_question_list'</span></span><span class="pun">:</span><span class="pln"> latest_question_list</span><span class="pun">})</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">detail</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/detail.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'question'</span></span><span class="pun">:</span><span class="pln"> question</span><span class="pun">})</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">results</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/results.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'question'</span></span><span class="pun">:</span><span class="pln"> question</span><span class="pun">})</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">vote</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">try</span></span><span class="pun">:</span><span class="pln">
        selected_choice </span><span class="pun">=</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">choice_set</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">=</span><span class="pln">request</span><span class="pun">.</span><span class="pln">POST</span><span class="pun">[</span><span class="hljs-string"><span class="str">'choice'</span></span><span class="pun">])</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">except</span></span><span class="pln"> </span><span class="pun">(</span><span class="typ">KeyError</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">.</span><span class="typ">DoesNotExist</span><span class="pun">):</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/detail.html'</span></span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="hljs-string"><span class="str">'question'</span></span><span class="pun">:</span><span class="pln">question</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"error_message"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"لم تقم بالتصويت على السؤال"</span></span><span class="pun">})</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pun">:</span><span class="pln">
        selected_choice</span><span class="pun">.</span><span class="pln">votes </span><span class="pun">+=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pln">
        selected_choice</span><span class="pun">.</span><span class="pln">save</span><span class="pun">()</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponseRedirect</span><span class="pun">(</span><span class="pln">reverse</span><span class="pun">(</span><span class="hljs-string"><span class="str">'polls:results'</span></span><span class="pun">,</span><span class="pln"> args</span><span class="pun">=(</span><span class="pln">question</span><span class="pun">.</span><span class="pln">id</span><span class="pun">,)))</span></code></pre>

<p>
	هل لاحظت أمرًا ما؟ الدالتان <code>detail()</code> و<code>results()</code> متشابهتان كثيرًا، وفي الواقع الفارق الوحيد بينهما هو القالب الذي يرتبط بكل دالة. إضافة إلى ذلك فإن هاتين الدالتين إضافة إلى دالة <code>index()</code> تقوم بعمل واحد وبسيط، وهو عرض مجموعة من المعلومات على المتصفح.
</p>

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

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

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

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

<ol>
<li>
		تعديل أنماط <code>URL</code>.
	</li>
	<li>
		الاستغناء عن بعض العروض التي لسنا بحاجة إليها بعد الآن.
	</li>
	<li>
		كتابة عروض جديدة بالاعتماد على عروض Django العامة.
	</li>
</ol>
<h3 id="تعديل-أنماط-url">
	تعديل أنماط URL
</h3>

<p>
	توجّه إلى ملف <code>polls/urls.py</code> وعدّله بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> url

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> views

app_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls'</span></span><span class="pln">
urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="typ">IndexView</span><span class="pun">.</span><span class="pln">as_view</span><span class="pun">(),</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'index'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;pk&gt;[0-9]+)/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="typ">DetailView</span><span class="pun">.</span><span class="pln">as_view</span><span class="pun">(),</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'detail'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;pk&gt;[0-9]+)/results/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="typ">ResultsView</span><span class="pun">.</span><span class="pln">as_view</span><span class="pun">(),</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'results'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/vote/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">vote</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'vote'</span></span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></code></pre>

<p>
	لاحظ أنّنا استبدلنا <code>&lt;question_id&gt;</code> بـ <code>&lt;pk&gt;</code> في مساري <code>detail</code> و <code>results</code>، وسنتعرف على سبب ذلك بعد قليل.
</p>

<h3 id="تعديل-العروض">
	تعديل العروض
</h3>

<p>
	التعديلات التي سنجريها على العروض ستشمل دوال <code>index(), detail(), results()</code> أما دالة <code>vote()</code> فستبقى دون تغيير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> get_object_or_404</span><span class="pun">,</span><span class="pln"> render
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">HttpResponseRedirect</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="pln">urlresolvers </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> reverse
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">views </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="kwd">generic</span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> </span><span class="typ">Choice</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Question</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">IndexView</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">generic</span><span class="pun">.</span><span class="typ">ListView</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    template_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/index.html'</span></span><span class="pln">
    context_object_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'latest_question_list'</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">get_queryset</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">self</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="hljs-string"><span class="str">'-pub_date'</span></span><span class="pun">)[:</span><span class="hljs-number"><span class="lit">5</span></span><span class="pun">]</span><span class="pln">


</span><span class="hljs-class"><span class="hljs-keyword"><span class="kwd">class</span></span><span class="pln"> </span><span class="hljs-title"><span class="typ">DetailView</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">generic</span><span class="pun">.</span><span class="typ">DetailView</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">
    template_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/detail.html'</span></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">ResultsView</span></span><span class="hljs-params"><span class="pun">(</span><span class="kwd">generic</span><span class="pun">.</span><span class="typ">DetailView</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    model </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">
    template_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls/results.html'</span></span>
</code></pre>

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

<p>
	لقد استخدمنا نوعين من أنواع العروض العامة، وهما <code>ListView</code> و <code>DetailView</code>. يلخّص العرض اﻷول عملية عرض جميع العناصر، في حين يلخّص العرض الثاني عملية عرض التفاصيل المرتبطة بعنصر معيّن.
</p>

<p>
	يحتاج كل عرض عامٍّ إلى التعرّف على النموذج الذي سيتعامل معه، ويتم التصريح عن ذلك في المعامل <code>model</code>. إلى جانب ذلك، يطلب العرض <code>DetailView</code> أن يتم إسناد قيمة المفتاح الرئيسي المأخوذة من عنوان <code>URL</code> إلى متغير يحمل الاسم <code>pk</code>، لهذا السبب قمنا بتبديل <code>question_id</code> بالاسم الجديد في ملف المسارات <code>urls.py</code>.
</p>

<p>
	يبحث العرض <code>DetailView</code> بصورة افتراضية عن القالب المرتبط به في المسار <code>&lt;app name&gt;/&lt;model_name&gt;_detail.html</code>، وهذا يعني أنّ هذا العرض سيستخدم القالب <code>polls/question_detail.html</code> بشكل تلقائي. ويمكن تجاوز هذه القيمة التلقائية من خلال تعيين اسم القالب باستخدام المعامل <code>template_name</code>. ينطبق الأمر ذاته على العرض <code>ListView</code> والذي سيستخدم بشكل تلقائي القالب <code>polls/question_list.html</code>.
</p>

<p>
	بقي أن نشير إلى أنّنا كنا نزوّد كل قالب بمتغيرات السياق التي سيستخدمها، وفي مثالنا هذا كانت المتغيرات هي <code>question</code> و <code>latest_question_list</code>.<br>
	عند استخدام العروض العامّة يتم تزويد العرض <code>DetailView</code> بالمتغير <code>question</code> تلقائيًا، وذلك ﻷننا نستخدم النموذج <code>Question</code>، حيث يستطيع Django تحديد اسم مناسب لمتغيرات السياق بناء على النموذج الذي يرتبط بالعرض العام. ويمكن تجاوز القيمة التلقائية هذه بسهولة وذلك بإسناد اسم المتغير الذي نرغب به إلى المعامل <code>context_object_name</code>، وبهذا نخبر Django بأنّنا نرغب باستخدام هذا الاسم بدلًا من الاسم الذي سينشئه بصورة تلقائية وهو في هذه الحالة <code>question_list</code>.
</p>

<p>
	كما يمكنك الإبقاء على الاسم الافتراضي <code>question_list</code> إن كنت ترغب في ذلك، ولكن هنا عليك تغيير اسم المتغير في أي مكان يرد فيه ضمن القوالب.
</p>

<h2 id="الملفات-الساكنة-static-files">
	الملفات الساكنة Static Files
</h2>

<p>
	يبدو تطبيقنا بشعًا أليس كذلك؟ لنقم إذًا بإضافة بعض التنسيقات البسيطة إليه، ولنتعرف على مفهوم الملفات الساكنة.
</p>

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

<p>
	سنبدأ أولًا بإنشاء مجلد باسم <code>static</code> في مجلد <code>polls</code> الرئيسي، ثم أنشئ داخل المجلد <code>static</code> مجلّدًا جديدًا باسم <code>polls</code>. بمعنى آخر يجب أن يكون مسار ملف CSS بالشكل التالي: <code>polls/static/polls/style.css</code>. كما هو الحال مع القوالب، فإن Django يبحث بنفس الطريقة عن الملفات الساكنة، واستخدام هذه المجلدات هو أمر تنظيمي يتيح لـ Django التمييز بين الملفات الساكنة الخاصة بكل تطبيق.
</p>

<p>
	والآن توجّه من خلال محرّر النصوص إلى ملف <code>style.css</code> وأضف إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">li</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> green</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">decoration</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> none</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1.3</span></span><span class="lit">em</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	والآن توجّه قالب <code>index.html</code> وأضف الشيفرة التالية في بداية الملف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs django"><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">load</span></span><span class="pln"> staticfiles </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">link</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">rel</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"stylesheet"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">type</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"text/css"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-template_tag"><span class="str">{% </span><span class="hljs-keyword"><span class="str">static</span></span><span class="str"> 'polls/style.css' %}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pln"> </span><span class="pun">/&gt;</span></span></span></code></pre>

<p>
	يعمل الوسم <code>load staticfiles</code> في بداية الملف على تحميل الوسم <code>static</code> المسؤول بدوره عن توليد عنوان URL المطلق للملف الساكن المطلوب.
</p>

<p>
	والآن أعد تحميل الصفحة الرئيسية وستلاحظ أن الأسئلة قد تلونت باللون اﻷخضر.
</p>

<p>
	ولإضافة صورة للخلفية قم بإنشاء مجلد <code>images</code> في نفس المجلد الذي يحتوي الملف <code>style.css</code> ثم ضع فيه الصورة التي ترغب في جعلها خلفية للصفحة، وعلى فرض استخدام صورة باسم <code>background.gif</code> أضف الشيفرة التالية إلى ملف <code>style.css</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_4249_7" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">body</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> white </span><span class="hljs-function"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="str">"images/background.gif"</span></span><span class="pun">)</span></span><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">repeat right bottom</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	أعد تحميل الصفحة الرئيسية، وستلاحظ أن الصورة قد أصبحت خلفية للصفحة.
</p>

<p>
	من الجدير بالذكر أنّه لا يمكن استخدام الوسم <code>{% static %}</code> استخدام داخل الملفات الساكنة والتي لا يتم توليدها بواسطة Django، لذا يجب استخدام المسارات النسبية وليست المطلقة لربط الملفات الساكنة بعضها ببعض.
</p>

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

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

<p>
	المصدر:<br><a href="https://docs.djangoproject.com/en/1.9" rel="external nofollow">توثيقات Django</a>
</p>
]]></description><guid isPermaLink="false">476</guid><pubDate>Mon, 01 May 2017 21:03:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x631;&#x648;&#x636; &#x648;&#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; &#x641;&#x64A; Django - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-%D9%88%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-%D9%81%D9%8A-django-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r439/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_03/django6.png.4f746cac0cc50d1191d71f24d202761d.png" /></p>

<p>
	تعرّفنا في الدرس السابق على القسمين الثاني والثالث من بنية المشاريع في إطار العمل Django وهما العروض Views والقوالب Templates، وقد تحدّثنا عن العروض وآلية عملها بشكل مفصّل، وسنتطرّق في هذا الدرس بشيء من التفصيل إلى القوالب وآلية عملها وسنتعرّف كذلك على محرّك القوالب الخاص بـ Django.
</p>

<p style="text-align: center;">
	<img alt="django6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22280" data-unique="qg2nkyotf" src="https://academy.hsoub.com/uploads/monthly_2017_03/django6.png.739dc8c34834610d5c491e7ab9ffac98.png"></p>

<h2 id="ما-هي-القوالب">
	ما هي القوالب؟
</h2>

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

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

<p>
	ﻻ بدّ أنّك قد لاحظت أنّه في كلّ مرة أجرينا فيها عملية ربط القالب، فقد قمنا بتعريف سياق المتغيرات Variable Context معه. يقوم Django بتصيير Rendering القالب مع السياق المرتبط به، حيث يتم استبدال أسماء المتغيرات بالقيم المرتبطة بها وذلك بعد مطابقتها مع سياق المتغيرات المرفق مع القالب، ويتم كذلك تنفيذ الوسوم الموجودة في ملف القالب، أما ما تبقى في هذا الملف فيظهر كما هو.
</p>

<h3 id="المتغيرات">
	المتغيرات
</h3>

<p>
	يعرض المتغير القيمة المرتبطة به عن طريق السياق، وهو قاموس يضم مجموعة من المفاتيح والقيم المرتبطة بها.
</p>

<p>
	لاستخدام المتغيرات في قوالب Django يكفي إحاطتها بقوسين معقوفين بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs handlebars"><span class="xml"><span class="typ">My</span><span class="pln"> first name </span><span class="kwd">is</span><span class="pln"> </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">first</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">name</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pun">.</span><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="kwd">last</span><span class="pln"> name </span><span class="kwd">is</span><span class="pln"> </span></span><span class="hljs-expression"><span class="pun">{{</span><span class="pln"> </span><span class="hljs-variable"><span class="pln">last</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">name</span></span><span class="pln"> </span><span class="pun">}}</span></span><span class="xml"><span class="pun">.</span></span></code></pre>

<p>
	فلو كان سياق المتغيرات بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs css"><span class="hljs-rules"><span class="pun">{</span><span class="hljs-rule"><span class="str">'</span><span class="hljs-attribute"><span class="str">first_name</span></span><span class="str">:</span><span class="hljs-value"><span class="str"> </span><span class="hljs-string"><span class="str">'</span><span class="typ">Mohammed</span><span class="str">'</span></span><span class="str">, </span><span class="hljs-string"><span class="str">'</span><span class="pln">last_name</span><span class="str">'</span></span><span class="str">: </span><span class="hljs-string"><span class="str">'</span><span class="typ">Taher</span><span class="str">'</span></span></span></span></span><span class="str">}</span></code></pre>

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

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript"><span class="typ">My</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">first</span></span><span class="pln"> </span><span class="hljs-property"><span class="pln">name</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> </span><span class="typ">Mohammed</span><span class="pun">.</span><span class="pln"> </span><span class="typ">My</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">last</span></span><span class="pln"> </span><span class="hljs-property"><span class="pln">name</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> </span><span class="typ">Taher</span><span class="pun">.</span></code></pre>

<h3 id="الوسوم">
	الوسوم
</h3>

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

<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="pln">csrf_token</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	ومعظمها يتقبل المعاملات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs mel"><span class="pun">{%</span><span class="pln"> cycle </span><span class="hljs-string"><span class="str">'odd'</span></span><span class="pln"> </span><span class="hljs-string"><span class="str">'even'</span></span><span class="pln"> </span><span class="hljs-variable"><span class="pun">%}</span></span></code></pre>

<p>
	وتتطلب بعض الوسوم تحديد وسم البداية والنهاية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_71_12">
<span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">is_authenticated </span><span class="pun">%}</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{{</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">}}.{%</span><span class="pln"> endif </span><span class="pun">%}</span></pre>

<p>
	لنلقِ نظرة اﻵن على أشيع الوسوم المستخدمة في لغة قوالب Django:
</p>

<p>
	<u><strong>الجمل الشرطية</strong></u>
</p>

<p>
	يتحقّق الوسم <code>{% if %}</code> من قيمة المتغير، فإذا كانت القيمة صحيحة (بمعنى أنّ المتغير موجود، وليس فارغًا، ولا يحمل قيمة <code>false</code>) يتم عرض محتوى المتغير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_71_10">
<span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> article_list </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">Number</span><span class="pln"> of articles</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{{</span><span class="pln">article_list</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">elif</span><span class="pln"> article_in_archive </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">The</span><span class="pln"> </span><span class="typ">Articels</span><span class="pln"> are </span><span class="kwd">in</span><span class="pln"> </span><span class="typ">Archive</span><span class="pun">.</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">No</span><span class="pln"> articles</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>{% elif %}</code> و <code>{% else %}</code> لمرة واحدة أو لعدة مرات ضمن الوسم <code>If</code>، وﻻحظ أيضًا أن هذا الوسم يتطلب وجود وسم إغلاق.
</p>

<p>
	يمكن استعمال المعاملات المنطقية <code>(and, or, not)</code> في الوسم <code>If</code>، كما يمكن استخدام المعاملات الرياضية <code>(==, !=, &lt;, &gt;, &lt;=, &gt;=, in)</code>، إضافة إلى إمكانية دمج هذه المعاملات مع بعضها البعض، إليك بعض اﻷمثلة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_71_8">
<span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> athlete_list </span><span class="kwd">and</span><span class="pln"> coach_list </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">Both</span><span class="pln"> athletes </span><span class="kwd">and</span><span class="pln"> coaches are available</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="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> athlete_list </span><span class="kwd">and</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> coach_list </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">There</span><span class="pln"> are some athletes </span><span class="kwd">and</span><span class="pln"> absolutely no coaches</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="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> athlete_list </span><span class="kwd">and</span><span class="pln"> coach_list </span><span class="kwd">or</span><span class="pln"> cheerleader_list </span><span class="pun">%}</span><span class="pln">
    </span><span class="typ">There</span><span class="pln"> are some athelets </span><span class="kwd">and</span><span class="pln"> maybe some coaches </span><span class="kwd">or</span><span class="pln"> cheerleaders</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="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> somevar </span><span class="pun">==</span><span class="pln"> </span><span class="str">"x"</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
  </span><span class="typ">This</span><span class="pln"> appears </span><span class="kwd">if</span><span class="pln"> variable somevar equals the string </span><span class="str">"x"</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">


</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="str">"bc"</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="str">"abcdef"</span><span class="pln"> </span><span class="pun">%}</span><span class="pln">
  </span><span class="typ">This</span><span class="pln"> appears since </span><span class="str">"bc"</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> a substring of </span><span class="str">"abcdef"</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span><span class="pln">

</span><span class="pun">{%</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> user </span><span class="kwd">in</span><span class="pln"> users </span><span class="pun">%}</span><span class="pln">
  </span><span class="typ">If</span><span class="pln"> users </span><span class="kwd">is</span><span class="pln"> a </span><span class="typ">QuerySet</span><span class="pun">,</span><span class="pln"> this will appear </span><span class="kwd">if</span><span class="pln"> user </span><span class="kwd">is</span><span class="pln"> an
  instance that belongs to the </span><span class="typ">QuerySet</span><span class="pun">.</span><span class="pln">
</span><span class="pun">{%</span><span class="pln"> endif </span><span class="pun">%}</span></pre>

<p id="حلقة-for-التكرارية">
	<u><strong>حلقة for التكرارية</strong></u>
</p>

<p>
	يؤدي هذا الوسم نفس الوظيفة التي تؤديها أي حلقة <code>for</code> في أي لغة برمجية، إليك هذا المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_71_14">
<span class="tag">&lt;ul&gt;</span><span class="pln">
{% for athlete in athlete_list %}
    </span><span class="tag">&lt;li&gt;</span><span class="pln">{{ athlete.name }}</span><span class="tag">&lt;/li&gt;</span><span class="pln">
{% endfor %}
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	يمكن المرور على عناصر مصفوفة معينة وبصورة عكسية بإضافة كلمة <code>reversed</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs ocaml"><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"> obj </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">list</span></span><span class="pln"> reversed </span><span class="pun">%}</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">for</span></span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> points </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="typ">There</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> a point at </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> x </span><span class="pun">}}</span></span><span class="xml"><span class="pun">,</span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> y </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	ويمكن استخدام هذا الوسم للعرض المفاتيح والقيم المرتبطة بها في قاموس معين:
</p>

<pre class="ipsCode prettyprint lang-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"> key</span><span class="pun">,</span><span class="pln"> value </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> data</span><span class="pun">.</span><span class="pln">items </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> key </span><span class="pun">}}</span></span><span class="xml"><span class="pun">:</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> value </span><span class="pun">}}</span></span><span class="xml"><span class="pln">
</span></span><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>
	يمكن الوصول إلى عداد الحلقة التكرارية بأساليب مختلفة، وذلك عن طريق مجموعة من المتغيرات يقدّمها محرّك القوالب في Django. فمثلًا <code>forloop.counter</code> يظهر العدد الحالي للحلقة ويبدأ عدّ الحلقات من الرقم 1، و <code>forloop.counter0</code> الذي يؤدي نفس الوظيفة ولكن يبدأ العدّ من الرقم 0، و <code>forloop.first</code> والذي يعطي قيمة <code>True</code> إن كانت الدورة الحالية هي الدورة اﻷولى ضمن الحلقة، و<code>forloop.last</code> والذي يؤدي نفس الوظيفة ولكن عند الوصول إلى الدورة اﻷخيرة ضمن الحلقة.
</p>

<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">for</span></span><span class="pln"> photo </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> gallery </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"> forloop</span><span class="pun">.</span><span class="pln">counter </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
       </span><span class="typ">Do</span><span class="pln"> something </span><span class="kwd">with</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> photo </span><span class="pun">}}</span></span><span class="xml"><span class="pun">.</span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">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>gallery</code> ويتحقق وسم <code>if</code> أثناء ذلك من العدد الحالي للحلقة، فإن كانت الحلقة هي اﻷولى يتم تنفيذ الشرط، وإلا فلا.<br>
	الشيفرة السابقة مطابقة للشيفرة التالية:
</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"> photo </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> gallery </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"> forloop</span><span class="pun">.</span><span class="pln">first </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
       </span><span class="typ">Do</span><span class="pln"> something </span><span class="kwd">with</span><span class="pln"> </span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> photo </span><span class="pun">}}</span></span><span class="xml"><span class="pun">.</span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">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>
	تقدّم لغة قوالب Django عددًا كبيرًا من الأوسمة التي تؤدي وظائف متعددة ومتنوعة، ويمكنك الاطلاع على جميع الوسوم المتوفرة ووظائفها <a href="https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#built-in-template-tags-and-filters" rel="external nofollow">من هنا</a>.
</p>

<h3 id="المرشحات-filters">
	المرشحات Filters
</h3>

<p>
	تعمل المرشّحات على إجراء تحويل معيّن على قيم المتغيرات والأوسمة، وتستخدم بالشكل التالي:
</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"> hsoub</span><span class="hljs-filter"><span class="pun">|</span><span class="hljs-keyword"><span class="pln">title</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"> messages</span><span class="hljs-filter"><span class="pun">|</span><span class="hljs-keyword"><span class="pln">length</span></span></span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="typ">You</span><span class="pln"> hove lots of messages</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></code></pre>

<p>
	يعمل المرشح <code>title</code> على تحويل الحرف اﻷول من كل كلمة في قيمة المتغير إلى حرف كبير، فلو كان السياق معرفًا بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs applescript"><span class="pun">{</span><span class="str">'hsoub'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'</span><span class="hljs-function_start"><span class="hljs-keyword"><span class="str">on</span></span></span><span class="str"> a mission </span><span class="hljs-keyword"><span class="str">to</span></span><span class="str"> develop </span><span class="hljs-keyword"><span class="str">the</span></span><span class="str"> arab world'</span><span class="pun">}</span></code></pre>

<p>
	فإن الحرف اﻷول من كل كلمة في العبارة السابقة سيتحول إلى حرف كبير:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs vbnet"><span class="hljs-keyword"><span class="typ">On</span></span><span class="pln"> A </span><span class="typ">Mission</span><span class="pln"> </span><span class="hljs-keyword"><span class="typ">To</span></span><span class="pln"> </span><span class="typ">Develop</span><span class="pln"> </span><span class="typ">The</span><span class="pln"> </span><span class="typ">Arab</span><span class="pln"> </span><span class="typ">World</span></code></pre>

<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">my</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">date</span></span><span class="pun">|</span><span class="hljs-variable"><span class="pln">date</span></span><span class="pun">:</span><span class="hljs-string"><span class="str">"Y-m-d"</span></span><span class="pln"> </span><span class="pun">}}</span></span></code></pre>

<p>
	يقدم محرّك قوالب Django عددًا كبيرًا من المرشحات التي تؤدي وظائف مختلفة، كتنسيق الوقت والتاريخ، وعرض الجمل المناسبة لصيغتي المفرد والجمع، وتكبير اﻷحرف اﻹنكليزية وتصغيرها، وحساب عدد الكلمات وغيرها الكثير. يمكنك الاطلاع جميع المرشحات المتوفرة ووظائفها <a href="https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#built-in-template-tags-and-filters" rel="external nofollow">من هنا</a>.
</p>

<h2 id="استخدام-محرك-القوالب-في-تطبيق-الاقتراعات">
	استخدام محرّك القوالب في تطبيق الاقتراعات
</h2>

<p>
	لنعد اﻵن إلى تطبيق الاقتراعات الذي نعمل على إنشائه ضمن هذه السلسلة، ولنتوجه إلى ملف <code>templates/polls/index.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="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> latest_question_list </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">ul</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> question </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> latest_question_list </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">li</span></span><span class="str">&gt;</span></span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"/polls/</span></span></span></span><span class="hljs-variable"><span class="str">{{ question.id }}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">/"</span></span><span class="pun">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">question_text </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;</span><span class="str">/</span><span class="hljs-title"><span class="str">a</span></span><span class="str">&gt;</span></span><span class="hljs-tag"><span class="str">&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="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span><span 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-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	ﻻحظ أنّنا نستخدم في هذا الملف عددًا من المتغيرات واﻷوسمة، إذ يبدأ الملف بوسم <code>If</code> يتحقق من قيمة المتغير <code>latest_question_list</code> الموجود في سياق المتغيرات المرفق مع القالب، فإن كانت نتيجة التحقق صحيحة، يضاف وسم <code>&lt;ul&gt;</code> إلى الملف ثم تبدأ حلقة <code>for</code> بالعمل، حيث تمرّ على جميع عناصر القائمة <code>latest_question_list</code> وإسناد كل قيمة إلى المتغير <code>question</code>. ﻻحظ أن هذا المتغير يضمّ متغيرات فرعية (إن صح التعبير) تحمل قيمًا مختلفة، مثل <code>question.id</code> و <code>question.question_text</code>. تقوم بالحلقة بسرد عناصر القائمة مع إضافة وسمي <code>&lt;li&gt;</code> و <code>&lt;a&gt;</code> إلى كل عنصر، وبعد الانتهاء يضاف الوسم <code>&lt;/ul&gt;</code>. استخدمنا الوسم <code>else</code> لعرض رسالة تخبر المستخدم بعدم وجود أي اقتراعات في الوقت الحاضر في حال كانت نتيجة التحقق خاطئة.
</p>

<p>
	توجّه اﻵن إلى الملف detail.html وعدّله ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs django"><span class="xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span></span><span class="hljs-variable"><span class="pln">{{ question.question_text }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">for</span></span><span class="pln"> choice </span><span class="hljs-keyword"><span class="pln">in</span></span><span class="pln"> question.choice_set.all %}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span></span><span class="hljs-variable"><span class="pln">{{ choice.choice_text }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pln">{% </span><span class="hljs-keyword"><span class="pln">endfor</span></span><span class="pln"> %}</span></span><span class="xml"><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">ul</span></span><span class="tag">&gt;</span></span></span></code></pre>

<p>
	ستعمل الشيفرة السابقة على عرض اﻷجوبة المرتبطة بالسؤال الذي اختاره المستخدم على هيئة قائمة نقطية.
</p>

<h3 id="توليد-الروابط-بصورة-ديناميكية">
	توليد الروابط بصورة ديناميكية
</h3>

<p>
	هناك مشكلة صغيرة في قالب <code>index.html</code> وهي أننا قمنا بكتابة مسار الرابط بأنفسنا، ولم يتم توليد هذا المسار ديناميكيًا، اﻷمر الذي يجعل من تبديل المسار في وقت لاحق أمرًا صعبًا خصوصًا إن تضمن القالب مسارات عديدة.
</p>

<p>
	يمكن لـ Django أن يتكفل بعملية توليد مسارات الروابط بشكل كامل، وذلك باستخدام الوسم <code>{% url %}</code> ليصبح الملف index.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">if</span></span><span class="pln"> latest_question_list </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">ul</span></span><span class="str">&gt;</span></span><span class="pln">
    </span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> question </span><span class="hljs-keyword"><span class="kwd">in</span></span><span class="pln"> latest_question_list </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">li</span></span><span class="str">&gt;</span></span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="str">"</span></span></span></span><span class="hljs-template_tag"><span class="str">{% </span><span class="hljs-keyword"><span class="str">url</span></span><span class="str"> 'detail' question.id %}</span></span><span class="xml"><span class="hljs-tag"><span class="hljs-value"><span class="str">"</span></span><span class="pun">&gt;</span></span></span><span class="hljs-variable"><span class="pun">{{</span><span class="pln"> question</span><span class="pun">.</span><span class="pln">question_text </span><span class="pun">}}</span></span><span class="xml"><span class="hljs-tag"><span class="pun">&lt;</span><span class="str">/</span><span class="hljs-title"><span class="str">a</span></span><span class="str">&gt;</span></span><span class="hljs-tag"><span class="str">&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="kwd">else</span></span><span class="pln"> </span><span class="pun">%}</span></span><span class="xml"><span class="pln">
    </span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">p</span></span><span class="str">&gt;</span></span><span 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-tag"><span class="pun">&lt;/</span><span class="hljs-title"><span class="pln">p</span></span><span class="pun">&gt;</span></span><span class="pln">
</span></span><span class="hljs-template_tag"><span class="pun">{%</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">endif</span></span><span class="pln"> </span><span class="pun">%}</span></span></code></pre>

<p>
	ولكن كيف يتعرّف Django على المسار المطلوب؟ يستخدم Django قيمة المعامل <code>name</code> الذي قمنا بتعريفه في الدرس الرابع من هذه السلسلة (المسارات في Django). توجّه إلى ملف <code>polls/urls.py</code> والق نظرة على المسار الخاص بعرض detail:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs python"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'detail'</span></span><span class="pun">)</span></code></pre>

<p>
	ﻻحظ أن هذا المسار يحمل اسمًا خاصًّا به، وقد عرّفناه من خلاله المعامل <code>name</code>. بهذه الطريقة يتعرّف Django على المسار المطلوب استخدامه في القوالب.<br>
	واﻵن إن كنت ترغب في تغيير المسار المرتبط بهذا العرض إلى مسار آخر، وليكن <code>polls/specifics/12/</code> على سبيل المثال، فيمكن تعديله ضمن ملف <code>polls/urls.py</code> بدلًا من تعديل المسار في القالب أو القوالب التي تم استخدامه فيها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_71_16">
<span class="pln">url</span><span class="pun">(</span><span class="pln">r</span><span class="str">'^specifics/(?P&lt;question_id&gt;[0-9]+)/$'</span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="str">'detail'</span><span class="pun">),</span></pre>

<h3 id="استخدام-نطاقات-اﻷسماء-للتمييز-بين-المسارات">
	استخدام نطاقات اﻷسماء للتمييز بين المسارات
</h3>

<p>
	يتضمن مشروعنا هذا تطبيقًا واحدًا فقط وهو تطبيق الاقتراعات، ولكن المشاريع الحقيقية تتضمن عددًا كبيرًا من التطبيقات، فكيف يمكن لـ Django إذًا أن يميز بين أسماء المسارات في هذه الحالة؟ على سبيل المثال، يحتوي تطبيق الاقتراعات على عرض باسم detail، وقد يحتوي المشروع على تطبيق مدونة يتضمن عرضًا باسم detail أيضًا، فكيف يمكن لـ Django أن يتعرف على المسار المطلوب عند استخدام الوسم <code>url</code> في ملف القالب؟
</p>

<p>
	اﻹجابة هي نطاقات اﻷسماء Namespaces. توجه إلى الملف <code>polls/urls.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"> django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> url

</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> views

app_name </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">'polls'</span></span><span class="pln">
urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'index'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'detail'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/results/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">results</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'results'</span></span><span class="pun">),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/vote/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">vote</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'vote'</span></span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></code></pre>

<p>
	واﻵن عدّل العبارة التالية في القالب <code>polls/index.html</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"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"{% url 'detail' question.id %}"</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">question.question</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">text</span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span></span></code></pre>

<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"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"{% url 'polls:detail' question.id %}"</span></span><span class="tag">&gt;</span></span></span><span class="hljs-expression"><span class="pln">{{ </span><span class="hljs-variable"><span class="pln">question.question</span></span><span class="pln">_</span><span class="hljs-variable"><span class="pln">text</span></span><span class="pln"> }}</span></span><span class="xml"><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">li</span></span><span class="tag">&gt;</span></span></span></code></pre>

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

<p>
	لا زالت هناك بعض اﻷمور اﻷساسية التي تنقص تطبيق الاقتراعات، فصفحات التطبيق غير منسّقة، كما أنّه لا يوفّر للمستخدم طريقة واضحة للتصويت على الاقتراعات.<br>
	في الدرس القادم سنتعرّف على كيفية التعامل مع النماذج Forms بصورة مبسطة لتهيئة آلية التصويت على الاقتراعات، وسنتعرف كذلك على العروض العامة Generic views وسنرى كيف يمكن لهذه العروض أن تختصر الوقت والجهد. بعد ذلك سنقوم بإضافة التنسيقات الخاصة بتطبيق الاقتراعات بواسطة CSS وسنتعرف على مفهوم الملفات الساكنة Static Files في Django.
</p>

<p>
	المصدر:<br><a href="https://docs.djangoproject.com/en/1.9" rel="external nofollow">توثيقات Django</a>
</p>
]]></description><guid isPermaLink="false">439</guid><pubDate>Wed, 22 Mar 2017 21:02:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x631;&#x648;&#x636; &#x648;&#x627;&#x644;&#x642;&#x648;&#x627;&#x644;&#x628; &#x641;&#x64A; Django - &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%B9%D8%B1%D9%88%D8%B6-%D9%88%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-%D9%81%D9%8A-django-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r436/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_03/django5.png.90b763d55b735eb9d47b7098873958c6.png" /></p>

<p>
	تحدّثنا في بداية هذه السلسلة عن أن مشاريع إطار العمل Django تتبع بنية Model-View-Template (النموذج - العرض - القالب) وبعد أن تطرقنا في <a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-models-%D9%88%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85-%D8%B9%D9%86-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-django-r405/" rel="">الجزء الثالث من هذه السلسلة إلى النماذج Models</a> وآلية عملها، سنشرع في هذا الجزء بالحديث عن القسم الثاني من بنية المشاريع ألا وهو العروض Views.
</p>

<p style="text-align: center;">
	<img alt="django5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22176" data-unique="17yrykbdo" src="https://academy.hsoub.com/uploads/monthly_2017_03/django5.png.876ccea86adc2386827a4e5cb03b0a04.png"></p>

<p style="text-align: center;">
	 
</p>

<p>
	والعروض في Django هي صفحة ويب في تطبيق Django تؤدي وظيفة معينة وترتبط بقالب Template معين. فعلى سبيل المثال إن كان التطبيق الذي نعمل عليه عبارة عن مدونة، فإنه سيتضمن العروض التالية:
</p>

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

<ul>
<li>
		صفحة الأسئلة الرئيسية index، والتي نعرض فيها آخر الأسئلة المضافة.
	</li>
	<li>
		صفحة تفاصيل السؤال detail، نعرض فيها نص السؤال، إلى جانب نموذج للتصويت.
	</li>
	<li>
		صفحة نتائج السؤال results، نعرض فيها نتائج التصويت على سؤال معين.
	</li>
	<li>
		حدث التصويت، نتحكم من خلاله بعملية التصويت على سؤال معين.
	</li>
</ul>
<p>
	ذكرنا في الدرس السابق أن اختيار العرض المناسب وتنفيذه في Django يتم بالاعتماد على المسار الذي يدخله المستخدم في شريط العناوين في المتصفح، إذ يرتبط كل عرض بمسار محدد ويتم تنفيذ العرض عندما يتطابق المسار الذي أدخله المستخدم مع أحد المسارات الموجودة في ملف urls.py، وقد قمنا بذلك بالفعل في الدرس السابق من هذه السلسلة.
</p>

<h3 id="آلية-عمل-العروض">
	آلية عمل العروض
</h3>

<p>
	تقتصر وظيفة العروض على القيام بأمرين اثنين:
</p>

<ol>
<li>
		إرجاع كائن HttpResponse يتضمن محتوى الصفحة المطلوبة.
	</li>
	<li>
		إطلاق استثناء مثل Http404.
	</li>
</ol>
<p>
	والباقي عائد إليك، إذ يمكنك أن تجلب عددًا من السجلات من قاعدة البيانات باستخدام العروض، أو يمكنك استخدام نظام القوالب الخاص بـ Django أو أي نظام قوالب آخر، كما يمكنك إنشاء ملفات PDF أو XML أو إنشاء ملفات مضغوطة ZIP… الخ. عمليًا، يمكنك القيام بما تشاء وباستخدام أي مكتبة من مكتبات بايثون، وكل ما يحتاجه Django هو الكائن HttpResponse أو الاستثناء.<br>
	لنقم الآن بكتابة عرض بسيط يعمل على جلب آخر خمسة أسئلة في قاعدة البيانات ويعرضها في المتصفح مفصولة عن بعضها البعض بفاصلة (,) ومرتبة حسب تاريخ النشر.<br>
	توجه إلى polls/views.py ثم أضف الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_9">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">

</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    latest_question_list </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="str">'-pub_date'</span><span class="pun">)[:</span><span class="lit">5</span><span class="pun">]</span><span class="pln">
    output </span><span class="pun">=</span><span class="pln"> </span><span class="str">', '</span><span class="pun">.</span><span class="pln">join</span><span class="pun">([</span><span class="pln">q</span><span class="pun">.</span><span class="pln">question_text </span><span class="kwd">for</span><span class="pln"> q </span><span class="kwd">in</span><span class="pln"> latest_question_list</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="pln">output</span><span class="pun">)</span></pre>

<p>
	لنتحدث عن هذه الشيفرة بشيء من التفصيل:
</p>

<ul>
<li>
		<p>
			في السطر الأول قمنا باستيراد الكائن HttpResponse من وحدة django.http والصنف Question من ملف النماذج models.py الموجود في نفس المجلد الذي يحتوي الملف views.py، وذلك لنتمكن من الاستعلام عن الأسئلة الموجودة في قاعدة البيانات.
		</p>
	</li>
	<li>
		<p>
			بعد ذلك بدأنا بتعريف العرض وذلك من خلال إنشاء الدالة index. في كل دالة عرض يتم تمرير كائن HttpRequest والذي يأخذ عادة الاسم request.<br>
			من الجدير بالذكر أنك لست مقيدًا بتسمية الدالة باسم معين لكي تؤدي العمل المطلوب، إذ يمكنك أن تسمي الدالة السابقة بأي اسم تشاء، ولكن ينصح بتسمية الدوال بأسماء واضحة يمكن من خلالها معرفة العمل الذي ستؤديه عند العودة إليها في وقت لاحق.
		</p>
	</li>
	<li>
		<p>
			يرجع العرض كائن HttpResponse يحتوي الردّ الذي قمنا بإنشائه والذي يتضمن نتيجة الاستعلام عن آخر خمسة أسئلة تم نشرها في الموقع، وذلك بواسطة الواجهة البرمجية الخاصة باستدعاء البيانات الخاصة بـ Django، والتي تحدثنا عنها في موضوع النماذج في Django.
		</p>
	</li>
</ul>
<p>
	قمنا في الدرس السابق بربط العرض index بالمسار r’^$’، وهذا يعني أننا لسنا بحاجة إلى إدخال أي شيء في شريط العناوين سوى عنوان النطاق، وهو الخادوم المحلي الخاص بـ Django.<br>
	ولمشاهدة مخرجات الدالة التي قمنا بكتابتها، توجّه إلى سطر الأوامر وقم بتشغيل خادوم Django من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2698_12">
<code class="hljs avrasm">python manage<span class="hljs-preprocessor">.py</span> runserver</code></pre>

<p>
	افتح المتصفح ثم توجه إلى العنوان التالي:<br><a href="http://127.0.0.1:8000/" rel="external nofollow">http://127.0.0.1:8000/</a>
</p>

<h3 id="ربط-العروض-بالقوالب">
	ربط العروض بالقوالب
</h3>

<p>
	أعتقد أنّك لاحظت وجود مشكلة بسيطة في هذه الشيفرة، وهي أن تنسيق المخرجات من خلال إضافة وسوم HTML وتنسيقات CSS وغيرها من الأمور المرتبطة بواجهة الموقع العامة من خلال العروض ليس أمرًا عمليًّا على الإطلاق.<br>
	هذا يعني أننا بحاجة إلى طريقة لفصل تصميم صفحة الويب عن الشيفرات المكتوبة بلغة بايثون، وهنا يأتي دور القوالب Templates، العنصر الثالث من بنية المشاريع في Django.<br>
	والقوالب عبارة عن ملفات HTML عادية تتضمن وسوم HTML و تنسيقات CSS وشيفرات Javascript (سواء أكانت شيفرات عادية أم مكتبات مثل Jquery، Angular، React وغيرها)، ولكن الفارق الوحيد هو إمكانية استخدام محرك القوالب Template Engine الخاص بـ Django داخل هذه القوالب.<br>
	لاستخدام القوالب في مشروعنا هذا، أنشئ مجلدًا باسم templates في مجلد polls، واعتمادًا على الإعدادات الافتراضية فإن Django سيبحث عن ملفات القوالب ضمن هذا المجلد.<br>
	والآن في مجلد templates أنشئ مجلدًا آخر باسم polls وبداخل هذا المجلد أنشئ الملف index.html، وهكذا يكون مسار ملفنا هذا هو: polls/templates/polls/index.html.<br>
	والآن يمكن الإشارة إلى هذا القالب باستخدام المسار: polls/index.html فقط.<br>
	ولكن ما الداعي لإنشاء كل هذه المجلدات؟<br>
	في الواقع كان بالإمكان أن نضع الملف index.html في مجلد templates وحسب دون الحاجة إلى إنشاء مجلد polls آخر ضمنه، ولكن من غير المستحسن على الإطلاق القيام بذلك.<br>
	السبب وراء هذا هو أن Django سيعتمد أول قالب يطابق اسمه الاسم المطلوب، وهذا يعني أنه لو وجد اسم القالب نفسه (index.html في مثالنا هذا) في تطبيق آخر فإنه لن يكون قادرًا على التمييز بينهما؛ لذا يستحسن دائمًا استخدام هذه الطريقة لضمان عدم تداخل القوالب بين التطبيقات المتعددة في المشروع الواحد.<br>
	والآن أضف الشيفرة التالية إلى ملف index.html الذي أنشأته:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1816_11">
<span class="pln">{% if latest_question_list %}
    </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    {% for question in latest_question_list %}
    </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/polls/{{ question.id }}/"</span><span class="tag">&gt;</span><span class="pln">{{ question.question_text }}</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
    {% endfor %}
</span><span class="tag">&lt;/ul&gt;</span><span class="pln">
{% else %}
    </span><span class="tag">&lt;p&gt;</span><span class="pln">الاقتراعات غير متوفرة حالياً.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
{% endif %}</span></pre>

<p>
	سنتكلم عن محرك القوالب الخاص بـ Django وكل ما يتعلق به في الدرس القادم.<br>
	بقي علينا ربط العرض index بالقالب index.html؛ لذا توجه إلى الملف polls/views.py وعدله بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_13">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">http </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pln">
</span><span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">template </span><span class="kwd">import</span><span class="pln"> loader

</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">


</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    latest_question_list </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="str">'-pub_date'</span><span class="pun">)[:</span><span class="lit">5</span><span class="pun">]</span><span class="pln">
    template </span><span class="pun">=</span><span class="pln"> loader</span><span class="pun">.</span><span class="pln">get_template</span><span class="pun">(</span><span class="str">'polls/index.html'</span><span class="pun">)</span><span class="pln">
    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="str">'latest_question_list'</span><span class="pun">:</span><span class="pln"> latest_question_list</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="pln">template</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> request</span><span class="pun">))</span></pre>

<p>
	في السطر الثاني من الدالة index قمنا بتحميل القالب الذي سيرتبط بهذه الدالة، وذلك من خلال الدالة get_template التابعة للوحدة loader التي قمنا باستيرادها في بداية الملف من الوحدة template.<br>
	تأخذ الدالة get_template معاملًا وهو عبارة عن سلسلة نصية نحدّد من خلالها مسار القالب الذي نرغب في ربطه بالعرض.<br>
	بعد ذلك قمنا بتعريف ما يسمى في Django بالسياق context وهو عبارة عن قاموس Dictionary يعمل على ربط المتغيرات التي سنستخدمها في محرك القوالب الخاص بـ Django - متمثلة بالمفتاح الخاص بالقاموس -، مع المتغيرات الموجودة في العرض - متمثلة بالقيمة المرتبطة بذلك المفتاح -.<br>
	في الشيفرة السابقة، قمنا بربط المتغير latest_question_list في العرض بالمتغير latest_question_list في القالب index.html.<br>
	وفي نهاية الشيفرة ترجع الدالة index كائن HttpResponse ولكن هذه المرة قمنا بتمرير الدالة render كمعامل لهذا الكائن، وقمنا بتمرير المتغير template والقاموس context كمعاملين لدالة render، والتي تعمل على دمج قالب معين مع السياق المحدد وتعيد كائن HttpRespons يتضمن ما سيعرض في القالب.<br>
	توجه الآن من خلال المتصفح إلى العنوان التالي، بعد تشغيل الخادوم الخاص بـ Django:<br><a href="http://127.0.0.1:8000/polls/" rel="external nofollow">http://127.0.0.1:8000/polls/</a><br>
	سترى الآن قائمة نقطية تتضمن الأسئلة التي أضفناها في الدروس السابقة إلى قاعدة البيانات.
</p>

<h3 id="اختصار-عرض-القوالب-باستخدام-الدالة-render">
	اختصار عرض القوالب باستخدام الدالة render:
</h3>

<p>
	إن الخطوات السابقة (تحميل القالب ثم تحديد سياق المتغيرات ثم إرجاع الكائن HttpResponse الذي يتضمن النتيجة التي سيعرضها القالب) شائعة جدًّا وتتكرر باستمرار، لذا يقدّم Django اختصارًا لهذه الخطوات باستخدام الدالة render() التابعة لحزمة django.shortcuts والتي تتضمن عددًا من الدوال التي تختصر بعض الخطوات التي تتكرر باستمرار في Django.<br>
	قم بتعديل الملف polls/views.py ليصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_15">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> render

</span><span class="kwd">from</span><span class="pln"> </span><span class="pun">.</span><span class="pln">models </span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Question</span><span class="pln">


</span><span class="kwd">def</span><span class="pln"> index</span><span class="pun">(</span><span class="pln">request</span><span class="pun">):</span><span class="pln">
    latest_question_list </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">order_by</span><span class="pun">(</span><span class="str">'-pub_date'</span><span class="pun">)[:</span><span class="lit">5</span><span class="pun">]</span><span class="pln">
    context </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'latest_question_list'</span><span class="pun">:</span><span class="pln"> latest_question_list</span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'polls/index.html'</span><span class="pun">,</span><span class="pln"> context</span><span class="pun">)</span></pre>

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

<h3 id="رمي-الاستثناء-http404">
	إطلاق الاستثناء Http404
</h3>

<p>
	لننتقل الآن إلى دالة العرض المسؤولة عن سرد تفاصيل السؤال الذي يختاره المستخدم؛ لذا توجه إلى الملف polls/views.py ثم أضف السطر التالي في بداية الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2698_12">
<code class="hljs python"><span class="hljs-keyword">from</span> django.http <span class="hljs-keyword">import</span> Http404</code></pre>

<p>
	ثم عدّل الدالة detail لتصبح بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_17">
<span class="kwd">def</span><span class="pln"> detail</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">try</span><span class="pun">:</span><span class="pln">
        question </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="pln">objects</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">except</span><span class="pln"> </span><span class="typ">Question</span><span class="pun">.</span><span class="typ">DoesNotExist</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">raise</span><span class="pln"> </span><span class="typ">Http404</span><span class="pun">(</span><span class="str">"السؤال المطلوب غير موجود."</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'polls/detail.html'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="str">'question'</span><span class="pun">:</span><span class="pln"> question</span><span class="pun">})</span></pre>

<p>
	قمنا بتمرير معامل جديد في الدالة detail وهو question_id، وهذا المعامل هو المتغير الذي قمنا بتعريفه في ملف المسارات urls.py في الدرس السابق، ضمن المسار المرتبط بهذه الدالة.<br>
	يحمل هذا المتغير الرقم الذي سيدخله المستخدم في شريط العناوين والذي سيلتقطه Django بواسطة التعابير النظامية Regular expressions ويسنده إلى المتغير question_id.<br>
	تبدأ الدالة بالاستعلام عن السؤال الذي يحمل المفتاح الأساسي primary key - يختصر Django اسم هذا المفتاح بالحرفين pk - الذي يطابق قيمة المتغير question_id وإسناد النتيجة إن وجدت إلى المتغير question.<br>
	وفي حالة عدم وجود هذا السؤال يتم إطلاق الاستثناء Http404 ليُعلم المستخدم بعدم وجود السؤال الذي قام بطلبه.<br>
	والآن نحن بحاجة إلى القالب detail.html لنتمكن من مشاهدة السؤال المطلوب؛ لذا قم بإنشاء هذا الملف في مجلد templates/polls. سنكتفي هنا بإضافة السطر التالي في هذا الملف، للتأكد من عمل الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2698_12">
<code class="hljs handlebars"><span class="hljs-expression">{{ <span class="hljs-variable">question</span> }}</span></code></pre>

<h3 id="اختصار-خطوات-الاستعلام-ورمي-الاستثناء">
	اختصار خطوات الاستعلام وإطلاق الاستثناء Http404
</h3>

<p>
	مرة أخرى، فإن الخطوات السابقة (الاستعلام باستخدام الدالة get وإطلاق الاستثناء Http404) تتكرر باستمرار، لذا يقدّم Django دالة بديلة تختصر هذه العملية، وكما هو متوقع فهذه الدالة موجودة في حزمة django.shortcuts، لذا سنقوم باستيرادها بالشكل التالي مع الدالة render:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_19">
<span class="kwd">from</span><span class="pln"> django</span><span class="pun">.</span><span class="pln">shortcuts </span><span class="kwd">import</span><span class="pln"> get_object_or_404</span><span class="pun">,</span><span class="pln"> render</span></pre>

<p>
	يمكن الآن استخدام الدالة get_object_or_404() بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1816_21">
<span class="kwd">def</span><span class="pln"> detail</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">):</span><span class="pln">
    question </span><span class="pun">=</span><span class="pln"> get_object_or_404</span><span class="pun">(</span><span class="typ">Question</span><span class="pun">,</span><span class="pln"> pk</span><span class="pun">=</span><span class="pln">question_id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> </span><span class="str">'polls/detail.html'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="str">'question'</span><span class="pun">:</span><span class="pln"> question</span><span class="pun">})</span></pre>

<p>
	المعامل الأول في الدالة get_object_or_404() هو اسم النموذج الذي نرغب في الاستعلام داخله، أما المعامل الثاني فهو مجموعة من معاملات الكلمة المفتاحية والتي تقوم الدالة بتمريرها إلى دالة get() الخاصة بواجهة Django البرمجية للاستعلام في قواعد البيانات. في حالة عدم وجود الكائن المطلوب تطلق الدالة الاستثناء Http404.<br>
	يقدّم Django كذلك دالة get_list_or_404() والتي تعمل بنفس الطريقة باستثناء أنّها تستخدم الدالة filter() بدلًا من get()، وتطلق الدالة الاستثناء Http404 في حال عدم وجود القائمة المطلوبة.<br>
	والآن توجّه إلى العنوان التالي في المتصفح بعد تشغيل خادوم Django، ولاحظ النتيجة:<br>
	(<a href="http://127.0.0.1:8000/polls/1" rel="external nofollow">http://127.0.0.1:8000/polls/1</a>)<br>
	حاول تغيير رقم السؤال لإطلاق الاستثناء Http404.
</p>

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

<p>
	تعرفنا في هذا الدرس على العنصر الثاني من بنية المشاريع في Django ألا وهي العروض، وتعرفنا كذلك على طريقة ربطها بالقوالب والتي تمثّل العنصر الثالث من بنية المشاريع في إطار العمل هذا.<br>
	وسنتطرق في الفصل القادم بمزيد من التفصيل إلى القوالب وآلية عملها وسنتعرف على محرك القوالب الخاص بـ Django وما يتضمنه من متغيرات ووسوم وغيرها، وسنتعرّف كذلك على العروض المستندة إلى الأصناف والعروض العامة Generic Views.
</p>

<p>
	المصادر:<br><a href="https://docs.djangoproject.com/en/1.9" rel="external nofollow">توثيقات Django</a>
</p>
]]></description><guid isPermaLink="false">436</guid><pubDate>Tue, 14 Mar 2017 21:07:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x633;&#x627;&#x631;&#x627;&#x62A; &#x641;&#x64A; Django</title><link>https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-django-r426/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_02/django-4.png.2c13299f312ff7c495229cfd21ab2a85.png" /></p>

<p id="المسارات-في-django">
	تعرفنا في الأجزاء الثلاثة السابقة <a href="https://academy.hsoub.com/programming/python/django/" rel="">من هذه السلسلة</a> على إطار العمل Django وكيفية تنصيبه وبدأنا بالفعل بإنشاء تطبيق الاقتراعات من خلال هذا الإطار، وتعرفنا بشكل مبسط على المسارات والعروض وطريقة ربطها ببعض، كما تعرفنا كذلك على طريقة التعامل مع قواعد البيانات باستخدام النماذج وكيفية تهجير قواعد البيانات وطرق الاستعلام المختلفة المتوفرة في Django.<br>
	وفي الجزء الرابع من هذه السلسلة سنتكلم عن المسارات URLs وآلية عملها بصورة أوسع، وسنتطرق في حديثنا إلى كيفية الاستفادة من التعابير النظامية Regular expressions لجعل مسارات تطبيقنا (تطبيق الاقتراعات) أكثر ترتيبًا ووضوحًا.
</p>

<p style="text-align: center;">
	<img alt="django-4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="21843" data-unique="0p9r6nao8" src="https://academy.hsoub.com/uploads/monthly_2017_02/django-4.png.8d7127c0124f9a47edaa576bc6af5dda.png" style=""></p>

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

<pre>
<code>“ME2/Sites/dirmod.asp?sid=&amp;type=gen&amp;mod=Core+Pages&amp;gid=A6CD4967199A42D9B65B1B”
</code></pre>

<p>
	هذا الشكل من الروابط غير مرغوب فيه على الإطلاق في Django، إذ يستخدم هذا الإطار مفهوم أنماط المسارات URL patterns لإظهارها بصورة مرتبة وواضحة وذات دلالة في نفس الوقت.<br>
	والمقصود بأنماط المسارات بكل بساطة هو أن تمتلك المسارات نسقًا معينًا، مثل:
</p>

<pre class="prettyprint prettyprinted">
<code class="hljs xml"><span class="str">/newsarchive/</span><span class="hljs-tag"><span class="str">&lt;</span><span class="hljs-title"><span class="str">year</span></span><span class="str">&gt;</span></span><span class="pun">/</span><span class="hljs-tag"><span class="pun">&lt;</span><span class="hljs-title"><span class="pln">month</span></span><span class="pun">&gt;</span></span><span class="pun">/</span></code></pre>

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

<h2 id="مسارات-تطبيق-الاقتراعات">
	مسارات تطبيق الاقتراعات
</h2>

<p>
	سيؤدي تطبيق الاقتراعات الذي نعمل على إنشائه المهام التالية:
</p>

<ol>
<li>
		صفحة رئيسية <code>index</code> تعرض عددًا من الأسئلة المطروحة في الموقع.
	</li>
	<li>
		صفحة تفاصيل السؤال <code>detail</code> تعرض سؤالًا معيّنًا إلى جانب الأجوبة المتاحة لهذا السؤال للتصويت.
	</li>
	<li>
		صفحة نتائج <code>results</code> تعرض النتائج المتعلقة بسؤال معين.
	</li>
	<li>
		عملية التصويت، والتي يتم من خلالها التصويت على جواب معين مرتبط بسؤال معين.
	</li>
</ol>
<p>
	وكما ذكرنا في الدروس السابقة فإنّ عملية إرسال الطلبات وتلقي الإجابة عليها هي مهمة العروض؛ لذا سننشئ أربعة عروض يختص كل منها بمهمة محددة من المهام الأربعة الخاصة بالتطبيق.<br>
	افتح ملف <code>polls/views.py</code> في محرر النصوص المفضل لديك، ثم أضف الشيفرة التالية بعد دالة <code>index</code> التي أضفناها إلى هذا الملف في الدرس الثاني.
</p>

<pre class="prettyprint prettyprinted">
<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">detail</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="hljs-string"><span class="str">"هذا هو السؤال  %s."</span></span><span class="pln"> </span><span class="pun">%</span><span class="pln"> question_id</span><span class="pun">)</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">results</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    response </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"هذه نتائج السؤال %s."</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="pln">response </span><span class="pun">%</span><span class="pln"> question_id</span><span class="pun">)</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">def</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">vote</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> question_id</span><span class="pun">)</span></span><span class="pun">:</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">HttpResponse</span><span class="pun">(</span><span class="hljs-string"><span class="str">"أنت تصوت على السؤال %s."</span></span><span class="pln"> </span><span class="pun">%</span><span class="pln"> question_id</span><span class="pun">)</span></code></pre>

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

<h2 id="عزل-مسارات-التطبيق-عن-مسارات-المشروع">
	عزل مسارات التطبيق عن مسارات المشروع
</h2>

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

<pre class="prettyprint prettyprinted">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> include</span><span class="pun">,</span><span class="pln"> url
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">contrib </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> admin

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^polls/'</span></span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="hljs-string"><span class="str">'polls.urls'</span></span><span class="pun">)),</span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^admin/'</span></span><span class="pun">,</span><span class="pln"> admin</span><span class="pun">.</span><span class="pln">site</span><span class="pun">.</span><span class="pln">urls</span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></code></pre>

<p>
	قمنا في السطر الأول باستيراد الدالة <code>include</code> والتي ستعمل على تضمين المسارات الموجودة في ملف <code>polls/urls.py</code> وربطها بالمسار <code>polls/</code>، كما هو موضح في العنصر الأول من قائمة <code>urlpatterns</code>.<br>
	فعلى سبيل المثال، لو طلب المستخدم العنوان <code>mypolls/</code> في المتصفح يبدأ إطار العمل في البحث عن هذه الكلمة في ملف urls.py الخاص بالمشروع، وفي حالة عدم العثور عليها تظهر صفحة خطأ للمستخدم تفيد بعدم وجود هذا العنوان.<br>
	وفي حالة استخدام الدالة <code>include</code> يضيف Django إلى مجال بحثه الملف الذي تشير إليه هذه الدالة، بمعنى أنه لو طلب المستخدم العنوان <code>polls/3/</code> مثلًا فسيتم البحث أولًا عن عبارة <code>polls</code> في ملف <code>mysite/urls.py</code> الخاص بالمشروع الرئيسي، وما أن يتم العثور على العبارة المطلوبة تبدأ الدالة <code>include</code> بالعمل وتبدأ عملية البحث عن العبارة التالية لـ <code>polls</code> (الرقم 3 في مثالنا هذا) في ملف <code>polls/urls.py</code> الخاص بالتطبيق والذي تشير إليه الدالة.<br>
	ولعزل مسارات التطبيق في ملف منفصل، توجّه إلى مجلد polls وأنشأ فيه ملفًّا جديدًا باسم urls.py، ثم أضف فيه الشيفرة التالية:
</p>

<pre class="prettyprint prettyprinted">
<code class="hljs python"><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> django</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">.</span><span class="pln">urls </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> url
</span><span class="hljs-keyword"><span class="kwd">from</span></span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">import</span></span><span class="pln"> views

urlpatterns </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="hljs-comment"><span class="com"># ex: /polls/</span></span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'index'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="hljs-comment"><span class="com"># ex: /polls/5/</span></span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'detail'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="hljs-comment"><span class="com"># ex: /polls/5/results/</span></span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/results/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">results</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'results'</span></span><span class="pun">),</span><span class="pln">
    </span><span class="hljs-comment"><span class="com"># ex: /polls/5/vote/</span></span><span class="pln">
    url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/vote/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">vote</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'vote'</span></span><span class="pun">),</span><span class="pln">
</span><span class="pun">]</span></code></pre>

<p>
	لاحظ أن بنية هذا الملف مشابهة بشكل كبير للملف <code>mysite/urls.py</code>، حيث يتم استيراد الدالة <code>url</code> في بداية الملف، كما أن قائمة المسارات <code>urlpatterns</code> مماثلة للقائمة الموجودة في ملف <code>mysite/urls.py</code>.<br>
	يعمل السطر الثاني في الشيفرة السابقة على استيراد ملف العروض <code>views.py</code> والموجود في مجلد <code>polls</code> والذي يضم في الوقت نفسه ملف المسارات هذا، لذا يمكن اختصار اسم المجلد باستخدام النقطة <code>.</code>.
</p>

<h2 id="كيف-تعمل-المسارات-في-django">
	كيف تعمل المسارات في Django
</h2>

<p>
	يستخدم Django المسارات كوسيلة للربط بين العنوان الذي يدخله المستخدم في شريط العناوين الخاص بالمتصفح وبين العروض التي تؤدي وظائف مختلفة ومتنوعة، فعندما يدخل المستخدم عنوانًا معينًا في شريط العناوين يبدأ Django بالبحث ضمن المسارات المتوفرة لديه في ملفات <code>urls.py</code> - كما ذكرنا قبل قليل - عن أي نمط يطابق المسار المدخل، فإن حصل تطابق بين العنوان الذي أدخله المستخدم وبين أحد المسارات ينفّذ Django العرض المرتبط بذلك المسار مباشرة.<br>
	أما وسيلة البحث التي يستخدمها Django فهي التعابير النظامية، وهي عبارة عن سلسلة من الرموز التي تكوّن نمطًا معيّنًا يستعمل للبحث في النصوص (المسارات في حالتنا هذه) عن أجزاء تطابق هذا النمط، وتتألف سلسلة الرموز هذه من مجموعة من الحروف أو الأرقام التي تساعد في البحث عن كلمة معينة أو عبارة أو رقم معين، وإلى جانب ذلك يمكن استخدام عدد من الرموز الخاصة التي تحمل دلالات معينة في التعبيرات النظامية مثل <code>^</code>، <code>$</code>، <code>؟</code> وغيرها.
</p>

<h3 id="المعامل-regex-والتعابير-النظامية">
	المعامل regex والتعابير النظامية
</h3>

<p>
	تمتلك دالة <code>url</code> أربعة معاملات، اثنان منها معاملات إلزامية وهما <code>regex</code> و<code>view</code> واثنان اختياريان هما <code>kwargs</code> و <code>name</code>.<br>
	والمعامل <code>regex</code> في دالة <code>url</code> عبارة عن سلسلة نصية خام تتضمن تعبيرًا نظاميًا، يستخدمه Django في مطابقة العناوين المدخلة من قبل المستخدم مع المسارات المتوفرة في ملفات <code>urls.py</code>.<br>
	لتوضيح كيفية استخدام التعابير النظامية في Django سنبدأ أولًا بدالة <code>url</code> في ملف <code>mysite/urls.py</code>:
</p>

<pre class="prettyprint prettyprinted">
<code class="hljs python"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^polls/'</span></span><span class="pun">,</span><span class="pln"> include</span><span class="pun">(</span><span class="hljs-string"><span class="str">'polls.urls'</span></span><span class="pun">)),</span></code></pre>

<p>
	لاحظ أن المعامل الأول يبدأ بالرمز <code>^</code>، وهو أحد الرموز الخاصة في التعابير النظامية، ويشير إلى وجوب ورود الكلمة التي تلي هذا الرمز في بداية الجملة، وفي حالتنا هذه يتم البحث عن العبارات التي تبدأ بـ <code>polls/</code>، وهذا يعني أن العبارات <code>polls/30</code> و <code>polls/q=44</code> و <code>polls/polls/polls/</code> و <code>polls/sport/football/worldcup/2014</code> تكون كلها مطابقة لهذا النمط، إذ أنّ العبارات كلها تبدأ بـ <code>polls/</code>.<br>
	عند استخدام الدالة <code>include</code> في هذا المسار، يبدأ Django بالبحث عن العبارات التي تبدأ بـ <code>polls/</code> في ملف <code>mysite/urls.py</code> مضافًا إليها كل العبارات الموجودة في ملف <code>polls/urls.py</code>.<br>
	يستخدم الرمز الخاص <code>$</code> للإشارة إلى وجوب ورود الكلمة التي تسبق هذا الرمز في نهاية الجملة. لاحظ المثال التالي:
</p>

<pre class="prettyprint prettyprinted">
<code class="hljs python"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^polls/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'index'</span></span><span class="pun">),</span></code></pre>

<p>
	سيبحث Django في هذه الحالة عن العبارات التي تكون فيها كلمة <code>polls/</code> في بداية ونهاية الجملة في الوقت ذاته، بمعنى أن العبارات <code>polls/30</code> و <code>polls/q=44</code> و <code>polls/polls/polls/</code> و <code>polls/sport/football/worldcup/2014</code> لن تكون مطابقة لهذا النمط، إذ أن كلمة <code>polls/</code> تقع في بداية هذه الجمل، ولكنها ليست في نهايتها، أما العبارة <code>polls/polls/polls</code> فليست مطابقة لأن الكلمة المطلوبة ليست في بداية ونهاية الجملة في الوقت ذاته، فكلمة <code>polls/</code> الأولى تقع في بداية الجملة وليست في نهايتها، وكلمة <code>polls/</code> الأخيرة موجودة في نهاية الجملة وليست في بدايتها، وبهذا لا يحصل التطابق.<br>
	لنرفع الآن من مستوى تعقيد السلاسل المستخدمة كتعابير نظامية، ونأخذ دالة <code>url</code> التي تربط المسار بالعرض <code>detail</code> في ملف <code>polls/urls.py</code>:
</p>

<pre class="prettyprint prettyprinted">
<code class="hljs python"><span class="pln">url</span><span class="pun">(</span><span class="hljs-string"><span class="pln">r</span><span class="str">'^(?P&lt;question_id&gt;[0-9]+)/$'</span></span><span class="pun">,</span><span class="pln"> views</span><span class="pun">.</span><span class="pln">detail</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">=</span><span class="hljs-string"><span class="str">'detail'</span></span><span class="pun">),</span></code></pre>

<p>
	يستخدم Django الأقواس لالتقاط النص الذي يطابق النمط المستخدم في التعابير النظامية، ويمكن إسناد هذه القيمة إلى متغير بالشكل التالي: <code>?P&lt;variable_name&gt;</code>، وفي مثالنا هذا سيتم إسناد القيمة المطابقة للتعبير النظامي إلى المتغير <code>question_id</code>.<br>
	يتألف التعبير <code>[0-9]+</code> من جزأين، الأول هو <code>[0-9]</code> ويطابق الأعداد التي تضم الأرقام من <code>0</code> إلى <code>9</code> حصرًا ولن يحدث التطابق في حال وجود أي حرف حتى مع وجود الأرقام، أما علامة <code>+</code> فهي إحدى الرموز الخاصة بالتعابير النظامية والتي تعني تكرار الأرقام مرة واحدة أو أكثر.<br>
	هذا يعني أن Django سيبحث عن أي عبارة تبدأ بأي عدد (مثلًا: 3، 20، 4003 تطابق النمط، لكن <code>abc</code>، <code>3b2</code>، <code>ac3</code> لن تطابق النمط)، وفي حال مطابقة النمط لعبارة معينة سيتم إسنادها إلى المتغير <code>question_id</code> المستخدم في دالة <code>detail</code> الموجودة في ملف <code>polls/views.py</code>.<br>
	للتأكد من ذلك، قم بتشغيل الخادوم الخاص بـ Django، من خلال سطر الأوامر، ثم أدخل العنوان التالي في المتصفح، ولاحظ النتيجة:
</p>

<pre>
<code>http://127.0.0.1:8000/polls/33/
</code></pre>

<p>
	ما حدث هنا، هو أنك بعد أن أدخلت العنوان السابق في المتصفح، بدأ Django في البحث في ملف <code>mysite/urls.py</code> عن أي نمط يطابق العنوان المدخل، وبعد أن وجد أن النمط <code>^polls/</code> مطابق لهذا العنوان، بدأ المعامل الثاني للدالة <code>url</code> بالعمل والذي يتضمن الدالة <code>include</code> التي توجّه Django للبحث مرة أخرى عن العبارات التي تلي الكلمة <code>polls/</code> ضمن العنوان المدخل، وتتم عملية البحث في الملف الذي تشير إليه الدالة وهو <code>polls/urls.py</code>، وبعد أن وجد Django أن النمط <code>[0-9]+</code> مطابق لـ <code>33</code> بدأ المعامل الثاني للدالة url <code>enter code here</code>بالعمل وهو تنفيذ العرض المرتبط بهذا المسار (detail) والموجود في ملف <code>views.py</code>.<br>
	جرب تغيير الرقم (33) إلى أرقام أخرى، كذلك جرب كتابة حروف بدلًا من الأرقام ولاحظ النتائج.<br>
	جرّب الآن تعديل العنوان إلى الشكل التالي، ولاحظ النتيجة:
</p>

<pre>
<code>http://127.0.0.1:8000/polls/33/results/
</code></pre>

<p>
	يوضح الجدول التالي بعض التعابير النظامية والأنماط الناشئة من هذه التعابير:
</p>

<table>
<thead><tr>
<th>
				التعبير النظامي
			</th>
			<th>
				النمط
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				[A-Z]+
			</td>
			<td>
				الحروف الإنكليزية الكبيرة مع تكرارها لمرة واحدة على الأقل
			</td>
		</tr>
<tr>
<td>
				[A-Za-z]+
			</td>
			<td>
				الحروف الإنكليزية الكبيرة والصغيرة مع تكرارها لمرة واحدة على الأقل
			</td>
		</tr>
<tr>
<td>
				[0-9]+
			</td>
			<td>
				جميع الأرقام مع تكرار الرقم لمرة واحدة على الأقل
			</td>
		</tr>
<tr>
<td>
				\w
			</td>
			<td>
				يطابق هذا النمط أي كلمة
			</td>
		</tr>
<tr>
<td>
				\d
			</td>
			<td>
				يطابق هذا النمط أي رقم
			</td>
		</tr>
<tr>
<td>
				[A-Za-z0-9]+
			</td>
			<td>
				يطابق هذا النمط جميع الحروف الإنكليزية إضافة إلى الأرقام
			</td>
		</tr>
</tbody>
</table>
<p>
	للاطلاع بشكل أكبر على التعابير النظامية والرموز المستخدمة فيها، يمكن زيارة المواقع التالية:<br>
	* <a href="http://www.regular-expressions.info/" rel="external nofollow">Regular-Expressions.info</a><br>
	* <a href="http://regexr.com" rel="external nofollow">Regexr</a>، يتيح هذا الموقع تجربة التعابير النظامية بصورة مباشرة في المتصفح.
</p>

<h3 id="المعامل-name">
	المعامل name
</h3>

<p>
	المعامل <code>name</code> عبارة عن سلسلة نصية يمكن من خلالها تحديد اسم خاص بالمسار، وسنستفيد من هذا الاسم لاحقًا في الإشارة إلى المسار عند التعامل مع القوالب في الدروس القادمة.
</p>

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

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

<p>
	المصدر:<br><a href="http://docs.djangoproject.com/en/1.9/" rel="external nofollow">توثيقات Django</a>
</p>
]]></description><guid isPermaLink="false">426</guid><pubDate>Mon, 20 Feb 2017 07:44:00 +0000</pubDate></item></channel></rss>
