بناء تطبيق لاختصار الرّوابط باستعمال لغة بايثون وإطار العمل Flask الجزء الثّاني


عبدالهادي الديوري

مُقدّمة:

بعد أن أعددنا السّند الخلفي لتطبيقنا، حان الوقت لإعداد النّظام الأمامي لتحسين تجربة الاستخدام، سنقوم في هذا الدّرس بإنشاء ملفّ HTML ليحتوي على حقل يُمكن المُستخدم من لصق الرّابط إليه، وسنستخدم لغة جافاسكربت لإرسال الرّابط إلى تطبيق Flask واستقبال الرّابط المُختصر، بعدها سنقوم بطرح الرّابط المُختصر مع إمكانيّة نسخه عن طريق الضّغط على زر واحد.

 

مُتطلّبات هذا الجزء

لتتمكّن من فهم هذا الدّرس بشكل كامل، ستحتاج إلى معرفة جيدة بلغة جافاسكربت وخاصّة تقنيّة Ajax وكيفيّة إرسال واستقبال طلبات HTTP باستعمال خاصيّة XMLHttpRequest، ومن المُفضّل إلقاء نظرة على الموضوع قبل إكمال قراءة هذا الدّرس، ويُمكنك أن تتعلّم اللغة هنا على موقع الأكاديميّة.

وتجدر الإشارة إلى أنّك ستحتاج إلى معرفة بسيطة بأداة git لتتمكّن من التّعامل مع منصّة Heroku لخدمات الاستضافة السّحابيّة.

دروس جافاسكريبت
دروس git

الهدف من هذا الجزء

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

إعداد ملفّ HTML

سنقوم باستخدام ملف HTML واحد باسم index.html بداخل مُجلّد templates وسنربطه بملفّ جافاسكريبت باسم index.js وملفّ css باسم style.css اللذان سيكونان بداخل مجلّد static.
ما يعني بأنّ الملفّات والمجلّدات ستكون كالتالي:

├── app.db
├── app.py
├── create_db.py
├── static
│   ├── css
│   │   └── style.css
│   └── js
│       └── index.js
└── templates
    └── index.html

لتقديم ملفّ HTML سنقوم بتعديل الموجّه الرّئيسيّ ليُصبح كالآتي:

@app.route('/')
def index():
    return render_template("index.html")

بعدها سنُضيف الشيفرة التّالية إلى ملفّ index.html:

<!DOCTYPE html>
<html >
  <head>
    <meta charset="UTF-8">
    <title>قصّرتك</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
  </head>
  <body>
    <header>
        <h1>قصّرتُك</h1>
        <h3> خدمة تقصير الروابط الأكثر بساطة </h3>
    </header>
    <div id='bg-box'>
        <input name="link" type='text' id='input' placeholder='ضع رابطك هنا لتقصيره' onchange='change()'>
        <input type='text' id='result' value='الرّابط المُختصر هنا'>
        <a id='cp' href='#' onclick='copy()'>انسخ</a>
        <span id='msg' href='#'></span>
    </div>

<script src="{{ url_for("static", filename="js/index.js") }}" >
</script>
  </body>
</html>

لاحظ بأنّنا جلبنا ملف style.css في أعلى الملف وindex.js في أسفله.
ستحتوي الصّفحة على حقل ليضع فيه المُستخدم رابطه (سمّيناه link)، وحقل لعرض النّتيجة (أي الرّابط المُختصر)، ثم أضفنا رابطا ليعمل كزر لنسخ الرّابط المُختصر وكذلك وضعنا وسم span لنعرض عليه رسالة النّجاح (أو الإخفاق) في نسخ الرّابط.

لاحظ كذلك بأنّنا نستدعي دالتين من ملفّ جافاسكربت هما change() و copy() مُباشرة بعد حدثي onchange و onclick على التّوالي. الأولى مسؤولة عن إرسال طلب لاختصار الرّابِط والأخرى لتمكين المُستخدم من نسخ الرّابط المُختصر.

إرسال واستقبال الطّلبات من وإلى تطبيق Flask بالاستعانة بلغة جافاسكريبت

