جدول المحتويات

, , , , , ,

بدهيات إطار الويب جانغو Django

الحصول على جانغو

طرق الحصول على جانغو

يفضل أن تعود لمقالة بدهيات بايثون حيث هناك فصل للحصول على الحزم وحزمة جانغو ليست استثناء.

يمكن تثبيت جانغو من خلال مدير حزم بايثون pip والذي أصبح منذ 2.7.9 و 3.4.0 جزء من توزيعة بايثون القياسية (في لينكس عليك تثبيت الحزمة python-pip من مدير الحزم في توزيعتك). وينصح أن يتم ذلك من خلال مجلد البيئة الافتراضية من خلال أداة virtualenv وهي الأخرى يمكن الحصول عليها من مدير حزم بايثون pip.

هذه جلسة بصلاحيات المستخدم الجذر (وضعت فيها أشياء زائدة قصدا الشيء الوحيد الضروري من السطر الأول هو python-pip)

yum install python-pip python-pillow python-lxml python-psutil python-simplejson python-crypto  PyYAML MySQL-python python-psycopg2 libxslt-python python-greenlet python-gevent  
pip install virtualenv

إذا كنت تستخدم أوبنتو apt-get install python-pip عوضا عن السطر الأول.

الآن وبصلاحيات المستخدم العادي اعمل مجلد البيئة الافتراضية المعزولة

virtualenv --system-site-packages myenv
cd myenv
source bin/activate
pip install Django

وكلما أردت العمل على مشروعك تذهب إلى ذلك المجلد الذي سميناه myenv وهو الذي فيه bin ثم تكتب source bin/activate

ويندوز

نظام ويندوز لا يحتوي على لغة بايثون لذا عليك الحصول عليها بنفسك. موقع بايثون يوفر ملف تثبيت msi للغة يقوم بتثبيت بايثون. تأكد من أن مسارات بايثون و pip و virtualenv مثبتة في مسار النظام PATH

التأكد من سلامة تثبيته

افتح سطر الأوامر وشغل بايثون واكتب فيه import django إذا كان جانغو مثبت بشكل صحيح لن تحصل على ImportError بل ستكون الشاشة هكذا:

Python 2.7 (r27:82500, Sep 16 2010, 18:02:00) 
[GCC 4.5.1 20100907 (Red Hat 4.5.1-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> 

إنشاء تطبيق

قم بتنفيذ أداة إدارة جانغو django-admin أو django-admin.py مع تمرير كلمة startproject متبوعة باسم المشروع myproj على سبيل المثال

django-admin startproject myproj
cd myproj

وهناك أنشئ تطبيق الويب بالأداة manage.py الموجودة داخل المجلد الجديد وذلك بكتابة python متبوعة ب manage.py متبوعة ب startapp ثم اسم التطبيق

python ./manage.py startapp myapp

تحذير: لا تستخدم django-admin إلا لإنشاء المشروع أما بقية الأوامر فتكون من خلال manage.py الموجودة داخل المشروع.

وبهذا نكون عملنا هيكل الملفات لتطبيق الويب والذي يبدو كما في هذه الصورة

شجرة الملفات لمشروعنا على جانغو

هذا التطبيق الذي عملنا يعمل الآن. لتشغيله اكتب

python ./manage.py runserver

وستشاهد ما يشبه

إنه يعمل

تقول لك هذه الصورة أن عليك اختيار قاعدة البيانات

اختيار قاعدة البيانات

افتح ملف الإعدادات settings.py وابحث عن سطر في رأس الملف يحدد قاعدة البيانات ستجد جزء يشبه

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

يمكنك الآن اختيار أي قاعدة بيانات سواء PostgreSQL أو MySQL أو Oracle لكن لأغراض تجربة جانغو سنستخدم sqlite3 وهي قاعدة بيانات تكون عبارة عن ملف (لن نحتاج لخادم) ودعمها موجود ضمنا في بايثون أي:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': 'myproj.db',

ثم احفظ الملف.

واجهة الإدارة

تفعيل واجهة الإدارة

تحتوي جانغو على واجهة جميلة تستخدم لإدارة التطبيق بل وتعديل المدخلات. لتفعيلها افتح ملف الإعدادات settings.py وأزل علامة التعليق # عن أول سطري الإدارة ووثائق الإدارة لتصبح كما يلي

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    'django.contrib.admindocs',
)

ثم فعّل الروابط في ملف urls.py بطريقة مشابهة في رأس الملف

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

وفي ذيل نفس الملف

urlpatterns = patterns('',
    # Example:
    # (r'^myproj/', include('myproj.foo.urls')),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
)

احفظ الملفين ثم نفذ أداة الإدارة متبوعة ب syncdb هكذا

python manage.py syncdb
يجب تنفيذ syncdb بعد عمل أي تعديل على نموذج قاعدة البيانات

تفعيل واجهة الإدارة يعني ضمنا تفعيل نظام المواثقة بما فيه جداول المستخدمين لذا فإن الأمر السابق سيطلب عمل مستخدم خارق (المدير) وتحديد كلمته السرية

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use 'alsadi'): 
E-mail address: alsadi@somewhere.com
Password: 
Password (again): 
...
No fixtures found.

