أعجوبة

البرمجيات الحُرة والمفتوحة المصدر

أدوات المستخدم

أدوات الموقع


okasha:sample1

مثال أولي بسيط

إن غالبية دوال وصنوف عكاشة موثّقة جيّداً لذا يمكنك استعمال pydoc للوصول لها.

كذلك يمكنك استعمال المثال test.py الموجود في كود عكاشة فهو يوضّح أغلب استخدامات عكاشة.

بعكس ذاك المثال المسهب فإن هذه الوثيقة ستعلّمك كيف تعمل مشروع بدهي مثل “مرحبا، يا عالم!”

وقبل أن تبدأ تخلّص من الخوف فأغلب الكود هو تعليقات (مجرد شرح).

كيف نبدأ ؟

أنشء مجلّد للمشروع. وإن لم تكن الاعتماديات1) مثبّتة في النظام أو كنت تريد أن يكون التطبيق الخاص بك قابل للنقل portable إلى أجهزة لا تضمن أن يكون عكاشة وبقية الاعتماديات مثبّتا فيها كل ما عليك هو وضع نسخة من تلك الحزم داخل مجلد المشروع الحالي.

بعكس أطر الويب الأخرى تطبيق الويب هو مجرّد ملف واحد به صنف واحد لذا اعمل ملف سمّه مثلا myapp.py ولتكن محتوياته كما يلي:

#! /usr/bin/python
# -*- coding: UTF-8 -*-
"""
this is my first okasha web app
"""
from okasha.baseWebApp import *
 
class MyApp(baseWebApp):
  def __init__(self, *args, **kw):
    baseWebApp.__init__(self,*args, **kw)

وبهذا نكون قد أنهينا أول تطبيق لنا

كيف نشغّل هذا التطبيق ؟

هناك عدّة طرق لإطلاق تطبيقات عكاشة. أسهلها وأفضلها خلال فترة التطوير هو استعمال حزمة python-paste

يمكنك عمل ملف منفصل اسمه serve.py مثلا يقوم على تشغيل التطبيق الخاص بك وذلك كما يلي

#! /usr/bin/python
# -*- coding: UTF-8 -*-
import sys, os, os.path
# this requires python-paste package
from paste import httpserver
from myapp import MyApp
 
d=os.path.dirname(sys.argv[0])
application=MyApp(
      os.path.join(d,'templates'),
      staticBaseDir={'/media/':os.path.join(d,'media')}
);
httpserver.serve(application, host='127.0.0.1', port='8080')

فعند تنفيذ برنامج serve.py أعلاه سيعمل خادم paste الضمني المنضدد على المنفذ 8080 (يمكنك تحديد أي رقم) وسيقبل أي اتصالات من العنوان المحلي 127.0.0.1 . إن كنت تريده أن يستقبل من كل العناوين اجعله 0.0.0.0 للمزيد من الخيارات انظر وثائق paste

بل ويمكن وضع هذا الكود داخل الوحدة التي تحتوي تطبيق الويب نفسه يعني في مثالنا يمكن الاستغناء عن serve.py وذلك بأن نجعل ملف myapp.py كما يلي:

#! /usr/bin/python
# -*- coding: UTF-8 -*-
"""
this is my first okasha web app
"""
from okasha.baseWebApp import *
 
class MyApp(baseWebApp):
    def __init__(self, *args, **kw):
      baseWebApp.__init__(self,*args, **kw)
 
if __name__ == '__main__':
    # this requires python-paste package
    from paste import httpserver
    import sys, os, os.path
 
    d=os.path.dirname(sys.argv[0])
    application=MyApp(
      os.path.join(d,'templates'),
      staticBaseDir={'/media/':os.path.join(d,'media')}
    );
    httpserver.serve(application, host='127.0.0.1', port='8080')