سنستعمل تقنيّة AJAX لإرسال طلب اختصار الرّابط إلى تطبيق Flask فور استقباله من المُستخدم عبر حقل input الأول المتواجد في الصّفحة الرّئيسيّة وعند استقبال الإجابة (والتي ستكون عبارة عن مُعرّف الرّابط في قاعدة البيانات مُشفّرا)، سنتعمد على تقنيّة DOM لتعديل مُحتويات الصّفحة وعرض النّتيجة إلى المُستخدم.

مُحتوى ملفّ جافاسكربت سيكون كالآتي:

function request(url,b,method,data,c){ 
 request = new XMLHttpRequest;
 request.open(method||'get',url);
 request.onload=b;
 request.send(data||null)

 result = document.getElementById("result");
 result.value = 'انتظر رجاء...'
 }

function callback(e){
      short_link = document.getElementById("result");
      short_link.value = window.location.host + this.response 
}

function change() {
url = document.getElementById("input").value;
request('shorten?link=' + url, callback, 'get')
}

// الدّالة المسؤولة عن نسخ الرّابِط المُختصر إلى لوحة مفاتيح المُستخدم
function copy() {
    result = document.getElementById("result");
    msg = document.getElementById("msg");
    result.select();
    try {
        var copy = document.execCommand('copy');
        if(copy) msg.innerHTML = 'نُسخَ الرّابِط بنجاح!';
        else msg.innerHTML = 'هناك خطأ ما! أعد المُحاولة رجاء';
    }
    catch(err) {
        msg.innerHTML = 'المُتصفّح لا يدعم هذه العمليّة';
    }
}

الدّالة request مسؤولة عن تنفيذ طلب XMLHttpRequest، حيث تستقبل الرّابِط الأصلي ثمّ تقوم الدّالة callback باستقبال الجواب (أي المُعرّف الخاصّ بالرّابط)، ثمّ تقوم بإسناده إلى العنصر الذي يحمل المُعرّف result في صفحة HTML (أي حقل النّتيجة).
لاحظ بأنّنا استخدمنا الخاصيّة window.location.host للحصول على اسم النّطاق، وذلك لمرونة أكثر بحيث لا نضطر إلى تغييره يدويا كلّما غيّرنا نطاق التّطبيق أو المُستضيف، والأمر مُفيد كذلك إذا أردت استخدام أكثر من اسم نطاق واحد.

الدّالة copy تقوم بالحصول على قيمة النّتيجة (أي الرّابط المُختصر) ثمّ تعتمد على التّابع select لتضليل النّتيجة، وبعدها نقوم بمُحاولة تنفيذ الأمر copy بالسّطر:

var copy = document.execCommand('copy');

فإن لم يكن المُتصفّح يدعم هذه العمليّة (إمّا لقِدَمِ إصداره أو لسبب آخر) فستُعرَض للمُستخدم رسالة تُفيد بأنّ هذه العمليّة غير ممكنة لكي ينتبه وينسخه يدويّا.

نشر التّطبيق على منصّة Heroku.

الآن وقد أصبح تطبيقنا كاملا ويعمل بشكل جيّد في بيئة التّطوير (المضيف المحلي) حان الوقت لرفعه إلى منصّة Heroku ونشره للعالم ليتمكّن الجميع من استخدامه. لكن قبل ذلك يجب أن نقوم ببعض التّعديلات.
أولا غيّر خيار تصحيح الأخطاء، بتعديل السّطر التّالي:

app.run(debug=True, host='0.0.0.0')

إلى ما يلي:

app.run(host='0.0.0.0')

وبما أنّ Heroku يعتمد على نظام Postgresql لإدارة قاعدة البيانات فيجب علينا تغيير رابط قاعدة البيانات.
الجميل في منصّة Heroku هي إمكانيّة الوصول إلى رابط قاعدة البيانات عن طريق مُتغيّر بيئة، وهذا المُتغيّر يُسمى DATABASE_URL وللوصول إى قيمته يكفي الاعتماد على الوحدة os مع الكائن environ وطريقة الوصول إلى قيمة هذا المُتغيّر هي كالآتي:

os.environ['DATABASE_URL']