الآن أعد تشغيل الخادم بالأمر

python ./manage.py runserver

ثم ادخل عبر المتصفح للعنوان http://127.0.0.1:8000/admin

واجهة الإدارة

مزايا واجهة الإدارة

لغة المشروع

هناك سطر في ملف الإعدادات يحدد اللغة يمكنك أن تجعله يشير للغة العربية هكذا

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'ar'

شاشة الولوج بالعربية

عمل نموذج البيانات

تفعيل التطبيق

قبل عمل أي شيء يجب إضافة تطبيقنا إلى INSTALLED_APPS في ملف settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    'django.contrib.admindocs',
    'myapp',
)

تصميم نموذج البيانات

يجب أن نحدد نموذج البيانات الخاص بمشروعنا وذلك بالدخول في مجلد myapp ثم فتح الملف models.py مثلا

from django.db import models
from django.contrib.auth.models import User
 
# Create your models here.
class Tag(models.Model):
  name = models.CharField(max_length=200)
  def __unicode__(self):
    return self.name
 
class Article(models.Model):
  title = models.CharField(max_length=200)
  body = models.TextField()
  user = models.ForeignKey(User)
  tags = models.ManyToManyField(Tag)
  def __unicode__(self):
    return self.title

تسجيل النموذج في واجهة الإدارة

وفي نفس المجلد نعمل ملف admin.py يضيف نموذجنا إلى واجهة الإدارة

from django.contrib import admin
from myapp.models import *
 
admin.site.register(Tag)
admin.site.register(Article)

الآن اعمل syncdb ثم ادخل لواجهة الإدارة لتجد كل ما ترغب به

تخصيص طريقة العرض

دالة unicode في كل صنف تحدد طريقة عرض المدخلة الواحدة مثلا يمكننا أن نظهر اسم المستخدم إلى جانب عنوان المقالة هكذا

  def __unicode__(self):
    return self.user.username+u" : "+self.title

عرض اسم المستخدم إلى جانب عنوان المقالة

بل ويمكننا عرض التصنيفات

  def __unicode__(self):
    return self.user.username+u" : "+self.title+u" @ "+(", ".join(map(lambda i: i.name ,self.tags.all())))

بل وبطريقة تويترية

  def __unicode__(self):
    return u"@"+self.user.username+u" : "+self.title+u" #"+(" #".join(map(lambda i: i.name ,self.tags.all())))

العرض بطريقة تويترية

تعديل النموذج

في أي لحظة يمكنك تعديل النموذج وإضافة جداول جديدة لكن إضافة حقول في الجدول الواحد لا يمكن القيام به بسهولة. لهذا فلنقم بحذف ملف قاعدة البيانات ولنعدل ملف النموذج ونضيف حقل مفهرس يبين هل المقالة منشورة وحقل يحتوي تاريخ النشر وليكن مفهرسا ولنجعل العنوان فريدا

from datetime import datetime
 
class Article(models.Model):
  title = models.CharField(max_length=200, unique=True)
  body = models.TextField()
  published = models.BooleanField(verbose_name=u"Published?", default=True, help_text=u"If not enabled it won't appear for browsing")
  ctime = models.DateTimeField(verbose_name=u"Creation time", db_index=True, default=datetime.now)
  user = models.ForeignKey(User)
  tags = models.ManyToManyField(Tag)
  def __unicode__(self):
    return u"@"+self.user.username+u" : "+self.title+u" #"+(" #".join(map(lambda i: i.name ,self.tags.all())))

أهم أنواع البيانات هي

العلاقات

لاحظ طريقة عمل العلاقات

المعامل الأول لها هو النموذج الآخر الذي ترتبط معه أو اسمه (على شكل نص) إن لم يكن معرفا بعد.

يجوز أن تعمل العلاقة بين الجدول ونفسه مثلا المستخدم قد يكون له حقل أصدقاء والذين هم أيضا مستخدمون!

يفضل أن تحدد نوع العلاقة related_name عند وجود غموض مثلا لو كان للمقالة مستخدمان أحدهما صاحب المقالة والثاني صاحب آخر تعديل فإنها تكون هكذا

  author = models.ForeignKey(User, related_name="created_by")
  last_editor = models.ForeignKey(User, related_name="last_edit_by")

تخصيص طريقة الإدارة

يمكنك تخصيص صفحات الإدارة عبر عمل صنف مشتق من الصنف admin.ModelAdmin وتمريره كمعامل ثاني للدالة admin.site.register في ملف admin.py مثلا

from django.contrib import admin
from myapp.models import *
 
class ArticleAdmin(admin.ModelAdmin):
  list_display = ('title', 'user', 'ctime')
  list_filter = ['ctime', 'published', 'tags']
  date_hierarchy = 'ctime'
  search_fields = ['title']
  list_per_page = 10
  fieldsets = [
        (None, {'fields': ['title', 'body']}),
        (u'Extra Information', {'fields': ['user', 'tags']}),
        (u'Advanced', {'classes': ['collapse'], 'fields': ['published', 'ctime']}),
    ]
 
admin.site.register(Article, ArticleAdmin)

الآن جرب الدخول لصفحة الإدارة وسترى أن عرض قائمة المقالات أصبحت عبارة عن جدول بعدة أعمدة (يمكن النقر على رأس العمود للترتيب) هي العنوان والمستخدم والوقت وليس مجرد عرض للتمثيل النصي الذي تعيده الدالة unicode. كذلك أصبحت تحتوي على بحث (في حقل العنوان) وفلترة حسب التاريخ وحالة النشر والتصنيفات في صندوق جانبي وتحت صندوق البحث هناك صندوق للتصفح عبر التاريخ وهناك تقسيم للصفحات.

لا نستطيع إضافة عمود يبين ألتصنيفات tags لأنها حقل many to many أي هناك أكثر من تصنيف. لكن يمكن التحايل على ذلك بعمل حقل وهمي يولد تلقائيا (غير موجود في قاعدة البيانات) مثلا وليكن اسمه tags_as_text وذلك بإضافة الدالة التالية داخل الصنف Article في النموذج models.py

  tags = models.ManyToManyField(Tag)
  def tags_as_text(self):
    return u" #"+(" #".join(map(lambda i: i.name ,self.tags.all())))
  tags_as_text.short_description = u'Tags List'

ثم نعدل أعمدة اللائحة لتكون

  list_display = ('title', 'user', 'tags_as_text', 'ctime')

عرض أجمل في صفحة الإدارة

يمكننا جعل عرض لائحة التصنيفات تحتوي على عدد المقالات فيه. لنحرر نموذج التصنيفات في models.py ليكون

class Tag(models.Model):
  name = models.CharField(max_length=200)
  def articles_count(self):
    return self.article_set.count()
  articles_count.short_description = u'Number of Articles'
  def __unicode__(self):
    return self.name

وفي الإدارة admin.py

class TagAdmin(admin.ModelAdmin):
  list_display = ('name', 'articles_count')
 
admin.site.register(Tag, TagAdmin)

التصنيفات مع عددها

ليس هذا فحسب بل إن شاشة تحرير المقالة في الإدارة أصبحت الآن أجمل حيث أن عدد من الحقول أصبحت مجمعة مثلا المستخدم user و التصنيفات tags أصبحت داخل صندوق Extra Information والتاريخ وهل هي منشورة أصبحت في صندوق منكمش اسمه Advanced وبالنقر عليه يتوسع ويظهر كل هذا fieldsets.

الواجهة المعدلة لتحرير مقالة في الإدارة

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

  inlines = [ChoiceInline]

حيث ChoiceInline معرفة في admin.py هكذا

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3

الصلاحيات

يمكنك عمل مستخدمين جدد وتحدد أنهم جزء من الطاقم stuff أي يمكنهم الدخول إلى صفحة الإدارة. لست مضطرا لإعطائهم كل الصلاحيات مثلا يمكنك السماح لهم فقط بإضافة مقالات وتعديل المقالات.

  readonly_fields=['ctime', 'published']

اختيار المستخدم تلقائيا

المفروض أن يتم اختيار المستخدم أضاف المقالة بل يتم ذلك تلقائيا لعمل ذلك نحذف 'user' من قائمة fieldsets ثم نضيف الدالة save_model داخل الصنف ArticleAdmin في ملف admin.py

  def save_model(self, request, obj, form, change):
    obj.user = request.user
    obj.save()

شرح هيكلية المشروع

مفهوم MVC في جانغو