وفي هذه الحالة لا نحتاج ملف serve.py حيث يمكننا إطلاق تطبيق الويب عبر تنفيذ myapp.py حيث أن الجزء في آخر الملف لن ينفّذ في حالة استخدام الملف كوحدة بايثونية (مكتبة) بل عند تنفيذه كبرنامج وليس مكتبة.

ما معنى الكود ؟

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

from okasha.baseWebApp import *

ثم قمنا بتعريف كائن مشتق من تطبيق الويب الأساسي في عكاشة baseWebApp

class MyApp(baseWebApp):

وفيه عرّفنا دالة الاستهلال التي كل مهمّتها هي استدعاء الدالة في الصنف الأساس وتمرير المعاملات له بشكل أعمى (سنشرح هذه المعاملات لاحقا)

  def __init__(self, *args, **kw):
    baseWebApp.__init__(self,*args, **kw)

يمكنك استقبال معاملات خاصة بك هكذا للاحتفاظ بها لاستخدامها لاحقا هكذا

  def __init__(self, name, *args, **kw):
    self.name=name
    baseWebApp.__init__(self,*args, **kw)

أما كود التشغيل فهو كما يلي:

from paste import httpserver

نستورد خادم http من داخل حزمة paste. يستقبل خادم paste تطبيق الويب المتوافق مع WSGI كمعامل أول هكذا

httpserver.serve(application, host='127.0.0.1', port='8080')

حيث application هو تطبيق الويب وهو في حالتنا كائن فرد من الصنف MyApp الذي اشتققناه من تطبيق الويب الأساسي في عكاشة baseWebApp

نقوم بعمل هذا الكائن كما نعمل أي متغير أو كائن في بايثون

    d=os.path.dirname(sys.argv[0])
    application=MyApp(
      os.path.join(d,'templates'),
      staticBaseDir={'/media/':os.path.join(d,'media')}
    );

المتغير d يمثّل المجلّد الذي يحتوي تطبيق الويب وقد قمنا بتحديد مجلد فرعي عنه اسمه templates كي يحتوي القوالب كذلك طلبنا أن تحال كل العناوين التي تبدأ ب /media/ إلى المجلد الفرعي media داخل مجلد التطبيق حيث يمكننا استخدامه لوضع ملفات الصور وملفات css وغيرها من الملفات الساكنة static files.

يوفّر عكاشة أكثر من طريقة لتخديم الملفات الساكنة منها أن تمرّر له قاموس staticBaseDir مفاتيحه هي الجزء في بداية العنوان ثم المجلد الذي سيتم البحث عن الملفات فيه (يمكن استخدام أكثر من مجلد)

كذلك هناك خاصية أخرى وهي عمل إعادة توجيه redirect لطلبات معيّنة إلى عنوان آخر أو خادم آخر يحتوي تلك الملفات الساكنة.

للمزيد انظر وثائق دالة الاستهلال لصنف baseWebApp في كود عكاشة.

ماذا يفعل هذا التطبيق الخالي ؟

سيبحث عكاشة عن الطريقة/الدالة في كائن التطبيق فإن لم يجد واحدة مناسبة فإنه يستدعي الدالة _root ويمرر لها كائن من الصنف Request يحتوي تفاصيل الطلب ويمرّر له بقية عناصر العنوان. وحيث أنّنا لم نعرّف تلك الدالة فإن دالة _root التلقائية الموجودة في عكاشة تعمل وتظهر لنا في شاشة المتصفح عند زيارة الموقع صفحة html تحتوي

You requested [/]

فإن زرنا العنوان http://localhost:8080/hello/omar سيظهر في المتصفح

You requested [/hello/omar]

كتابة دالة خاصة بنا

جرّب إضافة الكود التالي بعد دالة الاستهلال init في صنف MyApp

  @expose()
  def _root(self, rq, *args):
    return """<html><body>
<img src="/media/logo.gif"/>
<h1>welcome to my first okasha application</h1>
</body></html>"""

الكثير من النّاس لا يألَفون استخدام @ أو ما يُسمى decorator وشرحها في هذه المرحلة غير مناسب لكن اعلم أنها تستدعي دالة خاصة وهي expose موجودة داخل عكاشة تقوم هذه الدالة بتغيير الدالة التي بعدها وهي في مثالنا _root

يمكنك أن ترى وثائق دالة expose في كود عكاشة حتى تعرف ما هي المعاملات التي تستقبلها لكن إن استعملتها دون أي معاملات كما فعلنا فهي تعني أننا لن نستعمل أي قوالب بل سنعيد كود html

لاحظ أننا استعملنا ملف logo.gif الموجود في media لكن الرابط الذي استخدمناه قد لا يكون صحيحا دائما لأنه إن كان التطبيق يعمل من داخل سابقة ما حيث لا يكون التطبيق مربوط على جذر الخادم بل داخل سابقة هكذا http://myhost/myapp ويكون ذلك مفيدا عندما يكون هناك أكثر من تطبيق على نفس النطاق domain

وحتى لا تعيد كتابة الروابط يمكنك استخدام rq.script التي تعيد سابقة التطبيق الخاص بنا (طبعا ستكون نص خالي إن لم يكن هناك سابقة)

  @expose()
  def _root(self, rq, *args):
    return """<html><body>
<img src="%s/media/logo.gif"/>
<h1>welcome to my first okasha application</h1>
</body></html>""" % rq.script

التفاعل مع عناوين URL

  @expose()
  def hello(self, rq, *args):
    if not args: s="world"
    else: s=args[0]
    return """<html><body>
<h1>Hello, %s!</h1>
</body></html>""" % s
 
  @expose()
  def _root(self, rq, *args):
    if not args: raise redirectException(rq.script+'/hello/')
    elif args[0]=='favicon.ico': redirectException(rq.script+'/media/favicon.ico')
    else: raise forbiddenException()

في هذا المثال عملنا دالة اسمها hello سيتم تنفيذ هذه الدالة عند زيارة /hello/ أو /hello/Name/ أو ما شابه. هذه الدالة تستلم بقية العنوان على شكل معاملات حيث ستكون قيمة args منظومة خالية [] أو ['Name'] على الترتيب في المثالين.

كذلك جعلنا الوصول لجذر التطبيق يحيل إلى العنوان /hello/ الذي بدوره يطبع Hello, world! لأنه لا يوجد تتمة للعنوان (المنظومة خالية)

كذلك عملنا تحويلة أخرى داخل _root تحيل من favicon.ico إلى /media/favicon.ico

أمّا إن لم يجد دالة مناسبة ولم يحصل أي من الحالتين السابقتين (أي لم نطلب جذر التطبيق ولا favicon) عندها سينفذ ما بعد else وهو في حالتنا رفع الخطأ رقم 403 ممنوع الوصول لتلك الصفحة.

يمكنك مكان السطر الأخير كتابة ما يلي

  else: raise fileNotFoundException()

حتى تحصل على الخطأ 404 (صفحة غير موجودة)

كذلك يمكنك تخصيص الصفحة التي تظهر عند حدوث هذين الخطأين عبر تخصيص الدالة _403 و _404

التفاعل مع النماذج forms

غيّر الدالة hello لتصبح كما يلي :

  @expose()
  def hello(self, rq, *args):
    n=rq.q.getfirst('n','world').decode('utf-8')
    return """<html><body>
<h1>Hello, {0}!</h1>
<form name="MyForm">
Please enter name:
<input name="n" type="text" value="{0}"></input>
</form>
</body></html>""".format(n)

لاحظ استخدامنا ل rq.q.getfirst للحصول على قيمة عنصر من النموذج وهو في حالتنا n وهي ذاتها التي تأتي من مربع النص الذي اسمه n في كود html. إن لم تكن تلك القيمة التلقائية world مكانها

1)
الاعتماديات التي نحتاجها في هذا المثال هي عكاشة و python-paste فقط
okasha/sample1.txt · آخر تعديل: 2015/04/23 03:21 بواسطة 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki