البحث في الموقع
المحتوى عن 'mvt'.
-
يفتقر تطبيق الاقتراعات الذي نعمل على إنشائه إلى آلية جيّدة للتصويت على الأسئلة التي يتم عرضها للمستخدم، لذا يجب علينا توفير استمارة تتيح للمستخدم التصويت على الإجابة التي يرغب بها. إضافة إلى ذلك، سنتعرف في هذا الدرس على العروض العامة التي تهدف إلى اختصار الوقت والجهد عبر التخلّص من العمليات المتكررة بصورة دائمة، مثل جلب البيانات من قاعدة البيانات وعرض النتائج في صفحة مستقلة. وفي نهاية الدرس سنتعرف على الملفات الساكنة وسنضيف بعض التنسيقات إلى تطبيق الاقتراعات. إنشاء استمارة بسيطة يفترض أن يكون المستخدم قادرًا على اختيار إحدى الإجابات الخاصة بسؤال معين، ولكن قالب detail بشكله الحالي لا يوفّر هذا اﻷمر، لذا سنحتاج إلى إضافة استمارة إلى هذا القالب. توجّه إلى الملف polls/detail.html في مجلد القوالب templates ثم أضف إليه الشيفرة التالية: <h1>{{ question.question_text }}</h1> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="post"> {% csrf_token %} {% for choice in question.choice_set.all %} <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br /> {% endfor %} <input type="submit" value="صوّت" /> </form> يعمل السطر الأول على جلب نص السؤال ووضعه داخل وسم <h1> لعرضه بشكل واضح وكبير. في السطر الثاني يتم التحقق مما إذا كان المتغير error_message يحمل قيمة أم ﻻ، فإن كان كذلك يتم عرض هذه القيمة وإلا فلا، سنستخدم هذا المتغير بعد قليل في العرض المسؤول عن التصويت، حيث سيحمل هذا المتغير قيمة نصية وهي عبارة عن رسالة نخبر المستخدم فيها أنّه لم يقم باختيار أي إجابة من الإجابات المعروضة. في السطر الثالث أنشأنا استمارة يتم توليد قيمة الحدث action فيه بصورة ديناميكية، وذلك باستخدام الوسم url والمسار vote والمتغير question.id والذي يمثّل الرقم المعرف للسؤال، وستكون طريقة إرسال الحدث هي POST، وبما أننا نعتمد هذه الطريقة، فعلينا الانتباه إلى حماية المعلومات من تزوير الطلب عبر المواقع Cross-site request forgery والمعروف اختصارًا بـ CSRF. ولكن لا تقلق، يوفّر Django نظامًا سهل الاستخدام لتجنّب هذه المشكلة. باختصار، يجب عليك وضع الوسم {% csrf_tocken %} في أي استمارة تعتمد طريقة POST ﻹرسال اﻷحداث. تعمل الحلقة for على إضافة زر اختيار Radio button إلى الإجابات الخاصة بالسؤال الذي اختاره المستخدم، ويتم جلب هذه الإجابات من باستخدام العبارة question.choice_set.all. والآن لنقم بإنشاء العرض الذي سيتحكم في البيانات المرسلة إلى الخادوم. أعتقد أن سير العمل في Django قد أصبح واضحًا في هذه المرحلة، ففي البداية نقوم بتعريف المسار، ثم نربط هذا المسار بالعرض الذي سيكون مسؤولًا عن القيام بأي شيء نرغب به، وبعد ذلك نربط هذا العرض بالقالب الذي سيظهر النتائج. وقد قمنا فعلًا بالخطوة الأولى من سلسلة الخطوات هذه في الدرس الرابع من هذه السلسلة عندما بدأنا الحديث عن المسارات، حيث يتضمن ملف polls/urls.py المسار التالي: url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote') هذا المسار مرتبط بالعرض view والذي قمنا بإنشائه في الدرس نفسه: def vote(request, question_id): return HttpResponse("أنت تصوت على السؤال %s." % question_id) لنقم الآن بكتابة الشيفرة المسؤولة عن عملية التصويت ضمن هذا العرض، لذا توجّه إلى ملف views.py وأضف الشيفرة التالية في بداية الملف: from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from .models import Choice, Question ثم عدّل دالة vote لتصبح بالشكل التالي: def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', {'question':question, "error_message": "لم تقم بالتصويت على السؤال"}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) لنتكلم عن الشيفرة السابقة بشيء من التفصيل، فهناك عدد من الأمور الجديدة فيها: request.POST هو عنصر شبيه بالقاموس يتيح الوصول إلى البيانات المرسلة من الاستمارة بواسطة اسم المفتاح، وفي حالتنا هذا فإن request.POST['choice'] سوف يرجع قيمة المعرّف الخاص بالجواب الذي اختاره المستخدم، وتكون هذه القيمة على هيئة سلسلة نصية. وجدير بالذكر أن Django يقدّم عنصرًا آخر باسم request.GET ويستخدم عندما تكون طريقة إرسال البيانات في الاستمارة هي GET. يطلق العنصر request.POST['choice] خطأً مفتاحيًا KeyError وهذا النوع من الأخطاء يُطلق عندما لا يكون المفتاح المطلوب (ضمن القاموس) موجودًا ضمن مجموعة المفاتيح المتوفرة، وفي تطبيقنا ينطلق هذا الخطأ عندما ﻻ يختار المستخدم أي إجابة من الإجابات المعروضة أمامه، ويعمل على إعادة المستخدم إلى صفحة التصويت مرة أخرى، ولكن هذه المرة مع إضافة العبارة: “لم تقم بالتصويت على السؤال” إلى المتغير error_message، وبعد أن أصبح هذا المتغير يحمل قيمة معينة، سيقوم قالب detail بعرض الرسالة في المكان المناسب. إن تمت عملية التصويت بنجاح يتم إضافة صوت واحد إلى الأصوات الخاصة بالإجابة المختارة من قبل المستخدم، وقد استخدمنا الصنف HttpResponseRedirect بدلًا من الصنف HttpResponse لإعادة توجيه المستخدم إلى صفحة النتائج. هذا الصنف في الواقع هو أحد الأصناف الفرعية للصنف HttpResponse ويأخذ معاملًا واحدًا وهو عنوان URL الذي ستتم إعادة التوجيه إليه. والهدف من استخدام هذا الصنف هو تجنّب إرسال البيانات مرتين في حال ضغط المستخدم على زر الرجوع في المتصفح، وينصح باستخدام هذا الصنف في كل مرة يتم فيها التعامل بنجاح مع بيانات POST، وهذا الأمر ليس خاصًا بـ Django فقط، بل هو من الممارسات الجيدة في مجال تطوير الويب باستخدام أي لغة برمجية. استخدمنا الدالة reverse() في مشيّد الصنف HttpResponseRedirect لنتجنّب الإدخال اليدوي للمسار الذي نرغب بإعادة توجيه المستخدم إليه. يأخذ المعامل الأول في هذه الدالة اسم العرض أو اسم نمط URL المطلوب إعادة التوجيه إليه. في هذا المثال سيتم توجيه المستخدم إلى المسار الذي يحمل اسم polls:results، ولكن هذا المسار يتضمن متغيّرًا، لذا سنخبر Django بأن يأخذ قيمته من المتغيّر question.id وذلك من خلال المعامل args. بمعنى أنّه لو اختار المستخدم السؤال الذي يحمل الرقم 3، فإن الصنف HttpResponseRedirect سيعيد السلسلة النصية التالية: polls/3/results/ حيث أن قيمة question.id في هذه الحالة هو 3. بعد أن يقوم المستخدم بالتصويت على سؤال معين، تعمل دالة العرض vote() على إعادة توجيهه إلى صفحة النتائج الخاصة بذلك السؤال، فلنقم إذًا بكتابة دالة العرض الخاصّة بالنتائج. توجّه إلى ملف polls/views.py وعدّل الدالة results لتصبح بالشكل التالي: def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) والآن، قم بإنشاء القالب المسؤول عن عرض النتائج. في مجلد templates/polls/ أنشئ الملف results.html، وأضف إليه الشيفرة التالية: <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {% endfor %} </ul> <a href="{% url 'polls:detail' question.id %}">صوّت مرة أخرى</a> والآن توجّه إلى العنوان التالي في متصفحك بعد تشغيل الخادوم الخاص بـ Django: 127.0.0.1:8000/polls/1/ وستحصل على نتيجة مشابهة لهذه: وبعد التصويت سيتم توجيهك إلى صفحة النتائج: وفي حال عدم التصويت على أي إجابة والضغط على زرّ التصويت، تظهر رسالة الخطأ بالشكل التالي: العروض العامة Generic Views لنلق نظرة على ملف views.py بعد إضافة جميع الدوال إليه: from django.shortcuts import render, get_object_or_404 from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from .models import Choice, Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] return render(request, 'polls/index.html', {'latest_question_list': latest_question_list}) def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/detail.html', {'question': question}) def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, 'polls/results.html', {'question': question}) def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST['choice']) except (KeyError, Choice.DoesNotExist): return render(request, 'polls/detail.html', {'question':question, "error_message": "لم تقم بالتصويت على السؤال"}) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) هل لاحظت أمرًا ما؟ الدالتان detail() وresults() متشابهتان كثيرًا، وفي الواقع الفارق الوحيد بينهما هو القالب الذي يرتبط بكل دالة. إضافة إلى ذلك فإن هاتين الدالتين إضافة إلى دالة index() تقوم بعمل واحد وبسيط، وهو عرض مجموعة من المعلومات على المتصفح. تمثل هذه العروض حالة شائعة جدًّا في عملية تطوير الويب، وهي الحصول على البيانات من قاعدة البيانات بالاستناد إلى معامل يتم تمريره في عنوان URL في المتصفح، ثم تحميل قالب معين، ثم تصيير ذلك القالب على متصفح الإنترنت. لقد ذكرنا في بداية هذه السلسلة أنّ إطار العمل Django يركّز على مبدأ عدم التكرار، وقد رأينا هذا بشكل واضح عند استخدامنا للدوال المختصرة render() و get_object_or_404(). كذلك يوفّر Django في حالتنا هذه طريقة مختصرة للتعامل مع هذه العمليات الشائعة، وهي العروض العامّة. تعمل هذه العروض على اختصار الأنماط المتكررة من الشيفرات إلى درجة لا تعود فيها بحاجة إلى كتابة شيفرة بايثون لكتابة التطبيق. ولاستخدام العروض العامّة يتوجّب علينا إجراء بعض التعديلات البسيطة على شيفرتنا السابقة، ويمكن تلخيص هذه التعديلات بالنقاط التالية: تعديل أنماط URL. الاستغناء عن بعض العروض التي لسنا بحاجة إليها بعد الآن. كتابة عروض جديدة بالاعتماد على عروض Django العامة. تعديل أنماط URL توجّه إلى ملف polls/urls.py وعدّله بالشكل التالي: from django.conf.urls import url from . import views app_name = 'polls' urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'), url(r'^(?P<pk>[0-9]+)/results/$', views.ResultsView.as_view(), name='results'), url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'), ] لاحظ أنّنا استبدلنا <question_id> بـ <pk> في مساري detail و results، وسنتعرف على سبب ذلك بعد قليل. تعديل العروض التعديلات التي سنجريها على العروض ستشمل دوال index(), detail(), results() أما دالة vote() فستبقى دون تغيير: from django.shortcuts import get_object_or_404, render from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from django.views import generic from .models import Choice, Question class IndexView(generic.ListView): template_name = 'polls/index.html' context_object_name = 'latest_question_list' def get_queryset(self): return Question.objects.order_by('-pub_date')[:5] class DetailView(generic.DetailView): model = Question template_name = 'polls/detail.html' class ResultsView(generic.DetailView): model = Question template_name = 'polls/results.html' لاحظ كيف استغنينا بشكل كامل عن الدوال الثلاثة سابقة الذكر لتحلّ محلّها أصناف تحمل أسماءً مشابهة، ونظرًا لاستخدام الأصناف في هذا النوع من العروض، فإنّها تحمل اسم العروض المستندة إلى الأصناف Class based views. لقد استخدمنا نوعين من أنواع العروض العامة، وهما ListView و DetailView. يلخّص العرض اﻷول عملية عرض جميع العناصر، في حين يلخّص العرض الثاني عملية عرض التفاصيل المرتبطة بعنصر معيّن. يحتاج كل عرض عامٍّ إلى التعرّف على النموذج الذي سيتعامل معه، ويتم التصريح عن ذلك في المعامل model. إلى جانب ذلك، يطلب العرض DetailView أن يتم إسناد قيمة المفتاح الرئيسي المأخوذة من عنوان URL إلى متغير يحمل الاسم pk، لهذا السبب قمنا بتبديل question_id بالاسم الجديد في ملف المسارات urls.py. يبحث العرض DetailView بصورة افتراضية عن القالب المرتبط به في المسار <app name>/<model_name>_detail.html، وهذا يعني أنّ هذا العرض سيستخدم القالب polls/question_detail.html بشكل تلقائي. ويمكن تجاوز هذه القيمة التلقائية من خلال تعيين اسم القالب باستخدام المعامل template_name. ينطبق الأمر ذاته على العرض ListView والذي سيستخدم بشكل تلقائي القالب polls/question_list.html. بقي أن نشير إلى أنّنا كنا نزوّد كل قالب بمتغيرات السياق التي سيستخدمها، وفي مثالنا هذا كانت المتغيرات هي question و latest_question_list. عند استخدام العروض العامّة يتم تزويد العرض DetailView بالمتغير question تلقائيًا، وذلك ﻷننا نستخدم النموذج Question، حيث يستطيع Django تحديد اسم مناسب لمتغيرات السياق بناء على النموذج الذي يرتبط بالعرض العام. ويمكن تجاوز القيمة التلقائية هذه بسهولة وذلك بإسناد اسم المتغير الذي نرغب به إلى المعامل context_object_name، وبهذا نخبر Django بأنّنا نرغب باستخدام هذا الاسم بدلًا من الاسم الذي سينشئه بصورة تلقائية وهو في هذه الحالة question_list. كما يمكنك الإبقاء على الاسم الافتراضي question_list إن كنت ترغب في ذلك، ولكن هنا عليك تغيير اسم المتغير في أي مكان يرد فيه ضمن القوالب. الملفات الساكنة Static Files يبدو تطبيقنا بشعًا أليس كذلك؟ لنقم إذًا بإضافة بعض التنسيقات البسيطة إليه، ولنتعرف على مفهوم الملفات الساكنة. إلى جانب ملفات HTML التي ينشئها الخادوم، تحتاج تطبيقات الويب بشكل عام إلى بعض الملفات اﻹضافية - مثل الصور وملفات جافا سكربت وملفات CSS - لعرض صفحات الويب بشكل منسّق ومرتّب، ويطلق Django على هذه الملفات اسم الملفات الساكنة. سنبدأ أولًا بإنشاء مجلد باسم static في مجلد polls الرئيسي، ثم أنشئ داخل المجلد static مجلّدًا جديدًا باسم polls. بمعنى آخر يجب أن يكون مسار ملف CSS بالشكل التالي: polls/static/polls/style.css. كما هو الحال مع القوالب، فإن Django يبحث بنفس الطريقة عن الملفات الساكنة، واستخدام هذه المجلدات هو أمر تنظيمي يتيح لـ Django التمييز بين الملفات الساكنة الخاصة بكل تطبيق. والآن توجّه من خلال محرّر النصوص إلى ملف style.css وأضف إليه الشيفرة التالية: li a { color: green; text-decoration: none; font-size: 1.3em; } والآن توجّه قالب index.html وأضف الشيفرة التالية في بداية الملف: {% load staticfiles %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" /> يعمل الوسم load staticfiles في بداية الملف على تحميل الوسم static المسؤول بدوره عن توليد عنوان URL المطلق للملف الساكن المطلوب. والآن أعد تحميل الصفحة الرئيسية وستلاحظ أن الأسئلة قد تلونت باللون اﻷخضر. ولإضافة صورة للخلفية قم بإنشاء مجلد images في نفس المجلد الذي يحتوي الملف style.css ثم ضع فيه الصورة التي ترغب في جعلها خلفية للصفحة، وعلى فرض استخدام صورة باسم background.gif أضف الشيفرة التالية إلى ملف style.css: body { background: white url("images/background.gif") no-repeat right bottom; } أعد تحميل الصفحة الرئيسية، وستلاحظ أن الصورة قد أصبحت خلفية للصفحة. من الجدير بالذكر أنّه لا يمكن استخدام الوسم {% static %} استخدام داخل الملفات الساكنة والتي لا يتم توليدها بواسطة Django، لذا يجب استخدام المسارات النسبية وليست المطلقة لربط الملفات الساكنة بعضها ببعض. ختامًا تعرّفنا في هذا الدرس على كيفية استخدام نماذج الاستبيان في Django بصورة مبسطة، واستخدمنا بعد ذلك العروض العامّة التي تختصر الكثير من الوقت والجهد، وفي النهاية تعرّفنا على مفهوم الملفات الساكنة وكيفية استخدامها في تطبيقات Django. في الدرس القادم وهو الدرس اﻷخير ضمن هذه السلسلة، سنتحدّث بشيء من التفصيل عن لوحة التحكم التي يتم إنشاؤها بصورة تلقائية مع كل مشروع في Django. المصدر: توثيقات Django
-
وصلنا إلى ختام هذه السلسلة وفي الدرس الأخير منها سنتحدث عن لوحة التحكم التي يقدّمها إطار العمل Django بشكل جاهز مع كل مشروع تقوم بإنشائه، ويمكن الاستفادة من لوحة التحكم هذه في إدارة النماذج Models المستخدمة في المشروع إضافة إلى إدارة مجموعات المستخدمين وصلاحياتهم في إجراء التعديلات على الموقع اﻹلكتروني. الولوج إلى لوحة التحكم لنستعرض المسارات الموجودة في ملف mysite/urls.py: urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^polls/', include(polls_urls)), ] نلاحظ هنا وجود مسارين رئيسيين في مشروعنا هذا، وكما هو واضح فإنّ الولوج إلى لوحة التحكم يتطلب استخدام مسار يتضمن الكلمة admin/، وللتأكد من ذلك ابدأ بتشغيل الخادوم الخاص بـ Django ثم توجّه في المتصفّح إلى العنوان التالي: http://127.0.0.1:8000/admin ستظهر الشاشة التالية: ما تراه على متصفحك هو صفحة الولوج log-in إلى لوحة التحكم الخاصة بالمشروع، ومن الواضح أننا نحتاج إلى اسم مستخدم وكلمة مرور لنتمكن من الدخول إلى لوحة التحكم. لإنشاء حساب مستخدم يمكنه الولوج إلى لوحة التحكم توجّه إلى سطر اﻷوامر ونفذ الأمر التالي: python manage.py createsuperuser سيُطلب منك إدخال اسم المستخدم، ويمكنك استخدام الاسم الذي ترغب به: Username: admin ثم سيُطلب منك إدخال عنوان بريدك اﻹلكتروني: Email address: admin@example.com والخطوة اﻷخيرة هي إدخال كلمة المرور مرتين: Password: ********** Password (again): ********** Superuser created successfully. واﻵن توجه إلى نفس العنوان السابق في المتصفّح، ثم أدخل الاسم وكلمة المرور التي قمت بإدخالها قبل قليل، وستكون قادرًا اﻵن على الولوج إلى لوحة التحكم والتي ستظهر بالشكل التالي: نلاحظ في هذه الصفحة إمكانية تعديل بعض اﻷمور الخاصة بالمستخدمين ومجموعات المستخدمين، ولكن لا نرى ذكرًا لتطبيقنا على اﻹطلاق. سنحتاج في الواقع إلى القيام بخطوة إضافية، وهي إخبار لوحة التحكم بأنّ عناصر الصنف Question في ملف النماذج models.py تمتلك واجهة لوحة تحكم، وللقيام بذلك توجّه إلى ملف polls/admin.py وأضف إليه اﻷسطر التالية: from .models import Question admin.site.register(Question) والآن قم بإعادة تحميل الصفحة الرئيسية للوحة التحكم، وسترى ظهور التطبيق ضمن عناصر الواجهة: ﻻحظ أن Django قادر على تمييز أسماء النماذج واستخلاص أسماء ذات مدلولات أوضح بالنسبة للمستخدم، فقد تعرّف Django في مثالنا هذا على النموذج Question باعتباره نموذجًا يحتوي على عدد من العناصر المتمثلة باﻷسئلة، لذا أضاف (s) الجمع إلى الاسم المعروض في لوحة التحكم. واﻵن انقر على Questions وسترى قائمة باﻷسئلة التي أضفناها برمجيًا إلى النموذج Question في الدروس السابقة. يمكنك كذلك النقر على نص السؤال لتتمكن من تعديله أو حذفه: ﻻحظ كيف أن Django قد قام بإنشاء استمارة Form خاصة بالسؤال تتضمن جميع الحقول التي أضفناها في الصنف Question في الملف polls/models.py، إضافة إلى ذلك، يستخدم Django عناصر HTML المناسبة لكل نوع من أنواع الحقول. كذلك يضيف Django بعض شيفرات Javascript مع كل حقل من نوع DateTimeField لاختيار الوقت والتاريخ حسب الحاجة. تخصيص لوحة التحكم رأينا كيف قام Django ببناء لوحة التحكم والاستمارات الخاصة بالنموذج Question بشكل آلي، ولكن سنحتاج غالبًا إلى تخصيص مظهر لوحة التحكم وآلية عملها، ويمكننا القيام بذلك عند تسجيل النموذج في ملف polls/admin.py؛ لذا توجّه إلى هذا الملف وعدّله بالشكل اﻵتي: from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fields = ['pub_date', 'question_text'] admin.site.register(Question, QuestionAdmin) عرفنا في الشيفرة السابقة صنف model admin وقمنا بتمريره كمعامل ثانٍ للدالة register(). ستعمل هذه الشيفرة على تبديل مواقع حقلي تاريخ نشر السؤال ونص السؤال، ليحل أحدهما محل اﻵخر: يمكن كذلك تقسيم الحقول إلى مجموعات fieldsets وذلك بالشكل التالي: from django.contrib import admin from .models import Question class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date']}), ] admin.site.register(Question, QuestionAdmin) التعامل مع الاختيارات المرتبطة بالسؤال؟ لم نتعامل لحدّ اﻵن مع الاختيارات المرتبطة باﻷسئلة في تطبيق الاقتراعات، وفي الواقع هنا طريقتان للقيام بذلك: الطريقة اﻷولى هي اتباع نفس الخطوات التي قمنا باتباعها في تسجيل الصنف Question وذلك بتعديل ملف polls/admin.py ليصبح بالشكل التالي: from .models import Choice, Question # ... admin.site.register(Choice) قمنا في هذا الشيفرة باستيراد الصنف Choice إضافة إلى الصنف Question، بعد ذلك سجّلنا الصنف Choice باستخدام الدالة register(). واﻵن ستظهر الصفحة الرئيسية للوحة التحكم بالشكل التالي: ويمكن إضافة اختيارات جديدة بالضغط على أيقونة Add Choice أو Add وستظهر صفحة إضافة الاختيار بالشكل التالي: ﻻحظ أنّه يمكنك اختيار السؤال الذي تودّ ربط الاختيار به وذلك من القائمة المنسدلة المعنونة بـ Question، كما يمكنك إضافة سؤال جديد من هذه الصفحة وذلك بالضغط على علامة (+) الخضراء إلى جانب القائمة المنسدلة، أو تحرير السؤال الذي اخترته بالضغط على أيقونة القلم اﻷصفر. لا تبدو هذه الطريقة مفيدة من الناحية العملية، إذ يجب إضافة السؤال الجديد، ثم إضافة الاختيارات وربطها واحدًا تلو اﻵخر بالسؤال. إذًا، أليس من اﻷفضل أن نقوم بإضافة الاختيارات مباشرة عند إضافة السؤال؟ هذه هي الطريقة الثانية. للقيام بذلك توجّه إلى ملف polls/admin.py ثم عدّله ليصبح بالشكل التالي: from django.contrib import admin from .models import Choice, Question class ChoiceInline(admin.StackedInline): model = Choice extra = 3 class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), ] inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin) تخبر الشيفرة السابقة Django بأن الاختيارات يتم تحريرها في صفحة التحكم بالسؤال، إضافة إلى تقديم الحقول اللازمة ﻹضافة 3 اختيارات مع كل سؤال. بناء على ذلك ستظهر صفحة إضافة سؤال جديد بالشكل التالي: ستبرز هنا مشكلة صغيرة وهي أنّه في حال وجود عدد كبير من الاختيارات، فإن المساحة التي ستشغلها هذه الاختيارات ستكون كبيرة جدًّا. يقدّم Django طريقة أخرى لعرض الاختيارات وهي على شكل جدول، ويمكن الوصول إليها بتعديل المعامل في الصنف ChoiceInline ليصبح بالشكل التالي: class ChoiceInline(admin.TabularInline): ستظهر صفحة إضافة سؤال جديد بالشكل التالي: واﻵن بعد أن أجرينا التعديلات اللازمة على صفحة إضافة اﻷسئلة، لنجر بعض التعديلات كذلك على الصفحة الرئيسية التي يتم من خلالها عرض جميع اﻷسئلة المتوفرة في التطبيق. في البداية تظهر هذه الصفحة بالشكل التالي: يستخدم Django بصورة افتراضية مخرجات دالة str() لكل حقل من حقول قاعدة البيانات التي يتم عرضها في الصفحة الرئيسية، ولكننا بحاجة هنا إلى عرض جميع الحقول وليس حقل نصّ السؤال فقط. وللقيام بذلك نستخدم الصف list_display والذي سنضمنه أسماء الحقول التي نرغب في عرضها على شكل أعمدة في الصفحة الرئيسية. توجّه إلى ملف polls/admin.py وعدّل الصنف QuestionAdmin لصبح بالشكل التالي: class QuestionAdmin(admin.ModelAdmin): fieldsets =[ (None, {'fields': ['question_text']}), ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}), ] inlines = [ChoiceInline] list_display = ('question_text', 'pub_date', 'was_published_recently') واﻵن يفترض أن تظهر الصفحة الرئيسية بالشكل التالي: ﻻحظ أن Django قام بتسمية العمود اﻷخير بنفس اسم التابع المستخدم في النموذج Question مع استبدال الشرطات السفلية بفواصل، ويمكننا تغيير هذا الاسم وتحسين طريقة عرض المخرجات في هذا العمود بالتوجه إلى ملف polls/models.py وتعديل الصنف Question ليصبح بالشكل التالي: class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __str__(self): return self.question_text def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now was_published_recently.admin_order_field = 'pub_date' was_published_recently.boolean = True was_published_recently.short_description = 'Published recently?' أعد تحميل الصفحة الرئيسية ولاحظ الفرق: يمكننا إضافة المزيد من التحسينات إلى هذه الصفحة، فمثلًا يمكننا إضافة عمود جانبي يعمل على تصفية اﻷسئلة حسب تاريخ نشرها، وللقيام بذلك أضف السطر التالي إلى الصنف QuestionAdmin: list_filter = ['pub_date'] سيضيف هذا السطر عمودًا جانبيًا إلى الصفحة الرئيسية يتيح لمدير الصفحة تصفية اﻷسئلة حسب تاريخ النشر. ولكن ماذا لو أردنا البحث عن نص سؤال معين بدلًا من البحث بحسب تاريخ النشر؟ يمكن القيام بذلك بإضافة السطر التالي إلى الصنف QuestionAdmin والذي سيعمل على إظهار صندوق للبحث في الصفحة الرئيسية: search_fields = ['question_text'] بعد إجراء التعديلات السابقة ستظهر الصفحة الرئيسية بالشكل التالي: تعديل مظهر لوحة التحكم الخاصّة بالتطبيق من المؤكّد أننا لا نرغب في ظهور عبارة Django administration في رأس كل صفحة من صفحات لوحة التحكم، ويمكن تغيير هذه العبارة باستخدام نظام قوالب Django، فلوحة التحكم هذه تدار بواسطة Django، وتستخدم الواجهة نظام قوالب Django كذلك. أنشئ مجلّدًا باسم templates في مجلّد المشروع (المجلد الذي يحتوي على الملف manage.py)، ثم توجّه إلى ملف اﻹعدادات الخاص بالمشروع mysite/settings.py ثم أضف الخيار DIRS إلى إعدادات القالب بالشكل التالي: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] يحدّد السطر الذي أضفناه إلى إعدادات قوالب المسارات التي يجب على Django البحث فيها عن القوالب، وهنا أخبرنا Django بأن عليه البحث عن المجلد templates ضمن المجلد الرئيسي للمشروع BASE_DIR. تعمل الدالة os.path.join على ربط القيمة التي يتم الحصول عليها من BASE_DIR مع اسم المجلد المطلوب وهو templates. واﻵن أنشئ مجلّدًا جديدًا باسم admin داخل مجلد templates الذي أنشأناه قبل قليل، ثم انسخ إليه القالب base_site.html من مجلد admin الموجود ضمن الملفات المصدرية لـ Django في المسار django/contrib/admin/templates. إن واجهت صعوبة في العثور على الشيفرة المصدرية الخاصة بـ Django توجّه إلى سطر اﻷوامر ونفّذ اﻷمر التالي: python -c "import django; print(django.__path__)" واﻵن قم بتحرير ملف base_site.html واستبدل الشيفرة {{ site_header|default:_('Django administration') }} بالعبارة التي ترغب في ظهورها في رأس كل صفحة من صفحات لوحة التحكم، يجب أن تكون الشيفرة مقاربة لما يلي: {% block branding %} <h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1> {% endblock %} من هنا نلاحظ إمكانية إجراء أي تعديل نرغب به على أي قالب من القوالب الخاصة بلوحة التحكم بنفس الطريقة السابقة، فكل ما علينا فعله هو نسخ القالب المطلوب من الملفات المصدرية لـ Django ولصقه في المجلد المخصّص له، ثم إجراء التعديلات المطلوبة. فعلى سبيل المثال، يمكن تخصيص مظهر الصفحة الرئيسية للوحة التحكم وذلك من خلال نسخ الملف template/index.html من الملفات المصدرية لـ Django بنفس الطريقة السابقة، ثم قم بتحرير الملف، وستجد أنّه يستخدم متغيرًا يحمل الاسم app_list. يتضمن هذا المتغير جميع التطبيقات المثبتة في المشروع الذي تعمل عليه. يمكنك اﻵن استبدال هذا المتغير بروابط تأخذ المستخدم إلى مواضع مختلفة من لوحة التحكم، بدلًا من عرض جميع التطبيقات. تغيير لغة العرض في لوحة التحكم من الخصائص التي يتميّز بها إطار العمل Django دعمه للكثير من اللغات، ومن ضمنها اللغة العربية، ويمكن تغيير لغة واجهة لوحة التحكم إلى اللغة التي نرغب بها من خلال التوجّه إلى ملف اﻹعدادات الخاصّ بالمشروع setteings.py ثم تعديل قيمة المتغير LANGUAGE_CODE الافتراضية 'en' إلى رمز اللغة المطلوبة. فمثلًا لتغيير لغة الواجهة إلى العربية: LANGUAGE_CODE = 'ar' وللغة الفرنسية: LANGUAGE_CODE = 'fr' المصدر: توثيقات Django
-
Django هو إطار عمل مجّاني ومفتوح المصدر، مكتوب بلغة Python، وتتبع المشاريع فيه بنية Model-View-Template (عادة ما تختصر إلى MVT). يؤكّد Django على قابلية إعادة الاستخدام Reusability للمكونات وكذلك على التطوير السريع، بالإضافة إلى مبدأ عدم التكرار. تستخدم لغة Python في جميع مفاصل إطار العمل هذا، كالإعدادات ونماذج قواعد البيانات وغيرها. ومن أشهر المواقع التي تستخدم Django هي: Pinterest ،Instagram ،Mozilla ،The Washington Times ،Disqus ،National Geographic وغيرها الكثير. طوّر Django سنة 2003 على يدي المبرمجين Adrian Holovaty و Simon Willson اللذين يعملان في صحيفة Lawrence Journal World، وذلك عندما انتقلا إلى لغة Python لبناء التطبيقات. ثم أطلق Django سنة 2005 تحت رخصة BSD، وقد سمّي بهذا الاسم تيمنًا بعازف الغيتار Django Reinhardt. بنية MVT تنقسم بنية المشاريع في Django إلى ثلاثة أقسام مرتبطة ببعضها البعض، ولكنّها مختلفة عن أطر العمل الأخرى التي تتبع بنية (MVC - Model, View, Controller) مثل Laravel في PHP وغيرها، حيث تتكون المشاريع في Django من النموذج Model والعرض View والقالب Template. يتولى قسم النموذج معالجة البيانات والتعامل معها واسترجاعها، ويدعم Django العديد من قواعد البيانات، مثل: SQlite ،MySQL، و PostgreSQL. أما العرض فعبارة عن مجموعة من دوال Python التي تستجيب لعنوان URL معين، ووظيفة العرض هي تحديد البيانات والمعلومات التي يجب عرضها. أما القالب فهو عبارة عن ملف بصيغة HTML يتم من خلاله تحديد الطريقة التي ستظهر بها المعلومات التي يعرضها قسم العرض. أين المتحكم Controller إذًا؟ المتحكم هنا هو إطار العمل نفسه، أي الآلية التي يتم من خلالها إرسال الطلب إلى العرض المناسب بالاعتماد على عنوان URL محدّد. تثبيت Django إطار العمل Django هو إحدى الحزم الخاصة بلغة البرمجة بايثون، وتوفّر هذه اللغة مدير حزم خاصّ يدعى pip يتم من خلاله تثبيت وتحديث وإزالة الحزم بسهولة ويسر؛ لذا ستكون الخطوة الأولى في تثبيت Django هي التأكد من وجود مدير الحزم pip وتثبيته إن لم يكن متوفّرًا. تنصيب pip لتنصيب إطار العمل Django ستحتاج إلى مدير الحزم الخاصّ بـ Python وهو pip، ولحسن الحظّ فإن pip متوفّر في نسخة Python 2.7.9 وما بعدها، وفي نسخة Python 3.4 وما بعدها. في حال عدم توفّر pip في نسخة Python المنصّبة لديك يمكنك تنصيبه باتباع الخطوات التالية: حمّل الملفّ get-pip.py. توجه في سطر الأوامر إلى المكان الذي حملت فيه الملف السابق، ثم اكتب التعليمة التالية: python get-pip.py استخدام سطر الأوامر لنجرب الآن استخدام مدير الحزم في بايثون لتنصيب Django، توجّه الآن إلى سطر الأوامر ثم اكتب الأمر: pip install django==1.9 هل ظهرت لك رسالة خطأ؟ ما المشكلة، ألم نقم بتنصيب pip قبل قليل؟ هذا صحيح، ولكننا لم نخبر سطر الأوامر بأن يوجّه أي تعليمة تبدأ بكلمة pip إلى مدير حزم بايثون، وللقيام بذلك اتبع الخطوات التالية: في أوبنتو: يجب تنصيب حزمة python3-pip إن كنت تستخدم الإصدار الثالث من بايثون أو python-pip للإصدار الثاني من بايثون، لتتمكن من استخدام pip في سطر الأوامر في أبونتو، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install python3-pip أدخل كلمة المرور الخاصة بك، وستبدأ عملية التثبيت، وبعد الانتهاء يمكنك تنصيب أي حزمة خاصة بلغة بايثون عن طريق سطر الأوامر مباشرة. في نظام Windows: أما في نظام Windows فيجب إضافة السطر التالي: C:\Python34\scripts; إلى مسار النظام System path، وللقيام بذلك اتبع الخطوات التالية: انقر بزر الفأرة الأيمن على أيقونة Computer واختر Properties من القائمة المنسدلة: انقر على أيقونة Advance system settings، وفي مربع الحوار المنبثق اضغط على أيقونة Environment Variables. انقر نقراً مزدوجًا على متغير النظام Path في الجزء السفلي من مربع الحوار المنبثق. أضف السطر السابق إلى نهاية السلسلة النصّية، بعد الفاصلة المنقوطة (;) (إن لم تكن هناك فاصلة منقوطة في نهاية السطر فقم بإضافتها). اضغط Ok ثم أغلق بقية النوافذ بالضغط على Ok. يمكنك الآن استخدام pip من سطر الأوامر مباشرة. البيئة الافتراضية Virtual Environment قبل البدء بتنصيب Django سنعمل على تنصيب أداة مفيدة جدًّا من شأنها المساعدة على ترتيب البيئة البرمجية على حاسوبك. يمكن تجاوز هذه الخطوة، ولكن ينصح بها بشدّة. تعمل البيئة الافتراضية على عزل مشاريع Python أو Django الخاصّة بك عن بعضها البعض، وهذا يعني أن إجراء التعديلات على موقع إلكتروني معيّن لن تؤثّر على المشاريع الأخرى التي تعمل عليها. ستحتوي البيئة الافتراضية على الملفات التنفيذية الخاصة بـ Python بالإضافة إلى نسخة من مكتبة pip يمكنك استخدامها في تنصيب حزم Python المختلفة. سننشئ مجلدًا سيحتوي على البيئة الافتراضية التي سوف ننشئها بعد قليل. mkdir mysite cd mysite يتطلب إنشاء البيئة الافتراضية تنصيب حزمة virtualenv وسنستعين بـ pip للقيام بذلك: pip install virtualenv لاستخدام virtualenv من سطر الأوامر مباشرة في أوبنتو يجب تنصيب الحزمة virtualenv، وللقيام بذلك اكتب الأمر التالي في سطر الأوامر: sudo apt-get install virtualenv بعد اكتمال عملية التنصيب يمكنك إنشاء البيئة الافتراضية بالشكل التالي: virtualenv myvenv ستنشئ هذه الشيفرة بيئة افتراضية وهي عبارة عن مجموعة من المجلدات. لتفعيل البيئة الافتراضية الجديدة في نظام Windows استخدم الشيفرة التالية: myvenv\Scripts\activate أما في نظامي Linux و OS X فاستخدم: source myvenv/bin/activate ملاحظة: قد لا تحصل على النتيجة المرجوّة من الشيفرة السابقة، لذا يمكنك استخدام هذه الشيفرة: . myvenv/bin/activate سيتغيّر سطر الأوامر وذلك بإضافة كلمة (myvenv) إلى بداية السطر، وهذا يعني أن الأمور تسير على ما يرام. ولإغلاق البيئة الافتراضية يمكنك استخدام التعليمة التالية: deactivate تنصيب Django بعد اكتمال الخطوتين السابقتين يمكننا الآن تنصيب Django وذلك بتنفيذ الأمر التالي (انتبه إلى وجود علامتي مساواة لا علامة واحدة): pip install django==1.9 بعد اكتمال عملية التنصيب، وللتأكد من أن الأمور تجري على ما يرام، اكتب الأمر التالي في سطر الأوامر: python3 -c "import django; print(django.get_version())" إن حصلت على رقم النسخة (1.9 في حالتنا هذه) التي قمت بتنصيبها، فقد أصبحت جاهزًا لإنشاء مشروعك الأول على Django. إنشاء المشروع الأول مشروعنا الأول سيكون عبارة عن تطبيق استطلاع بسيط، يتألف من جزئين: موقع عام يتيح مشاهدة الاستطلاعات والتصويت عليها. لوحة تحكم تتيح لنا إضافة وحذف وتعديل الاستطلاعات. هذا المشروع سيكون مبنيًا على الإصدار 1.9 من Django والإصدار 3.4 من Python. في حال كنت تستخدم الإصدار 2.7 من Python فيتوجب عليك حينها إضافة بعض التعديلات على الشيفرة التي تكتبها، وسنشير إلى ذلك في محلّه. انتقل إلى سطر الأوامر وتوجه من خلاله إلى المجلد الذي ترغب استخدامه لإنشاء المشروع، وبإمكانك استخدام أي مجلد تحت أي تسمية وفي أي موقع في القرص الصلب، فلا مشكلة لدى Django في ذلك. لإنشاء المشروع نفّذ الأمر التّالي في سطر الأوامر (انتبه إلى النقطة في نهاية السطر): django-admin startproject mysite . سيعمل هذا الأمر على إنشاء مجلد باسم mysite داخل مجلد المشروع. انتبه كذلك إلى كتابة النقطة في نهاية السطر، فهي توجّه الشيفرة إلى تنصيب Django في المجلد الحالي. البنية الأولية للمشروع يحتوي مجلد mysite الذي أنشأته التعليمة السابقة، على مجموعة الملفات التالية: manage.py /mysite __init__.py settings.py urls.py wsgi.py manage.py، يُوصف هذا الملف بالسكين السويسري، وهو الأداة التي سنستعين بها للقيام بالكثير من الأشياء في إدارة الموقع، وفي تهجير قواعد البيانات وتشغيل الخادوم الخاص بـ Django، وغير ذلك الكثير. المجلد mysite هو حزمة بايثون الخاصة بمشروعنا، وسنستخدم هذا الاسم عندما نرغب في استيراد أي شيء داخله. (مثال mysite.urls). mysite/__init__.py ملف فارغ، ووجوده يعني أن هذا المجلّد هو حزمة من حزم بايثون. mysite/settings.py ملف الإعدادات الخاصة بمشروعنا. mysite/urls.py يحتوي على عناوين URL الخاصة بموقعنا، وهو أشبه ما يكون بجدول المحتويات الخاص بالموقع. mysite/wsgi.py نقطة الولوج إلى الخواديم المتوافقة مع WSGI. تشغيل الخادوم توجه في سطر الأوامر إلى المجلد الذي يحوي الملف manage.py ثم اكتب الأمر التالي: python manage.py runserver وستظهر العبارات التالية في سطر الأوامر: Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them. February 01, 2016 - 15:50:53 Django version 1.9, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ملاحظة: لا تستخدم هذا الخادوم في المشاريع الإنتاجية على الإطلاق، فالهدف من هذا الخادوم هو استخدامه لأغراض التطوير فقط. أدخل العنوان التالي في متصفح الإنترنت: http://127.0.0.1:8000 ستظهر الصفحة التالية لتشير إلى نجاحنا في إنشاء أول مشروع في Django.
- 3 تعليقات
-
- 4
-
- django 101
- بايثون
- (و 5 أكثر)
-
تحدّثنا في بداية هذه السلسلة عن أن مشاريع إطار العمل 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