لكن لا تنس أن تسترد الوحدة os في أعلى الملف:

import os

وبالتّالي فالتّغيير الذي يجب علينا القيام به هو تعويض السّطر الأول بالسّطر الثّاني في الشّيفرة التّاليّة:

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'

app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL']

سنقوم بتنصيب حزمة psycopg2 ليتمكّن SQLAlchemy من التّعامل مع قواعد بيانات Postgresql وسنستخدم خادوم gunicorn لنشر التّطبيق، لذلك عليك تنصيبه كذلك (تأكّد من أن البيئة الوهميّة لا تزال مُفعّلة):

pip install psycopg2 gunicorn

سيتوجّب علينا كذلك إنشاء ملفّ باسم requirements.txt لتعريف Heroku بمُتطلّبات التّطبيق من حزم ووحدات، وذلك ليقوم بتنصيبها عند النّشر.
لن نقوم بإنشاء هذا الملفّ يدويا، وسنستعمل أداة pip لإنشاء الملفّ، تأكّد فقط بأنّك لا تزال تعمل تحت البيئة الوهميّة ثمّ نفّذ الأمر التّالي لإنشاء الملفّ:

pip freeze > requirements.txt

بعد انتهاء التّنفيذ سيظهر ملفّ جديد باسم requirements.txt وستكون مُحتوياته شيئا مُشابها لما يلي (ربّما تتغيّر أرقام الإصدارات أو قد تظهر حزم جديدة حسب تاريخ تطبيقك لهذا المشروع):

click==6.6
Flask==0.11.1
Flask-SQLAlchemy==2.1
gunicorn==19.6.0
hashids==1.1.0
itsdangerous==0.24
Jinja2==2.8
MarkupSafe==0.23
psycopg2==2.6.2
SQLAlchemy==1.0.14
Werkzeug==0.11.10

هذه هي الاعتماديات (أو الحزم التي يعتمد عليها التّطبيق) التي يعتمد عليها تطبيقنا، ولو استخدمت إضافة من إضافات Flask (Flask-login على سبيل المثال) لَظهَرتْ في هذا الملف.

يجب كذلك إنشاء ملفّ باسمProcfile لتعريف منصّة Heroku بملفّ التّطبيق الرّئيسيّ، وسيحتوي هذا الملفّ ما يلي:

web: gunicorn app:app

لاحظ بأنّ الاسم app الأول هو المهم، وهو اسم ملفّ التّطبيق (أي app.py) ولو كان اسم الملف الرّئيسي مثلا run.py لكان مُحتوى ملفّ Procfile كالآتي:

web: gunicorn run:app

عليك كذلك تنصيب أداة git لتتمكّن من نشر التّطبيق ورفعه إلى المنصّة.

التّسجيل في منصّة Heroku

لتسجيل حساب جديد في منصّة Heroku ادخل إلى هذا الرّابط ، ثمّ املأ الحقول بما يُناسب، ويُمكنك ترك خانة Company name فارغة إن أردت.
عند ملء النّموذج سيكون كالتّالي:

001.png

اضغط على Create Free Account ثمّ فعّل بريدك الإلكتروني، بعد النّقر على رابط تفعيل البريد الإلكتروني ستنتقل إلى صفحة يُطلب منك فيها تعيين كلمة مرور وإعادة كتابتها كإجراء احتياطي. بعدها اضغط على Set password and log in (الخانة التي تسألك عمّا إذا كنت تريد الحصول على مُحتوى تقني عبر بريدك بشكل دوري ليست مُهمّة ولك كامل الحريّة في الاختيار بين القبول أو ضدّه).

بعد تعيين كلمة المرور ستنتقل إلى صفحة ترحيب مع رابط للمُتابعة إلى لوحة التحكم لتستطيع إنشاء التّطبيقات.

إنشاء التطبيق

بعد أن وصلت إلى لوحة التّحكم، يُمكنك الآن إنشاء تطبيق عبر الضّغط على زر “Create New App”، يُمكنك تعيين اسم للتّطبيق في خانة “App Name” سيكون هذا الاسم الذي ستختاره مُتواجدا في عنوان URL التّطبيق، ويُمكنك تركه فارغا وسيختار Heroku اسما عشوائيّا مُتاحا. ويُمكنك كذلك تعديل المنطقة الجغرافيّة للخادوم إن أردت.
بعد الانتهاء، اضغط على “Create App” لتُنشئ التّطبيق، تبقى لنا خطوة أخرى وهي تنصيب أداة Heroku Toolbelt التّي تُمكّننا من إدارة التّطبيقات عن طريق سطر الأوامر.

لتنصيب Heroku Toolbelt انتقل إلى هذا الرّابط واختر نظام التّشغيل الخاص بك وقم بالتّنصيب بالطّريقة الاعتياديّة. بالنّسبة لمُستخدمي توزيعة Debian أو ما بُنيَ عليه من توزيعات يُمكنك تنفيذ الأمر التّالي على الطّرفيّة:

$ wget -O- https://toolbelt.heroku.com/install-ubuntu.sh | sh

الآن بعد تنصيب الأداة، يُمكنك تسجيل دخولك إلى منصّة Heroku عبر سطر الأوامر، وذلك بتنفيذ الأمر:

$ heroku login

بعد إدخال بريدك الإلكتروني وكلمة المرور ستُلاحظ رسالة كالآتي:

Logged in as email@example.com

بعدها أنشئ مُستودع git في مُجلّد التّطبيق واربطه مع المستودع الخاص بالمنصة عن طريق تنفيذ الأوامر التّاليّة:

$ git init

$ heroku git:remote -a app-name

مع استبدال app-name باسم التّطبيق الذي اخترته (إن لم تختره فستجده في هذه الصّفحة )

يُفضّل إضافة مجلّد venv الخاصّ بالبيئة الوهميّة إلى ملفّ .gitignore لتجاهله.

بعدها يُمكنك نشر التّطبيق عن طريق الأوامر التّالية:

$ git add .
$ git commit -am "initial commit"
$ git push heroku master

بعد أن تُرفَع الملفّات بنجاح، ستهتم منصّة Heroku بتنصيب الحزم اللازمة عن طريق ملف requirements.txt الذي أعددناه سابقا.

بعد انتهاء الأمر، بقيت خطوة أخيرة، وهي خطوة إنشاء جدول قاعدة البيانات، وللقيام بذلك اذهب إلى هذا الرّابط:

https://dashboard.heroku.com/apps/app-name/resources

مع تغيير app-name إلى اسم تطبيقك.
وابحث في خانة “Quickly add add-ons from Elements” عن إضافة Heroku Postgres ثمّ اضغط على زر Provision، وبعدها يكفي تنفيذ الأمر التّالي على سطر الأوامر لإنشاء قاعدة البيانات والجدول الخاص بالرّوابط:

heroku run python create_db.py

إذا لاحظت رسالة مُشابهة لما يلي فلا تقلق فهي مُجرّد تنبيه ولا تُشكل أيّة مُشكلة:

warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')

بعد الانتهاء من الخطوة السّابقة سيتكون قد أكملت جميع الخطوات اللازمة لتطوير تطبيق ونشره للعالم ويُمكنك زيارة تطبيقك عبر عنوان URL الخاص به أو تنفيذ الأمر التّالي من سطر الأوامر:

heroku open

ختاما

بعد أن أنهينا التّطبيق يجب أن تكون قادرا على فهم كيفيّة عمل تطبيقات اختصار الرّوابط، ويجب عليك أن تكون قادرا على نشر تطبيقاتك على منصّة Heroku دون مشاكل، وإن واجهت أية مُشكلة أو أردت الاستفسار عن هذا التّطبيق، يُمكنك طرح سؤالك في قسم الأسئلة والأجوبة.

وأنبّه إلى أنّ هذا المشروع لم يكن للقارئ المبتدئ وإذا واجهت مشاكل مع هذا المشروع أو وجدته مُعقّدا بعض الشيء، فلا تقلق وتابع جديد الأكاديميّة لأنّنا سننشر سلسلة أخرى أكثر تفصيلا عن إطار العمل Flask فكن في الموعد.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن