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

البحث في الموقع

المحتوى عن 'مسارات'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 4 نتائج

  1. تعرَّفنا في المقال السّابق على العنصر Canvas الذي أُضيف إلى HTML5 ليوفّر أداة ومساحة لرسم الأشكال والتصاميم باستخدام جافاسكربت. سنتعلم في هذا الدّرس كيفية رسم الأشكال على Canvas باستخدام جافا سكربت مثل الدوائر، المثلَّثات والمستطيلات وسنتعرف على المنحنيات Curves لرسم أشكال أكثر تعقيدًا. الشبكة The grid إن أي عنصر يتم إضافته أو رسمه على Canvas يُحَدّد موقعه بواسطة الزَّاوية اليسارية العليا (0, 0) أي بإحداثيات (x, y) بحيث أنه يبعد عن المركز (0, 0) بمقدار (x, y). رسم المستطيلات Rectangles توفر canvas ثلاث دوال لرسم المستطيلات وجميعها تأخذ معاملات argumrnts مماثلة. الإحداثيات (x, y) تحدد موقع المستطيل بالنسبة للمركز (0, 0) والذي يحدَّد بالزَّاوية اليسارية العليا للـ Canvas، العرض width والطول height تحددان قياس المستطيل. الدَّالة ()fillRect ترسم مستطيلًا ذي مساحة لونية solid color. الدَّالة ()strokeRect ترسم مستطيلًا Storke (مُفرغًا) ذي حواف فقط outline. الدَّالة ()clearRect تقوم بمسح مستطيل محدّد بالمعاملات x, y) ،width ،height) أي تجعله شفافًا Transparent. ولا ننسى طبعا الدَّالة ()draw والتي تدير جميع عمليات الرَّسم على الـ canvas في الجافاسكربت. سنرى كيفية رسم المستطيلات باستخدام الدَّوال الثلاث أعلاه. السكربت التالي يرسم ثلاثة مستطيلات بإحداثيات وقياسات مختلفة : <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.fillStyle = "rgb(200,0,0)"; ctx.fillRect(10, 10, 200, 200); ctx.clearRect(30, 30, 150, 150); ctx.strokeRect(50, 50, 60, 60); } } </script> باستخدام ()fillRect تم رسم مستطيل ذو مساحة لونية حمراء بقياس 200*200 عند الإحداثيات (10,10). باستخدام ()clearRect تم رسم مستطيل بلا لون (شفاف) بقياس 150*150 عند الإحداثيات (30,30). باستخدام ()storkRect تم رسم مستطيل stroke مُفرغ ذو حواف بقياس 60*60 عند الإحداثيات (50,50). رسم المسارات Paths المسارات paths هي عبارة عن مجموعة من النقاط متصلة مع بعضها البعض بواسطة خطوط صغيرة segments لتقوم بتشكيل رسومات مختلفة كأشكال منحنية، أشكال هندسية…الخ. يمكن أن يكون المسار مفتوحًا مثل نصف دائرة او مغلقًا كالمثلَّث. هناك 4 خطوات أساسية لرسم المسارات حيث تُنفّذ مجموعة من الدَّوال بالتّرتيب للحصول على المسار بالشكل المطلوب. ()beginPath تقوم هذه الدَّالة بإنشاء المسار بحيث يتم رسم المسار وتخزين نقاطه في قائمة List. the methods هي مجموعة من الدَّوال التي تقوم بإنشاء أشكال أساسية مثل الدَّالة arc التي ترسم قوس والدّالة lineTo التي ترسم خط مستقيم. ()moveTo تقوم في كل مرة برسم نقطة انطلاق جديدة لبدء الرَّسم منها. ()closePath تقوم بإغلاق المسار ليتم الرَّسم خارج المسار بعدها أي البدء بمسار جديد. ()stroke تحول المسار المرسوم إلى شكل مُفرَّغ ذو حواف أي دون ملأ المسار. ()fill تحول المسار المرسوم إلى مسار ممتلئ بمساحة لونية solid. الخطوة الأولى لإنشاء مسار path هي استدعاء الدَّالة ()beginPath (بشكل ضمني المسارات تُخزَّن بشكل مسارات جزئية في مصفوفة أو قائمة List مثل خطوط أو منحنيات..الخ) والتي بمجملها مسؤولة عن تكوين الشكل. في كل مرة تتم فيها استدعاء الدَّالة ()beginPath يتم فيها إعادة إنشاء مصفوفة أو قائمة List جديدة ويمكننا البدء برسم شكل جديد. الخطوة الثانية هي استدعاء إحدى الدَّوال التي تقوم بتحديد المسار الذي سيُرسم مثل الدَّالة ()moveTo أو الدَّالة ()lineTo. الخطوة الثالثة هي استدعاء إحدى الدالتين ()storke أو ()fill. الخطوة الرابعة وهي خطوة اختيارية يتم فيها استدعاء الدَّالة ()closePath هذه الدَّالة تقوم بإغلاق الشكل عن طريق رسم خط مستقيم من النُّقطة الحالية التي توقف عندها الرَّسم إلى نقطة البداية التي بدأ عندها رسم المسار. ملاحظات: في حين كان الشكل قد أُغلق أثناء الرَّسم أو بقيت نقطة واحدة في القائمة List فهذه الدَّالة لن تقوم بعمل أي شيء. عند استدعاء الدَّالة ()fill فإن الأشكال المفتوحة ستُغلق تلقائيًّا أي لن يكون هناك داعي لاستدعاء الدَّالة ()closePath ولكن لا تنطبق هذه الحالة عند استدعاء الدَّالة ()storke. رسم مثلث اعتمادًا على خطوات إنشاء المسارات أعلاه سأقوم بإنشاء مسار مثلَّث كما في السكربت التالي: <script type="application/javascript"> function draw() { var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(300, 200); ctx.lineTo(100, 200); ctx.fillStyle = "rgb(200,0,180)"; ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.moveTo(100, 300); ctx.lineTo(400, 300); ctx.lineTo(400, 200); ctx.fillStyle = "rgb(140,50,80)"; ctx.fill(); } } </script> قمت بإنشاء مثلَّثين الأول عند النُّقطة (100, 100)، رسم خط مستقيم بواسطة الدَّالة ()lineTo إلى النُّقطة (300, 200)، خط مستقيم إلى النُّقطة (100, 200) ثم تحديد اللّون عن طريق الدَّالة ()fillStyle وبالنهاية استدعاء الدَّالة ()fill ليتم تلوين المسار والحصول على شكل مثلَّث. كذلك الأمر بالنسبة للمثلَّث الثاني. عند تشغيل المتصفّح يظهر المثلَّثان بهذا الشكل: الرسم بتحريك القلم moving pen تخيل أنك تقوم برسم لوحة فنية كم مرة ستحتاج لترك نقطة رسم وتحريك القلم للبدء من نقطة جديدة، هذا ما تقوم به الدَّالة ()moveTo أي أنها تقوم بنقل نقطة بدء الرَّسم إلى نقطة (x, y) جديدة. عند إنشاء canvas أو عند استدعاء الدَّالة ()beginPath ستحتاج إلى استدعاء الدَّالة ()moveTo لتحديد نقطة البداية التي ستبدأ عندها الرَّسم. أو عندما تكون بحاجة لرسم مسارات متقطعة. للتوضيح أكثر سأقوم برسم وجه ضاحك smiley face وتلوينه كما في السكربت التالي: <script type="application/javascript"> function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(75, 75, 50, 0, Math.PI * 2, true); ctx.stroke(); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "rgb(250, 250, 0)"; ctx.arc(75, 75, 50, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.fillStyle = "rgb(250, 0, 0)"; ctx.moveTo(110, 75); ctx.arc(75, 75, 35, 0, Math.PI, false); ctx.fill(); ctx.closePath(); ctx.moveTo(65, 65); ctx.beginPath(); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(60, 65, 5, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); ctx.beginPath(); ctx.moveTo(95, 65); ctx.fillStyle = "rgb(0, 0, 0)"; ctx.arc(90, 65, 5, 0, Math.PI * 2, true); ctx.fill(); ctx.closePath(); } } </script> يحتوى الشكل على 4 مسارات مغلقة: الإطار الخارجي للوجه، الوجه، الفم، العين اليمنى، العين اليسرى. لاحظ أنني قمت باستدعاء الدَّالة ()beginPath أربع مرات ولم أكن بحاجة لاستدعاء الدَّالة ()closePath عندما رسمت الإطار بالرغم من أنه stroke وذلك بسبب تقاطع نقطة النهاية مع البداية. أيضًا عند رسم الأشكال solid لم أحتج لاستدعاء الدَّالة ()closePath وذلك لأن الدَّالة ()fill تقوم بإغلاق المسار بشكل تلقائي لتلوينه. الخطوط Lines تُستخدم الدَّالة ()lineTo لرسم خطوط مستقيمة بحيث ترسم الخط من النُّقطة الحالية إلى نقطة محددة بـ (x, y). النقطة الحالية تتعلق بآخر مسار تم رسمه (أي أن النُّقطة الأخيرة لرسم المسار الأول هي نقطة بداية رسم المسار الثاني) يمكنك تغيير النُّقطة الحالية عبر استدعاء الدَّالة ()moveTo كما شرحنا في المثال السابق. لنقم بعمل مثال آخر لرسم مثلَّثين أحدهما solid والآخر stroke باستخدام الدالتين ()lineTo و ()moveTo واستدعاء الدَّالة ()lineTo مرتين لكل عملية رسم مثلَّث كما في السكربت التالي: <script> function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); // Filled triangle ctx.beginPath(); ctx.moveTo(100, 100); ctx.lineTo(180, 100); ctx.lineTo(100, 180); ctx.fill(); // Stroked triangle ctx.beginPath(); ctx.moveTo(125, 125); ctx.lineTo(125, 45); ctx.lineTo(45, 125); ctx.closePath(); ctx.stroke(); } } </script> قمت باستدعاء الدَّالة ()beginPath عند البدء في رسم الشكل ثم استدعاء الدَّالة ()moveTo للانتقال لنقطة بداية الرَّسم. ثم بعد ذلك استدعاء الدَّالة ()LineTo مرّتين لرسم المثلَّث بالإحداثيات المناسبة. الآن استدعاء الدَّالة ()closePath عند الانتهاء من رسم المثلَّث من نوع storke لإغلاق المسار لأنه في حال عدم استدعاء هذه الدَّالة سيقوم برسم خطين فقط وليس مثلَّثا كاملًا. الأقواس Arcs يتم رسم الأقواس باستخدام الدالتين ()arc أو ()arcTo. تقوم الدالة (arc(x, y, radius, startAngle, endAngle, anticlockwise برسم قوس عند النُّقطة (x, y) بمقدار القطر radius r ببداية الزَّاوية startAngle وانتهاءً بالزَّاوية endAngle وبالاتجاه anticlockwise (القيمة الافتراضية تكون مع اتجاه عقارب الساعة clockwise). تقوم الدالة (arcTo(x1, y1, x2, y2, radius برسم قوس بمجموعة نقاط وقطر radius يتصل بالنُّقطة السابقة بواسطة خط مستقيم. إنَّ الدَّالة ()arcTo تأخذ 5 معاملات arguments: (x, y) وهما إحداثيي مركز الدائرة التي سيرسم عندها القوس القطر raduis هو قطر الدائرة المعاملان startAngle و endAngle يُحدّدان بداية ونهاية نقاط القوس بالراديان radians على طول قوس الدائرة حيث أنها تقاس من المحور x المعامل anticlockwise هو متغير منطقي Boolean عندما يأخذ القيمة true سيتم رسم القوس عكس اتجاه عقارب الساعة وإلا سيتم رسم القوس باتجاه عقارب الساعة. ملاحظة: الزَّوايا في الدَّالة ()arc تقاس بالراديان radians وليس بالدّرجات، للتحويل من الدّرجات للراديان يمكنك استخدام السكربت: radians = (Math.PI/180)*degrees سأقوم بعرض مثال يشرح طريقة رسم مجموعة من 12 قوسًا بزوايا مختلفة، حيث ستُعرض الأقواس على شكل صفوف (أسطر وأعمدة) في كل صف ثلاث أقواس. سيتم إنشاء حلقتي تكرار وتطبيقهما على أسطر وأعمدة الأقواس. لكل مسار قوس سيتم استدعاء ()beginPath في السكربت لإنشاء مسار جديد في كل مرّة لرّسم شكل جديد. قمت بتخزين كل معامل للدالة arc ضمن متغير لتسهيل استخدامها عند استدعاء الدَّالة. القطر radius وزاوية البداية startAngle هما ثوابت. أمّا زاوية النّهاية endAngle تبدأ من 180 درجة (نصف دائرة) في العمود الأول. وتزداد بمقدار 90 درجة لتصل إلى دائرة كاملة في العمود الأخير. في السّطر الأوّل والثّالث سيتم رسم الأقواس باتجاه عقارب الساعة، وفي السّطر الثّاني والرّابع سيتم رسم الأقواس عكس اتجاه عقارب الساعة. أخيرًا الشرط if سيقوم بعرض أقواس مُفرغة Stroke في الجزء العلوي من الصّفوف وأقواس ذات مساحة لونية solid في الجزء السُّفلي من الصّفوف. سنكون بحاجة إلى canvas بقياسات 150*200. function draw() { var canvas = document.getElementById(‘canvas’); if (canvas.getContext) { var ctx = canvas.getContext(‘2d’); for (var i = 0; i < 4; i++) { for (var j = 0; j < 3; j++) { ctx.beginPath(); var x = 25 + j * 50; var y = 25 + i * 50; var radius = 20; var startAngle = 0; var endAngle = Math.PI + (Math.PI * j) / 2; var anticlockwise = i % 2 == 0 ? false : true; ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise); if (i > 1) { ctx.fill(); } else { ctx.stroke(); } } } } } المنحنيات التكعيبية والتربيعية Cubic and Quadratic Curves تخيّل أنّك تريد إنشاء قوس مائل أو قوس بقمة حادة أو أي نوع من الأقواس المعقدة، توفّر لك الدَّالة ()quadraticCurveTo إمكانيّة رسم أقواس ومنحنيات تربيعية Quadratic Curves والدَّالة ()bezierCurveTo تقوم برسم أقواس أو منحنيات تكعيبية cubic أو ما يعرف بـBézier Curves منحنيات بيزيير. 1- رسم منحني تربيعي تقوم الدالة (quadraticCurveTo(cp1x, cp1y, x, y برسم منحني بيزيير Bézier تربيعي من النُّقطة الحاليّة إلى نقطة معيّنة محددة بـ (x, y) باستخدام نقطة تحكم control point المحدّدة بـ cp1x و cp1y. تقوم الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y برسم منحني بيزيير Bézier تكعيبي cubic باستخدام النّقاط المتحكّمة عن طريق (cp1x, cp1y) و (cp2x, cp2y). الصورة التّالية توضّح الفرق بين المنحنيين Quadratic و cubic: لاحظ أن منحني Bézier من الدّرجة الرّابعة لديه نقطة بداية ونقطة نهاية (النقاط الزرقاء) ونقطة تحكم واحدة (النُّقطة الحمراء) في حين أن منحني Bézier من الدرجة الثالثة لديه نقطتي تحكم. المعاملين x و y في كلا الدّالتين هما إحداثيات نقطة النّهاية. المعاملين cp1x و cp1y هما إحداثيات نقطة التحكم الأولى، المعاملين cp2x و cp2y هما إحداثيات نقطة التحكم الثانية. لنأخذ مثالًا عن كيفية إنشاء منحني Bézier تربيعي سيكون المثال مسلي بعض الشيء إذ أنني سأقوم بإنشاء بالون محادثة speech balloon: function draw() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.moveTo(75, 25); ctx.quadraticCurveTo(25, 25, 25, 62.5); ctx.quadraticCurveTo(25, 100, 50, 100); ctx.quadraticCurveTo(50, 120, 30, 125); ctx.quadraticCurveTo(60, 120, 65, 100); ctx.quadraticCurveTo(125, 100, 125, 62.5); ctx.quadraticCurveTo(125, 25, 75, 25); ctx.stroke(); } } تقوم الدَّالة ()quadraticCurveTo برسم منحني بالإحداثيات ونقطة التحكم المناسبة عند استدعائها بالقيم وبالترتيب أعلاه: 2- رسم منحي تكعيبي في المثال التالي شرح استخدام الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y لرسم منحنيات من الدرجة الثالثة. تفيدنا هذه الدَّالة في رسم أشكال أكثر تعقيدًا لنأخذ مثلًا شكل القلب: function draw() { var canvas = document.getElementById(‘canvas’); if (canvas.getContext) { var ctx = canvas.getContext(‘2d’); ctx.beginPath(); ctx.fillStyle = "rgb(200,0,0)"; ctx.moveTo(75, 40); ctx.bezierCurveTo(75, 37, 70, 25, 50, 25); ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5); ctx.bezierCurveTo(20, 80, 40, 102, 75, 120); ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5); ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25); ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); ctx.fill(); } } ينتج عن استدعاء الدَّالة (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y بالقيم وبالترتيب أعلاه الشكل: ها قد أنهينا تفاصيل إنشاء ورسم أشكال بطرق مختلفة على عنصر اللوحة Cancas، بوصولك إلى هنا تكون قد كونت معرفة ممتازة عن كيفية رسم مستطيلات، مثلثات، خطوط، أقواس ومنحنيات وأيضًا التعامل مع المسارات في Canvas. سنقوم في الدرس المقبل بـإنشاء شكل رسومي أكثر احترافية باستخدام كل تلك الأدوات معًا. المصادر
  2. تعرّفنا في الدرس السابق على القسمين الثاني والثالث من بنية المشاريع في إطار العمل Django وهما العروض Views والقوالب Templates، وقد تحدّثنا عن العروض وآلية عملها بشكل مفصّل، وسنتطرّق في هذا الدرس بشيء من التفصيل إلى القوالب وآلية عملها وسنتعرّف كذلك على محرّك القوالب الخاص بـ Django. ما هي القوالب؟ نظرًا لكون Django إطار عمل للويب فإنّه بحاجة إلى وسيلة لتوليد شيفرات HTML بصورة ديناميكية، ويستخدم Django القوالب لهذا الغرض، إذ يحتوي القالب على أجزاء ثابتة تضم شيفرة HTML وCSS إضافة إلى صيغة برمجية خاصة تتحكم في طريقة إضافة المحتوى الديناميكي إلى القالب تسمى لغة قوالب Django (DTL). قالب Django عبارة عن ملف نصي يستخدم لغة قوالب Django، ويتضمن هذا الملف بعض الأمور التي يتم تفسيرها من قبل محرك القوالب، وأهمّها المتغيرات واﻷوسمة. ﻻ بدّ أنّك قد لاحظت أنّه في كلّ مرة أجرينا فيها عملية ربط القالب، فقد قمنا بتعريف سياق المتغيرات Variable Context معه. يقوم Django بتصيير Rendering القالب مع السياق المرتبط به، حيث يتم استبدال أسماء المتغيرات بالقيم المرتبطة بها وذلك بعد مطابقتها مع سياق المتغيرات المرفق مع القالب، ويتم كذلك تنفيذ الوسوم الموجودة في ملف القالب، أما ما تبقى في هذا الملف فيظهر كما هو. المتغيرات يعرض المتغير القيمة المرتبطة به عن طريق السياق، وهو قاموس يضم مجموعة من المفاتيح والقيم المرتبطة بها. لاستخدام المتغيرات في قوالب Django يكفي إحاطتها بقوسين معقوفين بالشكل التالي: My first name is {{ first_name }}. My last name is {{ last_name }}. فلو كان سياق المتغيرات بالشكل التالي: {'first_name: 'Mohammed', 'last_name': 'Taher'} تكون النتيجة: My first name is Mohammed. My last name is Taher. الوسوم تؤدي الوسوم مهام متعدّدة ومتنوعة، فيمكن للوسم أن يعرض محتوى معين، أو يؤدي وظيفة بنى التحكم كجمل If الشرطية وحلقات for التكرارية، أو جلب محتوى من قاعدة البيانات، وغير ذلك الكثير. تحاط الوسوم في القوالب بقوس معقوف وعلامة النسبة المئوية، كما في المثال التالي: {% csrf_token %} ومعظمها يتقبل المعاملات: {% cycle 'odd' 'even' %} وتتطلب بعض الوسوم تحديد وسم البداية والنهاية: {% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %} لنلقِ نظرة اﻵن على أشيع الوسوم المستخدمة في لغة قوالب Django: الجمل الشرطية يتحقّق الوسم {% if %} من قيمة المتغير، فإذا كانت القيمة صحيحة (بمعنى أنّ المتغير موجود، وليس فارغًا، ولا يحمل قيمة false) يتم عرض محتوى المتغير: {% if article_list %} Number of articles: {{article_list|length}} {% elif article_in_archive %} The Articels are in Archive. {% else %} No articles. {% endif %} ﻻحظ أنّه يمكن استخدام وسمي {% elif %} و {% else %} لمرة واحدة أو لعدة مرات ضمن الوسم If، وﻻحظ أيضًا أن هذا الوسم يتطلب وجود وسم إغلاق. يمكن استعمال المعاملات المنطقية (and, or, not) في الوسم If، كما يمكن استخدام المعاملات الرياضية (==, !=, <, >, <=, >=, in)، إضافة إلى إمكانية دمج هذه المعاملات مع بعضها البعض، إليك بعض اﻷمثلة: {% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} {% if athlete_list and coach_list or cheerleader_list %} There are some athelets and maybe some coaches or cheerleaders. {% endif %} {% if somevar == "x" %} This appears if variable somevar equals the string "x" {% endif %} {% if "bc" in "abcdef" %} This appears since "bc" is a substring of "abcdef" {% endif %} {% if user in users %} If users is a QuerySet, this will appear if user is an instance that belongs to the QuerySet. {% endif %} حلقة for التكرارية يؤدي هذا الوسم نفس الوظيفة التي تؤديها أي حلقة for في أي لغة برمجية، إليك هذا المثال: <ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul> يمكن المرور على عناصر مصفوفة معينة وبصورة عكسية بإضافة كلمة reversed: {% for obj in list reversed %} ويمكن إظهار عناصر قائمة معينة بالشكل التالي: {% for x, y in points %} There is a point at {{ x }},{{ y }} {% endfor %} ويمكن استخدام هذا الوسم للعرض المفاتيح والقيم المرتبطة بها في قاموس معين: {% for key, value in data.items %} {{ key }}: {{ value }} {% endfor %} يمكن الوصول إلى عداد الحلقة التكرارية بأساليب مختلفة، وذلك عن طريق مجموعة من المتغيرات يقدّمها محرّك القوالب في Django. فمثلًا forloop.counter يظهر العدد الحالي للحلقة ويبدأ عدّ الحلقات من الرقم 1، و forloop.counter0 الذي يؤدي نفس الوظيفة ولكن يبدأ العدّ من الرقم 0، و forloop.first والذي يعطي قيمة True إن كانت الدورة الحالية هي الدورة اﻷولى ضمن الحلقة، وforloop.last والذي يؤدي نفس الوظيفة ولكن عند الوصول إلى الدورة اﻷخيرة ضمن الحلقة. إليك هذا المثال لتوضيح الموضوع: {% for photo in gallery %} {% if forloop.counter == 1 %} Do something with {{ photo }}. {% endif %} {% endfor %} تبدأ حلقة for بالمرور على عناصر مجموعة معرض الصور gallery ويتحقق وسم if أثناء ذلك من العدد الحالي للحلقة، فإن كانت الحلقة هي اﻷولى يتم تنفيذ الشرط، وإلا فلا. الشيفرة السابقة مطابقة للشيفرة التالية: {% for photo in gallery %} {% if forloop.first %} Do something with {{ photo }}. {% endif %} {% endfor %} تقدّم لغة قوالب Django عددًا كبيرًا من الأوسمة التي تؤدي وظائف متعددة ومتنوعة، ويمكنك الاطلاع على جميع الوسوم المتوفرة ووظائفها من هنا. المرشحات Filters تعمل المرشّحات على إجراء تحويل معيّن على قيم المتغيرات والأوسمة، وتستخدم بالشكل التالي: {{ hsoub|title }} {% if messages|length >= 100 %} You hove lots of messages. {% endif %} يعمل المرشح title على تحويل الحرف اﻷول من كل كلمة في قيمة المتغير إلى حرف كبير، فلو كان السياق معرفًا بالشكل التالي: {'hsoub': 'on a mission to develop the arab world'} فإن الحرف اﻷول من كل كلمة في العبارة السابقة سيتحول إلى حرف كبير: On A Mission To Develop The Arab World يمكن لبعض المرشحات أن تتقبل المعاملات: {{ my_date|date:"Y-m-d" }} يقدم محرّك قوالب Django عددًا كبيرًا من المرشحات التي تؤدي وظائف مختلفة، كتنسيق الوقت والتاريخ، وعرض الجمل المناسبة لصيغتي المفرد والجمع، وتكبير اﻷحرف اﻹنكليزية وتصغيرها، وحساب عدد الكلمات وغيرها الكثير. يمكنك الاطلاع جميع المرشحات المتوفرة ووظائفها من هنا. استخدام محرّك القوالب في تطبيق الاقتراعات لنعد اﻵن إلى تطبيق الاقتراعات الذي نعمل على إنشائه ضمن هذه السلسلة، ولنتوجه إلى ملف templates/polls/index.html الذي يحتوي الشيفرة التالية: {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>الاقتراعات غير متوفرة حالياً.</p> {% endif %} ﻻحظ أنّنا نستخدم في هذا الملف عددًا من المتغيرات واﻷوسمة، إذ يبدأ الملف بوسم If يتحقق من قيمة المتغير latest_question_list الموجود في سياق المتغيرات المرفق مع القالب، فإن كانت نتيجة التحقق صحيحة، يضاف وسم <ul> إلى الملف ثم تبدأ حلقة for بالعمل، حيث تمرّ على جميع عناصر القائمة latest_question_list وإسناد كل قيمة إلى المتغير question. ﻻحظ أن هذا المتغير يضمّ متغيرات فرعية (إن صح التعبير) تحمل قيمًا مختلفة، مثل question.id و question.question_text. تقوم بالحلقة بسرد عناصر القائمة مع إضافة وسمي <li> و <a> إلى كل عنصر، وبعد الانتهاء يضاف الوسم </ul>. استخدمنا الوسم else لعرض رسالة تخبر المستخدم بعدم وجود أي اقتراعات في الوقت الحاضر في حال كانت نتيجة التحقق خاطئة. توجّه اﻵن إلى الملف detail.html وعدّله ليصبح بالشكل التالي: <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> ستعمل الشيفرة السابقة على عرض اﻷجوبة المرتبطة بالسؤال الذي اختاره المستخدم على هيئة قائمة نقطية. توليد الروابط بصورة ديناميكية هناك مشكلة صغيرة في قالب index.html وهي أننا قمنا بكتابة مسار الرابط بأنفسنا، ولم يتم توليد هذا المسار ديناميكيًا، اﻷمر الذي يجعل من تبديل المسار في وقت لاحق أمرًا صعبًا خصوصًا إن تضمن القالب مسارات عديدة. يمكن لـ Django أن يتكفل بعملية توليد مسارات الروابط بشكل كامل، وذلك باستخدام الوسم {% url %} ليصبح الملف index.html بالشكل التالي: {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>الاقتراعات غير متوفرة حالياً.</p> {% endif %} ولكن كيف يتعرّف Django على المسار المطلوب؟ يستخدم Django قيمة المعامل name الذي قمنا بتعريفه في الدرس الرابع من هذه السلسلة (المسارات في Django). توجّه إلى ملف polls/urls.py والق نظرة على المسار الخاص بعرض detail: url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail') ﻻحظ أن هذا المسار يحمل اسمًا خاصًّا به، وقد عرّفناه من خلاله المعامل name. بهذه الطريقة يتعرّف Django على المسار المطلوب استخدامه في القوالب. واﻵن إن كنت ترغب في تغيير المسار المرتبط بهذا العرض إلى مسار آخر، وليكن polls/specifics/12/ على سبيل المثال، فيمكن تعديله ضمن ملف polls/urls.py بدلًا من تعديل المسار في القالب أو القوالب التي تم استخدامه فيها: url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'), استخدام نطاقات اﻷسماء للتمييز بين المسارات يتضمن مشروعنا هذا تطبيقًا واحدًا فقط وهو تطبيق الاقتراعات، ولكن المشاريع الحقيقية تتضمن عددًا كبيرًا من التطبيقات، فكيف يمكن لـ Django إذًا أن يميز بين أسماء المسارات في هذه الحالة؟ على سبيل المثال، يحتوي تطبيق الاقتراعات على عرض باسم detail، وقد يحتوي المشروع على تطبيق مدونة يتضمن عرضًا باسم detail أيضًا، فكيف يمكن لـ Django أن يتعرف على المسار المطلوب عند استخدام الوسم url في ملف القالب؟ اﻹجابة هي نطاقات اﻷسماء Namespaces. توجه إلى الملف polls/urls.py وأضف اسم التطبيق في بداية قائمة أنماط المسارات، ليصبح الملف بالصورة التالية: from django.conf.urls import url from . import views app_name = 'polls' urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'), url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ] واﻵن عدّل العبارة التالية في القالب polls/index.html: <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> لتصبح بالشكل التالي: <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> ختامًا لا زالت هناك بعض اﻷمور اﻷساسية التي تنقص تطبيق الاقتراعات، فصفحات التطبيق غير منسّقة، كما أنّه لا يوفّر للمستخدم طريقة واضحة للتصويت على الاقتراعات. في الدرس القادم سنتعرّف على كيفية التعامل مع النماذج Forms بصورة مبسطة لتهيئة آلية التصويت على الاقتراعات، وسنتعرف كذلك على العروض العامة Generic views وسنرى كيف يمكن لهذه العروض أن تختصر الوقت والجهد. بعد ذلك سنقوم بإضافة التنسيقات الخاصة بتطبيق الاقتراعات بواسطة CSS وسنتعرف على مفهوم الملفات الساكنة Static Files في Django. المصدر: توثيقات Django
  3. تحدّثنا في بداية هذه السلسلة عن أن مشاريع إطار العمل Django تتبع بنية Model-View-Template (النموذج - العرض - القالب) وبعد أن تطرقنا في الجزء الثالث من هذه السلسلة إلى النماذج Models وآلية عملها، سنشرع في هذا الجزء بالحديث عن القسم الثاني من بنية المشاريع ألا وهو العروض Views. والعروض في Django هي صفحة ويب في تطبيق Django تؤدي وظيفة معينة وترتبط بقالب Template معين. فعلى سبيل المثال إن كان التطبيق الذي نعمل عليه عبارة عن مدونة، فإنه سيتضمن العروض التالية: الصفحة الرئيسية للمدونة، تعرض المقالات التي أضيفت مؤخرًا. صفحة المقالة، تعرض نص المقالة وتوفّر الرابط الدائم لها. أرشيف المدونة حسب السنوات، تعرض المقالات المنشورة في سنة معينة. أرشيف المدونة حسب الأشهر، تعرض المقالات المنشورة في شهر معين. أرشيف المدونة حسب الأيام، تعرض جميع المقالات المنشورة في يوم معين. حدث التعليق على المقالة، ويتحكم في عملية إضافة التعليقات على مقالة معينة. نرى مما سبق أن العروض تقوم بوظائف متعددة، فهناك عروض مسؤولة عن عرض المقالات إما باختيار المقالة المطلوبة من قبل المستخدم أو البحث عنها من خلال الأرشيف، وهناك عرض يتولى مسؤولية التحكم بعملية إضافة التعليقات في المدونة. سيتضمن تطبيق الاقتراعات الذي نعمل عليه ضمن هذه السلسلة العروض الأربعة التالية: صفحة الأسئلة الرئيسية index، والتي نعرض فيها آخر الأسئلة المضافة. صفحة تفاصيل السؤال detail، نعرض فيها نص السؤال، إلى جانب نموذج للتصويت. صفحة نتائج السؤال results، نعرض فيها نتائج التصويت على سؤال معين. حدث التصويت، نتحكم من خلاله بعملية التصويت على سؤال معين. ذكرنا في الدرس السابق أن اختيار العرض المناسب وتنفيذه في Django يتم بالاعتماد على المسار الذي يدخله المستخدم في شريط العناوين في المتصفح، إذ يرتبط كل عرض بمسار محدد ويتم تنفيذ العرض عندما يتطابق المسار الذي أدخله المستخدم مع أحد المسارات الموجودة في ملف urls.py، وقد قمنا بذلك بالفعل في الدرس السابق من هذه السلسلة. آلية عمل العروض تقتصر وظيفة العروض على القيام بأمرين اثنين: إرجاع كائن HttpResponse يتضمن محتوى الصفحة المطلوبة. إطلاق استثناء مثل Http404. والباقي عائد إليك، إذ يمكنك أن تجلب عددًا من السجلات من قاعدة البيانات باستخدام العروض، أو يمكنك استخدام نظام القوالب الخاص بـ Django أو أي نظام قوالب آخر، كما يمكنك إنشاء ملفات PDF أو XML أو إنشاء ملفات مضغوطة ZIP… الخ. عمليًا، يمكنك القيام بما تشاء وباستخدام أي مكتبة من مكتبات بايثون، وكل ما يحتاجه Django هو الكائن HttpResponse أو الاستثناء. لنقم الآن بكتابة عرض بسيط يعمل على جلب آخر خمسة أسئلة في قاعدة البيانات ويعرضها في المتصفح مفصولة عن بعضها البعض بفاصلة (,) ومرتبة حسب تاريخ النشر. توجه إلى polls/views.py ثم أضف الشيفرة التالية: from django.http import HttpResponse from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) لنتحدث عن هذه الشيفرة بشيء من التفصيل: في السطر الأول قمنا باستيراد الكائن HttpResponse من وحدة django.http والصنف Question من ملف النماذج models.py الموجود في نفس المجلد الذي يحتوي الملف views.py، وذلك لنتمكن من الاستعلام عن الأسئلة الموجودة في قاعدة البيانات. بعد ذلك بدأنا بتعريف العرض وذلك من خلال إنشاء الدالة index. في كل دالة عرض يتم تمرير كائن HttpRequest والذي يأخذ عادة الاسم request. من الجدير بالذكر أنك لست مقيدًا بتسمية الدالة باسم معين لكي تؤدي العمل المطلوب، إذ يمكنك أن تسمي الدالة السابقة بأي اسم تشاء، ولكن ينصح بتسمية الدوال بأسماء واضحة يمكن من خلالها معرفة العمل الذي ستؤديه عند العودة إليها في وقت لاحق. يرجع العرض كائن HttpResponse يحتوي الردّ الذي قمنا بإنشائه والذي يتضمن نتيجة الاستعلام عن آخر خمسة أسئلة تم نشرها في الموقع، وذلك بواسطة الواجهة البرمجية الخاصة باستدعاء البيانات الخاصة بـ Django، والتي تحدثنا عنها في موضوع النماذج في Django. قمنا في الدرس السابق بربط العرض index بالمسار r’^$’، وهذا يعني أننا لسنا بحاجة إلى إدخال أي شيء في شريط العناوين سوى عنوان النطاق، وهو الخادوم المحلي الخاص بـ Django. ولمشاهدة مخرجات الدالة التي قمنا بكتابتها، توجّه إلى سطر الأوامر وقم بتشغيل خادوم Django من خلال الأمر التالي: python manage.py runserver افتح المتصفح ثم توجه إلى العنوان التالي: http://127.0.0.1:8000/ ربط العروض بالقوالب أعتقد أنّك لاحظت وجود مشكلة بسيطة في هذه الشيفرة، وهي أن تنسيق المخرجات من خلال إضافة وسوم HTML وتنسيقات CSS وغيرها من الأمور المرتبطة بواجهة الموقع العامة من خلال العروض ليس أمرًا عمليًّا على الإطلاق. هذا يعني أننا بحاجة إلى طريقة لفصل تصميم صفحة الويب عن الشيفرات المكتوبة بلغة بايثون، وهنا يأتي دور القوالب Templates، العنصر الثالث من بنية المشاريع في Django. والقوالب عبارة عن ملفات HTML عادية تتضمن وسوم HTML و تنسيقات CSS وشيفرات Javascript (سواء أكانت شيفرات عادية أم مكتبات مثل Jquery، Angular، React وغيرها)، ولكن الفارق الوحيد هو إمكانية استخدام محرك القوالب Template Engine الخاص بـ Django داخل هذه القوالب. لاستخدام القوالب في مشروعنا هذا، أنشئ مجلدًا باسم templates في مجلد polls، واعتمادًا على الإعدادات الافتراضية فإن Django سيبحث عن ملفات القوالب ضمن هذا المجلد. والآن في مجلد templates أنشئ مجلدًا آخر باسم polls وبداخل هذا المجلد أنشئ الملف index.html، وهكذا يكون مسار ملفنا هذا هو: polls/templates/polls/index.html. والآن يمكن الإشارة إلى هذا القالب باستخدام المسار: polls/index.html فقط. ولكن ما الداعي لإنشاء كل هذه المجلدات؟ في الواقع كان بالإمكان أن نضع الملف index.html في مجلد templates وحسب دون الحاجة إلى إنشاء مجلد polls آخر ضمنه، ولكن من غير المستحسن على الإطلاق القيام بذلك. السبب وراء هذا هو أن Django سيعتمد أول قالب يطابق اسمه الاسم المطلوب، وهذا يعني أنه لو وجد اسم القالب نفسه (index.html في مثالنا هذا) في تطبيق آخر فإنه لن يكون قادرًا على التمييز بينهما؛ لذا يستحسن دائمًا استخدام هذه الطريقة لضمان عدم تداخل القوالب بين التطبيقات المتعددة في المشروع الواحد. والآن أضف الشيفرة التالية إلى ملف index.html الذي أنشأته: {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>الاقتراعات غير متوفرة حالياً.</p> {% endif %} سنتكلم عن محرك القوالب الخاص بـ Django وكل ما يتعلق به في الدرس القادم. بقي علينا ربط العرض index بالقالب index.html؛ لذا توجه إلى الملف polls/views.py وعدله بالشكل التالي: from django.http import HttpResponse from django.template import loader from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request)) في السطر الثاني من الدالة index قمنا بتحميل القالب الذي سيرتبط بهذه الدالة، وذلك من خلال الدالة get_template التابعة للوحدة loader التي قمنا باستيرادها في بداية الملف من الوحدة template. تأخذ الدالة get_template معاملًا وهو عبارة عن سلسلة نصية نحدّد من خلالها مسار القالب الذي نرغب في ربطه بالعرض. بعد ذلك قمنا بتعريف ما يسمى في Django بالسياق context وهو عبارة عن قاموس Dictionary يعمل على ربط المتغيرات التي سنستخدمها في محرك القوالب الخاص بـ Django - متمثلة بالمفتاح الخاص بالقاموس -، مع المتغيرات الموجودة في العرض - متمثلة بالقيمة المرتبطة بذلك المفتاح -. في الشيفرة السابقة، قمنا بربط المتغير latest_question_list في العرض بالمتغير latest_question_list في القالب index.html. وفي نهاية الشيفرة ترجع الدالة index كائن HttpResponse ولكن هذه المرة قمنا بتمرير الدالة render كمعامل لهذا الكائن، وقمنا بتمرير المتغير template والقاموس context كمعاملين لدالة render، والتي تعمل على دمج قالب معين مع السياق المحدد وتعيد كائن HttpRespons يتضمن ما سيعرض في القالب. توجه الآن من خلال المتصفح إلى العنوان التالي، بعد تشغيل الخادوم الخاص بـ Django: http://127.0.0.1:8000/polls/ سترى الآن قائمة نقطية تتضمن الأسئلة التي أضفناها في الدروس السابقة إلى قاعدة البيانات. اختصار عرض القوالب باستخدام الدالة render: إن الخطوات السابقة (تحميل القالب ثم تحديد سياق المتغيرات ثم إرجاع الكائن HttpResponse الذي يتضمن النتيجة التي سيعرضها القالب) شائعة جدًّا وتتكرر باستمرار، لذا يقدّم Django اختصارًا لهذه الخطوات باستخدام الدالة render() التابعة لحزمة django.shortcuts والتي تتضمن عددًا من الدوال التي تختصر بعض الخطوات التي تتكرر باستمرار في Django. قم بتعديل الملف polls/views.py ليصبح بالشكل التالي: from django.shortcuts import render from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context) المعامل الأول في دالة render هو كائن request الذي مررناه كمعامل للدالة index، أما المعامل الثاني فهو اسم القالب ومساره على هيئة سلسلة نصية، أما المعامل الثالث فهو قاموس سياق المتغيرات التي نرغب في تمريرها من العرض إلى القالب، وهو معامل اختياري. تعيد هذه الدالة كائن HttpResponse يتضمن ما سيتم عرضه في القالب المحدّد وباستخدام السياق المحدّد. لاحظ أننا لم نعد بحاجة إلى استيراد دالة loader وكائن HttpResponse في بداية الملف. إطلاق الاستثناء Http404 لننتقل الآن إلى دالة العرض المسؤولة عن سرد تفاصيل السؤال الذي يختاره المستخدم؛ لذا توجه إلى الملف polls/views.py ثم أضف السطر التالي في بداية الملف: from django.http import Http404 ثم عدّل الدالة detail لتصبح بالشكل التالي: def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("السؤال المطلوب غير موجود.") return render(request, 'polls/detail.html', {'question': question}) قمنا بتمرير معامل جديد في الدالة detail وهو question_id، وهذا المعامل هو المتغير الذي قمنا بتعريفه في ملف المسارات urls.py في الدرس السابق، ضمن المسار المرتبط بهذه الدالة. يحمل هذا المتغير الرقم الذي سيدخله المستخدم في شريط العناوين والذي سيلتقطه Django بواسطة التعابير النظامية Regular expressions ويسنده إلى المتغير question_id. تبدأ الدالة بالاستعلام عن السؤال الذي يحمل المفتاح الأساسي primary key - يختصر Django اسم هذا المفتاح بالحرفين pk - الذي يطابق قيمة المتغير question_id وإسناد النتيجة إن وجدت إلى المتغير question. وفي حالة عدم وجود هذا السؤال يتم إطلاق الاستثناء Http404 ليُعلم المستخدم بعدم وجود السؤال الذي قام بطلبه. والآن نحن بحاجة إلى القالب detail.html لنتمكن من مشاهدة السؤال المطلوب؛ لذا قم بإنشاء هذا الملف في مجلد templates/polls. سنكتفي هنا بإضافة السطر التالي في هذا الملف، للتأكد من عمل الشيفرة: {{ question }} اختصار خطوات الاستعلام وإطلاق الاستثناء Http404 مرة أخرى، فإن الخطوات السابقة (الاستعلام باستخدام الدالة get وإطلاق الاستثناء Http404) تتكرر باستمرار، لذا يقدّم Django دالة بديلة تختصر هذه العملية، وكما هو متوقع فهذه الدالة موجودة في حزمة django.shortcuts، لذا سنقوم باستيرادها بالشكل التالي مع الدالة render: from django.shortcuts import get_object_or_404, render يمكن الآن استخدام الدالة get_object_or_404() بالشكل التالي: def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) المعامل الأول في الدالة get_object_or_404() هو اسم النموذج الذي نرغب في الاستعلام داخله، أما المعامل الثاني فهو مجموعة من معاملات الكلمة المفتاحية والتي تقوم الدالة بتمريرها إلى دالة get() الخاصة بواجهة Django البرمجية للاستعلام في قواعد البيانات. في حالة عدم وجود الكائن المطلوب تطلق الدالة الاستثناء Http404. يقدّم Django كذلك دالة get_list_or_404() والتي تعمل بنفس الطريقة باستثناء أنّها تستخدم الدالة filter() بدلًا من get()، وتطلق الدالة الاستثناء Http404 في حال عدم وجود القائمة المطلوبة. والآن توجّه إلى العنوان التالي في المتصفح بعد تشغيل خادوم Django، ولاحظ النتيجة: (http://127.0.0.1:8000/polls/1) حاول تغيير رقم السؤال لإطلاق الاستثناء Http404. خاتمة تعرفنا في هذا الدرس على العنصر الثاني من بنية المشاريع في Django ألا وهي العروض، وتعرفنا كذلك على طريقة ربطها بالقوالب والتي تمثّل العنصر الثالث من بنية المشاريع في إطار العمل هذا. وسنتطرق في الفصل القادم بمزيد من التفصيل إلى القوالب وآلية عملها وسنتعرف على محرك القوالب الخاص بـ Django وما يتضمنه من متغيرات ووسوم وغيرها، وسنتعرّف كذلك على العروض المستندة إلى الأصناف والعروض العامة Generic Views. المصادر: توثيقات Django
  4. أصبح من المعروف أهمية العناوين (URLs) في تهيئة المواقع لمُحركات البحث SEO، ولكن ماذا عن تأثيرها على تحليل المواقع analytics؟ وهل يجب الاهتمام بها؟ ولماذا؟ هذا ما سيجيب عنه المقال. كنت أراجع أحد الملخصات التحليلية والتي قد كنت قمت بها منذ فترة، ما لفت نظري أن حصولي على نتائج وتقارير مُجدية كان من قبيل الصُدفة ولم أعد له بشكل جيّد، بعبارة أخرى، إن كانت بنية روابط الصّفحات URL قد نُفّذت بطريقة منطقيّة لكان الحصول على هذه النتائج أسهل بكثير. مثال حول أهمية بنية الروابط مع تحليل المواقع Analytics سأقوم بتوضيح الفكرة بمثال، لنفرض أنه لدينا موقع لشركة استشارية (أو شركة خدمات) والتي تعتمد بشكل أساسي على خبرة كل فرد من الأفراد في مجاله، ومن أهداف الموقع الرّئيسية هي تسهيل مهمة الزّائر في معرفة الأشخاص المُناسبين ضمن الفريق ممن يستطيع تقديم المُساعدة أو الخدمة التي يبحث عنها. بعض الأشخاص في الشركة شهيرون جدًا في مجالات تخصّصاتهم، لذلك سيصل بعض المستخدمين إلى الموقع عن طريق البحث عن أسمائهم على مُحرّكات البحث، أما باقي أفراد الشّركة فيصل الزّوار إلى صفحاتهم عبر تصفّح مُختلف صفحات الموقع. يأتي الزّوّار إلى الموقع لأسباب عديدة، وليس فقط بغرض البحث عن بيانات حول أعضاء الفريق، ومن أجل ذلك كان المطلوب إنشاء شريحة تحليلية باستخدام Google Analytics، والتي ستُحدّد المستخدمين الذين يبحثون عن أفراد الفريق (الأشخاص)، حيث كان المطلوب استقصاء صفات وميزات هؤلاء الزوّار لتحسين تجربتهم في استخدام الموقع. إن الشريحة segment ما هي إلّا مجموعة جزئية subset من البيانات، والتي توافق معايير معيّنة، وعليه كيف لنا أن نُحدّد هذه المجموعة الجزئية في Google Analytics؟ كيفية إعداد شريحة في Google Analytics الخطوة الأولى: تحديد الصفحات تحديد جميع الصفحات التي تمثل أية زيارة لها إشارة على أن الزائر يَقع ضمن الشريحة التي أتت إلى الموقع بحثًا عن أحد أعضاء الفريق (والتي ستعرّف لاحقًا) وهذه الصفحات هي التالية: صفحة الفريق الرئيسية People، والتي تتضمّن صندوق بحث، وروابط لصفحات تعرض الأشخاص بحسب الترتيب الأبجدي، وجميع هذه الروابط تشترك في الجزء المُتمثل في example.com/people/ (أي أن جميع هذه الرّوابط تحتوي هذا الجزء ضمنها). تملك صفحات التدريب المتخصّصة بالشركة صفحة فرعية تعرض الأشخاص المتخصصين في هذا المجال، جميع هذه الصفحات تحت المسار /services/، وتحتوي سجلّات الأشخاص هذه على detail=people& في آخر العنوان URL، وبالتالي هذا يُسهّل من عملية إضافتها إلى الشريحة، ولو كان العنوان على الشكل /services/servicename/ كان سيكون الأمر أفضل مع محركات البحث SEO وأوضح في القراءة للمستخدم. صفحات الملف الشخصي profile لكل شخص، وهنا نواجه مُشكلًا، حيث أن هذه المسارات/العناوين URLs تكون على الشكل example.com/name_of_the_user/ وهي صفحات هامّة تُحيل إليها محركات البحث، لذلك لا يمكن تجاهلها في تعريف الشريحة، ولكن يوجد عدد كبير من الأشخاص ليتم إضافتهم بشكل يدوي وصريح، إذًا نحتاج شيئًا يميّز هذه الصفحات عن غيرها، وهذا ما كان، حيث أن عناوين titles هذه الصفحات هي من الشكل "User Name | People |"، وعليه يمكن استخدام هذه العناوين في تعريف الشريحة. الخطوة الثانية: استخدام Google Analytics لإنشاء الشريحة سيتمّ اختيار "إضافة شريحة" من صفحة "إعداد التقارير"، ومنها اختيار "شريحة جديدة"، واختيار اسم مُناسب لها في "اسم الشريحة"، وليكن "الباحثون عن أشخاص" (People seeker). سيتمّ بعد ذلك إضافة المعايير التي من شأنها تحديد الزيارة في الشريحة، فعندما يزور المستخدم واحدة من صفحات التي تحتوي في مسارها URL على /people/ أو detail=people& أو الصفحات التي تحتوي في عنوانها على "| People |" ستكون هذه الصفحة مطابقة لتعريف الشريحة، ولذلك تمّ استخدام أو لجمع المعايير الثلاث، أي أحد هذه الشروط الثلاث سيُجّل من ضمن الشريحة. يُلاحظ كيف تمّ استخدام "عنوان الصفحة" (المعيار الثالث) لاختيار صفحات الملفّ الشخصي لكل شخص. تصميم أفضل يؤدي إلى تحليل أفضل تمّ استكمال المثال السابق عبر استخدام "عنوان الصفحة" كمعيار في تعريف الشريحة، وهذا الأسلوب قد لا ينجح دائمًا، فمن المحتمل جدًا ورود "people" في عناوين باقي الصفحات فمن الضروري وجود اختلاف ولو بسيط مثل "|" لتمييز هذه الصفحات عن بعضها، وإلا فلا يوجد طريقة لتمييز هذه الصفحات. يُهمل المطّورون الوسم title غالبًا، لذا قد يكون من غير الحكمة الاعتماد عليها كاستراتيجيّة في التحليل في المواقع المتوسطة والكبيرة، الأمر الذي يؤدي إلى نتائج غير دقيقة في التحليل. يُنصح من أجل ذلك بالتخطيط المسبق وفي مرحلة التطوير فعلى سبيل المثال، حال مثالنا السابق سيكون أفضل بكثير لو كان المسار URL على الشكل التّالي/people/name_of_the_user/، لكان من الممكن عندها ببساطة المطابقة باستخدام تعبير نمطي regular expression مثل /people/[a-zA-Z0-9]+/. خاتمة كما أسلفت سابقًا، إن بُنية المسار URL ليست من أجل محركات البحث فقط، فالاهتمام به والتخطيط له مسبقًا في مرحلة التطوير أمر حتمي ولا يُمكن تجاهله، وذلك من أجل الحصول على تحليل أفضل ونتائج دقيقة تُمثّل الواقع بالفعل. ترجمة -وبتصرّف- للمقال URL structures and analytics لصاحبه Chris Scott.
×
×
  • أضف...