مفهوم MVC والذي عني تقسم المشروع إلى نموذج بيانات Model و طريقة عرض View وحاكم Controller مثلا لا يجوز أن يحتوي الحاكم على كود html أو أي عناصر تصميم بل على الكود الذي يحضر العناصر من النموذج ويمررها إلى نظام العرض كذلك لا يجوز أن يحتوي العرض على كود بل على تصميم فقط.

اختلاف المصطلحات

في جانغو الأمر نفسه لكن اختلفت الأسماء فهم يسمون الحاكم باسم العرض View ويسمون العرض باسم القالب Template

هيكيلية الملفات

تعريف القوالب

اعمل مجلد باسم templates في مجلد المشروع (وليس التطبيق) أي إلى جوار ملف settings.py ثم حرر هذا الأخير وحرره كي تحدد مسار القوالب فيه

import os.path
# ...
TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), 'templates'),
)

ونحن بهذا نخبر جانغو أن مسار القوالب هي في templates الموجودة في مجلد الذي يحتوي الملف الحالي أي settings.py

عمل صفحة رئيسية

افتح ملف views.py في مجلد myapp وضع فيه

from django.shortcuts import render_to_response
from models import *
def homepage(request):
  return render_to_response('homepage.html', {'articles_list':Article.objects.all()} )

افتح ملف urls.py وحرر المسارات فيه كي تبدو هكذا

from myapp.views import *
urlpatterns = patterns('',
    (r'^$', homepage),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
)

حيث ربطنا العنوان الخالي مع دالة homepage التي تجلب كل المقالات ثم تركبها على قالب homepage.html وضع في ذلك القالب ما يشبه

<html>
<head>
<title>MyApp using Django</title>
</head>
<body>
<h1>MyApp using Django</h1>
<ul>
{% for a in articles_list %}
<li>{{ a.title }}</li>
{% endfor %}
</ul>
</body>
</html>

الآن زر الصفحة الرئيسية وسترى ما يشبه

الصفحة الرئيسية

العروض العامة Generic Views

حتى لا تضيع وقتك في عمل الصفحات القياسية التي تعرض قائمة بالكائنات التي عرفتها في النموذج أو لتحريرها أو إضافتها توفر جانغو عددا من العروض العامة من أهمها

عرض object_list

مثلا نستعمل object_list هكذا

from myapp.views import *
urlpatterns = patterns('',
    (r'^$', homepage),
    (r'^articles/$', 'django.views.generic.list_detail.object_list', {
      'queryset': Article.objects.all(),
      'paginate_by': 10,
      'template_name': 'articles.html',
      'template_object_name':'articles',
    }),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),
)

لاحظ أننا مررنا عدد من المعاملات لدالة العرض العامة django.views.generic.list_detail.object_list وهي

يمكنك نسخ القالب السابق homepage.html باسم جديد هو articles.html وانظر النتيجة لاحظ أنه عرض أول 10 عناصر فقط وعند زيارة الصفحة

الصفحة الثانية

تم عرض بقية العناصر. لكن كيف للمستخدم أن يعرف أن هناك صفحة ثانية؟ نحتاج لإضافة ما يلي إلى نهاية القالب قبل انتهاء وسم إغلاق body هكذا

<hr/>
        <span class="current">
            Page {{ page_obj.number }} of {{ paginator.num_pages }}.
        </span>
<hr/>
<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}
 
{% for i in page_range %}
        {% if page_obj.number == i %}
            <span>{{ i }}</span>
        {% else %}
            <a href="?page={{ i }}">{{ i }}</a>
        {% endif %}
{% endfor %}
 
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">next</a>
        {% endif %}
    </span>
</div>

الآن أصبحت لدينا صفحة المقالات هكذا

أزرار التصفح

عرض create_object

يقوم هذا العرض يتوليد استمارة form والسماح لك بتعبئتها ثم حفظ الناتج ثم إعادة التوجيه لصفحة ما (مثلا عرض الكائن الذي تم حفظه)

يمكنك تمرير المعاملات التالية

تعمل هذه على تمرير form للقالب يمكن إضهاره هكذا

<form action="" method="post">
<table>
{{ form }}
</table>
</form>

طبعا يمكنك توليد الاستمارة دون الحاجة للعروض العامة من النموذج فهي تستخدم ModelForm الذي يبنى تلقائيا من النموذج هكذا

from django.forms import ModelForm
from myapp.models import *
 
class ArticleForm(ModelForm):
  class Meta:
    model = Article

يمكنك تجربة ذلك من خلال

python manage.py shell

ثم نفذ الكود السابق أو استورده ثم اكتب

form=ArticleForm()
print form.as_table()

لكن الجميل في العروض العامة أنها تلقائيا تنفذ عملية ال validate وتعمل redirect …إلخ

القوالب