ترجمة آلية تحت المراجعة
الأسبوع 9: Flask
المصدر الأصلي على CS50المحاضرة التاسعة (Lecture 9)
- مرحبًا!
- خادم http
- قارورة
- النماذج
- القوالب
- طرق الطلب
- رسائل فورية فورية
- القارورة وSQL
- ملفات تعريف الارتباط والجلسة
- سلة التسوق
- عروض
- واجهات برمجة التطبيقات
- JSON
- التلخيص
مرحبًا! (Welcome!)
- في الأسابيع الماضية، تعلمت العديد من لغات البرمجة والتقنيات والاستراتيجيات.
- في الواقع، كان هذا الفصل أقل بكثير من المستوى فئة C أو فئة بايثون وأكثر من ذلك بكثير فئة البرمجة، بحيث يمكنك الاستمرار في متابعة الاتجاهات المستقبلية.
- في الأسابيع القليلة الماضية، تعلمت كيف أتعلم عن البرمجة.
- اليوم، سوف ننتقل من HTML وCSS إلى الجمع بين HTML وCSS وSQL وPython وJavaScript حتى تتمكن من إنشاء تطبيقات الويب الخاصة بك.
- قد تفكر في استخدام المهارات التي تعلمتها هذا الأسبوع لإنشاء مشروعك النهائي.
خادم http (http-server)
- حتى هذه اللحظة، كل HTML الذي شاهدته كان مكتوبًا مسبقًا وثابتًا.
- في الماضي، عندما تزور إحدى الصفحات، يقوم المتصفح بتنزيل صفحة HTML، ويمكنك مشاهدتها. تعتبر هذه ثابت صفحات ، حيث أن ما تمت برمجته بتنسيق HTML هو بالضبط ما يراه المستخدم ويقوم بتنزيله من جانب العميل إلى متصفح الإنترنت الخاص بهم.
- تشير الصفحات الديناميكية إلى قدرة Python واللغات المشابهة على إنشاء HTML أثناء التنقل. وفقا لذلك، يمكن أن يكون لديك صفحات الويب التي يتم إنشاؤها من جانب الخادم عن طريق الشيفرة بناءً على مدخلات المستخدمين أو سلوكهم.
- لقد استخدمت
http-serverفي الماضي لخدمة صفحات الويب الخاصة بك. سنستخدم اليوم خادمًا جديدًا يمكنه تحليل عنوان الويب وتنفيذ الإجراءات بناءً على عنوان URL المقدم. -
علاوة على ذلك، في الأسبوع الماضي، شاهدت عناوين URL كما يلي:
https://www.example.com/folder/file.htmlلاحظ ذلك تم الآن إنشاء
file.htmlهو ملف HTML داخل مجلد يسمىfolderفيexample.com.
قارورة (Flask)
- نقدم هذا الأسبوع إمكانية التفاعل الطرق مثل
https://www.example.com/route?key=value، حيث يمكن إنشاء وظائف محددة على الخادم عبر المفاتيح والقيم المتوفرة في عنوان URL. - قارورة هي مكتبة تابعة لجهة خارجية تسمح لك باستضافة تطبيقات الويب باستخدام إطار عمل Flask، أو إطار عمل صغير، داخل Python.
- يمكنك تشغيل Flask عن طريق التنفيذ
flask runفي نافذتك الطرفية cs50.dev. - للقيام بذلك، سوف تحتاج إلى ملف يسمى
app.pyواتصل آخرrequirements.txt.app.pyيحتوي على كود يخبر Flask بكيفية تشغيل تطبيق الويب الخاص بك. يتضمنrequirements.txtقائمة بالمكتبات المطلوبة لتشغيل تطبيق Flask الخاص بك. -
هنا عينة من
requirements.txt:Flaskإشعار فقط يظهر
Flaskفي هذا الملف. وذلك لأن Flask مطلوب لتشغيل تطبيق Flask. -
إليك تطبيق Flask البسيط جدًا
app.py:# Says hello to world by returning a string of text from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "hello, world"لاحظ أن يتم استخدام كتلة
/يؤدي المسار ببساطة إلى إرجاع النصhello, world. -
يمكننا أيضًا إنشاء تعليمات برمجية تنفذ HTML:
# Says hello to world by returning a string of HTML from flask import Flask app = Flask(__name__) @app.route("/") def index(): return '<!DOCTYPE html><html lang="en"><head><title>hello</title></head><body>hello, world</body></html>'لاحظ أنه بدلاً من إرجاع نص بسيط، فإنه يوفر HTML.
-
من خلال تحسين تطبيقنا، يمكننا أيضًا تقديم HTML بناءً على القوالب عن طريق إنشاء مجلد يسمى
templatesوإنشاء ملف يسمىindex.htmlبالشيفرة التالي داخل هذا المجلد:<!DOCTYPE html> <html lang="en"> <head> <title>hello</title> </head> <body> hello, world </body> </html> -
بعد ذلك، في نفس المجلد الذي يوجد به يظهر مجلد
templates، قم بإنشاء ملف يسمىapp.pyوأضف الشيفرة التالي:# Uses request.args.get from flask import Flask, render_template, request app = Flask(__name__) @app.route("/") def index(): name = request.args.get("name", "world") return render_template("index.html", name=name)لاحظ أن هذا الشيفرة يحدد
appكتطبيق Flask. ومن ثم يحدد/طريقappكإرجاع محتوياتindex.htmlمع وسيطةname. بشكل افتراضي، ستبحث الدالةrequest.args.getعن ملفnameيتم توفيره بواسطة المستخدم. إذا لم يتم تقديم أي اسم، فسيتم تعيينه بشكل افتراضي يُعرفworld.@app.routeباسم مصمم الديكور. -
يمكنك تشغيل تطبيق الويب هذا عن طريق الكتابة
flask runفي النافذة الطرفية. إذا لم يتم تشغيل Flask، فتأكد من صحة بناء الجملة في كل ملف من الملفات أعلاه. علاوة على ذلك، إذا لم يتم تشغيل Flask، فتأكد من تنظيم ملفاتك على النحو التالي:/templates index.html app.py requirements.txt - بمجرد تشغيله، سيُطلب منك النقر فوق الرابط. بمجرد الانتقال إلى صفحة الويب هذه، حاول إضافة
?name=[Your Name]إلى عنوان URL الأساسي في شريط URL الخاص بالمتصفح الخاص بك.
النماذج (Forms)
-
من خلال تحسين برنامجنا، نعلم أن معظم المستخدمين لن يكتبوا الوسائط في شريط العناوين. وبدلاً من ذلك، يعتمد المبرمجون على المستخدمين لملء النماذج على صفحات الويب. وبناء على ذلك، يمكننا تعديل
index.htmlعلى النحو التالي:<!DOCTYPE html> <html lang="en"> <head> <title>hello</title> </head> <body> <form action="/greet" method="get"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> <button type="submit">Greet</button> </form> </body> </html>لاحظ أنه تم الآن إنشاء نموذج يأخذ اسم المستخدم ثم يمرره إلى مسار يسمى تم إيقاف تشغيل
/greet.autocomplete. علاوة على ذلك، أplaceholderبالنص تم تضمينname. -
علاوة على ذلك، يمكننا التغيير
app.pyعلى النحو التالي:# Adds a form, second route from flask import Flask, render_template, request app = Flask(__name__) @app.route("/") def index(): return render_template("index.html") @app.route("/greet") def greet(): return render_template("greet.html", name=request.args.get("name", "world"))لاحظ أن المسار الافتراضي سيعرض نموذجًا للمستخدم لإدخال اسمه. ال
/greetسوف يمر الطريقnameإلى صفحة الويب هذه. -
لإنهاء هذا التنفيذ، ستحتاج إلى قالب آخر لـ المجلد
greet.htmlفي دليلtemplatesكما يلي:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>hello</title> </head> <body> hello, {{ name }} </body> </html>لاحظ أن هذا المسار سيعرض الآن التحية للمستخدم، متبوعة باسمه.
القوالب (Templates)
- كلا صفحتينا على الويب،
index.htmlوgreet.html، تحتوي على الكثير من البيانات نفسها. ألن يكون من اللطيف السماح للنص بأن يكون فريدًا مع نسخ نفس التصميم من صفحة إلى أخرى؟ -
أولاً، قم بإنشاء قالب جديد يسمى
layout.htmlواكتب الشيفرة كما يلي:<!DOCTYPE html> <html lang="en"> <head> <title>hello</title> </head> <body> {% block body %}{% endblock %} </body> </html>لاحظ أن يتم استخدام كتلة
{% block body %}{% endblock %}يسمح بإدراج تعليمات برمجية أخرى من ملفات HTML أخرى. -
ثم قم بتعديل ملفك
index.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} <form action="/greet" method="get"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> <button type="submit">Greet</button> </form> {% endblock %}لاحظ أن السطر
{% extends "layout.html" %}يخبر الخادم بمكان الحصول على تخطيط هذه الصفحة. ثم،{% block body %}{% endblock %}يخبرك بالرمز الذي سيتم إدراجه فيهlayout.html. -
أخيرًا، قم بالتغيير
greet.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} hello, {{ name }} {% endblock %}لاحظ كيف أن هذا الرمز أقصر وأكثر إحكاما.
طرق الطلب (Request Methods)
- يمكنك تخيل سيناريوهات حيث يكون الاستخدام غير آمن
get، حيث ستظهر أسماء المستخدمين وكلمات المرور في عنوان URL. -
يمكننا الاستفادة من هذه الطريقة
postللمساعدة في حل هذه المشكلة عن طريق التعديلapp.pyعلى النحو التالي:# Switches to POST from flask import Flask, render_template, request app = Flask(__name__) @app.route("/") def index(): return render_template("index.html") @app.route("/greet", methods=["POST"]) def greet(): return render_template("greet.html", name=request.form.get("name", "world"))لاحظ ذلك تم الآن إنشاء
POSTإلى قائمة/greetالطريق، والذي نستخدمهrequest.form.getبدلاً منrequest.args.get. - هذا يخبر الخادم أن يبحث أعمق في المظروف الافتراضي وعدم الكشف عن العناصر الموجودة فيه
postفي عنوان URL. -
ومع ذلك، يمكن تطوير هذا الرمز بشكل أكبر من خلال استخدام مسار واحد لكليهما
getوpost. للقيام بذلك، قم بالتعديلapp.pyعلى النحو التالي:# Uses a single route from flask import Flask, render_template, request app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": return render_template("greet.html", name=request.form.get("name", "world")) return render_template("index.html")لاحظ أن كلاهما
getوpostتتم في توجيه واحد. ومع ذلك، يتم استخدامrequest.methodللتوجيه بشكل صحيح بناءً على نوع التوجيه الذي يطلبه المستخدم. -
وبناءً على ذلك، يمكنك تعديل ملفك
index.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} <form action="/" method="post"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> <button type="submit">Greet</button> </form> {% endblock %}لاحظ أن النموذج تم تغيير
action. -
لا يزال هناك خطأ في هذا الشيفرة. مع تطبيقنا الجديد، عندما يقوم شخص ما بكتابة أي اسم في النموذج، يتم عرض
Hello,بدون اسم. يمكننا تحسين الشيفرة الخاص بنا عن طريق التحرير تم تغييرapp.pyعلى النحو التالي:# Moves default value to template from flask import Flask, render_template, request app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": return render_template("greet.html", name=request.form.get("name")) return render_template("index.html")لاحظ ذلك تم الآن إنشاء
name=request.form.get("name")). -
أخيرًا، قم بالتغيير تم تغيير
greet.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} hello, {% if name -%} {{ name }} {%- else -%} world {%- endif %} {% endblock %}لاحظ كيف
hello, {{ name }}للسماح بالإخراج الافتراضي عندما لا يتم تحديد أي اسم. - نظرًا لأننا قمنا بتغيير العديد من الملفات، فقد ترغب في مقارنة الشيفرة النهائي الخاص بك مع الشيفرة النهائي لدينا.
رسائل فروش الفورية (Frosh IMs)
- رسائل فروش الفورية أو فروشيم هو تطبيق ويب يسمح للطلاب بالتسجيل في الرياضات الجماعية.
- أغلق كل ما لديك
helloالنوافذ ذات الصلة وقم بإنشاء مجلد عن طريق الكتابةmkdir froshimsفي النافذة الطرفية. ثم اكتبcd froshimsللاستعراض للوصول إلى هذا المجلد. داخل، قم بإنشاء دليل يسمى القوالب عن طريق الكتابةmkdir templates. -
التالي، في المجلد
froshims، اكتبcode requirements.txtوالشيفرة كما يلي:Flaskكما كان من قبل، مطلوب Flask لتشغيل تطبيق Flask.
-
أخيرًا، اكتب يتم توفير خيار
code app.pyواكتب الشيفرة كما يلي:# Implements a registration form using a select menu, validating sport server-side from flask import Flask, render_template, request app = Flask(__name__) SPORTS = [ "Basketball", "Soccer", "Ultimate Frisbee" ] @app.route("/") def index(): return render_template("index.html", sports=SPORTS) @app.route("/register", methods=["POST"]) def register(): # Validate submission if not request.form.get("name") or request.form.get("sport") not in SPORTS: return render_template("failure.html") # Confirm registration return render_template("success.html")لاحظ أن أ يتم فتح علامة
failure، بحيث يتم عرض رسالة فشل للمستخدم إذا كانnameأوsportلم يتم ملء الحقل بشكل صحيح. -
بعد ذلك، قم بإنشاء ملف في ملف تم استدعاء المجلد
templatesindex.htmlعن طريق الكتابةcode templates/index.htmlواكتب الشيفرة كما يلي:{% extends "layout.html" %} {% block body %} <h1>Register</h1> <form action="/register" method="post"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> <select name="sport"> <option selected value="">Sport</option> {% for sport in sports %} <option value="{{ sport }}">{{ sport }}</option> {% endfor %} </select> <button type="submit">Register</button> </form> {% endblock %} -
بعد ذلك، قم بإنشاء ملف يسمى
layout.htmlعن طريق الكتابةcode templates/layout.htmlواكتب الشيفرة كما يلي:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>froshims</title> </head> <body> {% block body %}{% endblock %} </body> </html> -
رابعا، قم بإنشاء ملف في القوالب يسمى
success.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} You are registered! {% endblock %} -
أخيرًا، قم بإنشاء ملف في قوالب يسمى
failure.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} You are not registered! {% endblock %} - تنفيذ
flask runوالتحقق من التطبيق في هذه المرحلة. -
يمكنك أن تتخيل كيف قد نرغب في رؤية خيارات التسجيل المتنوعة باستخدام أزرار الاختيار. يمكننا أن نتحسن
index.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} <h1>Register</h1> <form action="/register" method="post"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> {% for sport in sports %} <input name="sport" type="radio" value="{{ sport }}"> {{ sport }} {% endfor %} <button type="submit">Register</button> </form> {% endblock %}لاحظ كيف
typeإلىradio. - مرة أخرى، جاري التنفيذ
flask runيمكنك أن ترى كيف تغيرت الواجهة الآن. -
يمكنك أن تتخيل كيف قد نرغب في قبول تسجيل العديد من المسجلين المختلفين. يمكننا أن نتحسن
app.pyعلى النحو التالي:# Implements a registration form, storing registrants in a dictionary, with error messages from flask import Flask, redirect, render_template, request app = Flask(__name__) REGISTRANTS = {} SPORTS = [ "Basketball", "Soccer", "Ultimate Frisbee" ] @app.route("/") def index(): return render_template("index.html", sports=SPORTS) @app.route("/register", methods=["POST"]) def register(): # Validate name name = request.form.get("name") if not name: return render_template("error.html", message="Missing name") # Validate sport sport = request.form.get("sport") if not sport: return render_template("error.html", message="Missing sport") if sport not in SPORTS: return render_template("error.html", message="Invalid sport") # Remember registrant REGISTRANTS[name] = sport # Confirm registration return redirect("/registrants") @app.route("/registrants") def registrants(): return render_template("registrants.html", registrants=REGISTRANTS)لاحظ أن القاموس يسمى يتم استخدام
REGISTRANTSلتسجيل الدخولsportتم التحديد بواسطةREGISTRANTS[name]. لاحظ ذلك أيضًاregistrants=REGISTRANTSيقوم بتمرير القاموس إلى هذا القالب. -
بالإضافة إلى ذلك، يمكننا التنفيذ
error.html:{% extends "layout.html" %} {% block body %} <h1>Error</h1> <p>{{ message }}</p> <img alt="Grumpy Cat" src="/static/cat.jpg"> {% endblock %} -
علاوة على ذلك، قم بإنشاء قالب جديد يسمى سيتم تكرار
registrants.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} <h1>Registrants</h1> <table> <thead> <tr> <th>Name</th> <th>Sport</th> </tr> </thead> <tbody> {% for name in registrants %} <tr> <td>{{ name }}</td> <td>{{ registrants[name] }}</td> </tr> {% endfor %} </tbody> </table> {% endblock %}لاحظ ذلك تم الآن إنشاء
{% for name in registrants %}...{% endfor %}من خلال كل من المسجلين. قوية جدًا لتكون قادرًا على التكرار على صفحة ويب ديناميكية! - أخيرًا، قم بإنشاء مجلد يسمى
staticفي نفس المجلدapp.py. هناك، قم بتحميل الملف التالي من a قطة. - تنفيذ
flask runواللعب بالتطبيق. - لديك الآن تطبيق ويب! ومع ذلك، هناك بعض العيوب الأمنية! نظرًا لأن كل شيء محفوظ في الذاكرة، يمكن للخصم تغيير HTML و الإختراق الموقع. علاوة على ذلك، لن تستمر هذه البيانات إذا تم إيقاف تشغيل الخادم. هل يمكن أن تكون هناك طريقة ما يمكننا من خلالها الاحتفاظ ببياناتنا حتى عند إعادة تشغيل الخادم؟
القارورة وSQL (Flask and SQL)
- تمامًا كما رأينا كيف يمكن لـ Python التفاعل مع قاعدة بيانات SQL، يمكننا الجمع بين قوة Flask وPython وSQL لإنشاء تطبيق ويب حيث ستستمر البيانات!
- لتنفيذ ذلك، ستحتاج إلى اتخاذ عدد من الخطوات.
- أولاً، قم بتنزيل ما يلي قاعدة بيانات SQL في الخاص بك
مجلد
froshims. - يتم تنفيذه في المحطة
sqlite3 froshims.dbواكتب.schemaلمعرفة محتويات ملف قاعدة البيانات. مزيد من النوعSELECT * FROM registrants;للتعرف على المحتويات. ستلاحظ أنه لا يوجد حاليًا أي تسجيلات في الملف. -
بعد ذلك، قم بالتعديل
requirements.txtعلى النحو التالي:cs50 Flask -
تعديل
index.htmlعلى النحو التالي:{% extends "layout.html" %} {% block body %} <h1>Register</h1> <form action="/register" method="post"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> {% for sport in sports %} <input name="sport" type="checkbox" value="{{ sport }}"> {{ sport }} {% endfor %} <button type="submit">Register</button> </form> {% endblock %} -
تعديل
layout.htmlعلى النحو التالي:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>froshims</title> </head> <body> {% block body %}{% endblock %} </body> </html> -
تأكد يظهر
error.htmlكما يلي:{% extends "layout.html" %} {% block body %} <h1>Error</h1> <p>{{ message }}</p> <img alt="Grumpy Cat" src="/static/cat.jpg"> {% endblock %} -
تعديل
registrants.htmlلتظهر بالشكل التالي:{% extends "layout.html" %} {% block body %} <h1>Registrants</h1> <table> <thead> <tr> <th>Name</th> <th>Sport</th> <th></th> </tr> </thead> <tbody> {% for registrant in registrants %} <tr> <td>{{ registrant.name }}</td> <td>{{ registrant.sport }}</td> <td> <form action="/deregister" method="post"> <input name="id" type="hidden" value="{{ registrant.id }}"> <button type="submit">Deregister</button> </form> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}لاحظ أن هناك قيمة مخفية تم تضمين
registrant.idبحيث يمكن استخدام هذاidلاحقًاapp.py -
أخيرًا، قم بالتعديل يتم استخدام مكتبة
app.pyعلى النحو التالي:# Implements a registration form, storing registrants in a SQLite database, with support for multiple sports and deregistration from cs50 import SQL from flask import Flask, redirect, render_template, request app = Flask(__name__) db = SQL("sqlite:///froshims.db") SPORTS = [ "Basketball", "Soccer", "Ultimate Frisbee" ] @app.route("/") def index(): return render_template("index.html", sports=SPORTS) @app.route("/deregister", methods=["POST"]) def deregister(): # Forget registrant id = request.form.get("id") if id: db.execute("DELETE FROM registrants WHERE id = ?", id) return redirect("/registrants") @app.route("/register", methods=["POST"]) def register(): # Validate name name = request.form.get("name") if not name: return render_template("error.html", message="Missing name") # Validate sports sports = request.form.getlist("sport") if not sports: return render_template("error.html", message="Missing sport") for sport in sports: if sport not in SPORTS: return render_template("error.html", message="Invalid sport") # Remember registrant for sport in sports: db.execute("INSERT INTO registrants (name, sport) VALUES(?, ?)", name, sport) # Confirm registration return redirect("/registrants") @app.route("/registrants") def registrants(): registrants = db.execute("SELECT * FROM registrants") return render_template("registrants.html", registrants=registrants)لاحظ أن يتم استخدام كتلة
cs50. يتم تضمين الطريق لregisterلـ طريقةpost. سيأخذ هذا المسار الاسم والرياضة المأخوذة من نموذج التسجيل وينفذ استعلام SQL لإضافة ملفnameوsportإلىregistrantsالجدول. الderegisterيوجه إلى استعلام SQL الذي سيستحوذ على استعلام المستخدمidواستخدم هذه المعلومات لإلغاء تسجيل هذا الشخص. - يمكنك التنفيذ
flask runوفحص النتيجة. - إذا كنت ترغب في تنزيل تطبيقنا لـ
froshimsيمكنك القيام بذلك هنا. - يمكنك قراءة المزيد عن Flask في توثيق القارورة.
ملفات تعريف الارتباط والجلسة (Cookies and Session)
-
app.pyيعتبر أ وحدة التحكم. أ عرض يعتبر ما يراه المستخدمون. أ نموذج هي كيفية تخزين البيانات ومعالجتها. ويشار إلى هذا معًا باسم MVC (نموذج، عرض، جهاز تحكم). - أثناء التنفيذ المسبق لـ
يعد
froshimsمفيدًا من وجهة نظر إدارية، حيث يمكن لمسؤول المكتب الخلفي إضافة وإزالة الأفراد من قاعدة البيانات، ويمكن للمرء أن يتخيل كيف أن هذا الرمز ليس آمنًا للتنفيذ على خادم عام. - أولاً، يمكن للجهات الفاعلة السيئة اتخاذ قرارات نيابة عن مستخدمين آخرين عن طريق الضغط على زر إلغاء التسجيل - مما يؤدي فعليًا إلى حذف إجابتهم المسجلة من الخادم.
- تستخدم خدمات الويب مثل Google بيانات اعتماد تسجيل الدخول لضمان وصول المستخدمين إلى البيانات الصحيحة فقط.
- يمكننا بالفعل تنفيذ هذا بنفسنا باستخدام ملفات تعريف الارتباط. ملفات تعريف الارتباط هي أجزاء صغيرة من البيانات يتم تخزينها في متصفحك بحيث يتمكن متصفحك من الاتصال بالخادم والقول بشكل فعال، "أنا مستخدم معتمد قام بتسجيل الدخول بالفعل". يُسمى هذا التفويض من خلال ملف تعريف الارتباط هذا بـ جلسة .
-
يمكن تخزين ملفات تعريف الارتباط على النحو التالي:
GET / HTTP/2 Host: accounts.google.com Cookie: session=valueهنا، أ يتم تخزين معرف
sessionبمعرف معينvalueيمثل تلك الجلسة. - في أبسط صورة، يمكننا تنفيذ ذلك عن طريق إنشاء مجلد يسمى
loginثم قم بإضافة الملفات التالية. -
أولاً، قم بإنشاء ملف يسمى
requirements.txtيقرأ كما يلي:Flask Flask-Sessionلاحظ أنه بالإضافة إلى
Flask، ندرجه أيضًاFlask-Session، وهو مطلوب لدعم جلسات تسجيل الدخول. -
ثانيا، في أ مجلد
templates، قم بإنشاء ملف يسمىlayout.htmlالذي يظهر كما يلي:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>login</title> </head> <body> {% block body %}{% endblock %} </body> </html>لاحظ أن هذا يوفر تخطيطًا بسيطًا للغاية مع عنوان ونص.
-
ثالثًا، قم بإنشاء ملف في ملف تم استدعاء المجلد
templatesindex.htmlالذي يظهر كما يلي:{% extends "layout.html" %} {% block body %} {% if name -%} You are logged in as {{ name }}. <a href="/logout">Log out</a>. {%- else -%} You are not logged in. <a href="/login">Log in</a>. {%- endif %} {% endblock %}لاحظ أن هذا الملف يبحث لمعرفة ما إذا كان
session["name"]موجود (تم تفصيله بشكل أكبر فيapp.pyأدناه). إذا حدث ذلك، فسوف يتم عرض رسالة ترحيب. إذا لم يكن الأمر كذلك، فسوف ننصحك بالتصفح للوصول إلى صفحة لتسجيل الدخول. -
رابعا، قم بإنشاء ملف يسمى
login.htmlوأضف الشيفرة التالي:{% extends "layout.html" %} {% block body %} <form action="/login" method="post"> <input autocomplete="off" autofocus name="name" placeholder="Name" type="text"> <button type="submit">Log In</button> </form> {% endblock %}لاحظ أن هذا هو تخطيط صفحة تسجيل الدخول الأساسية.
-
أخيرًا، قم بإنشاء ملف يسمى
app.pyواكتب الشيفرة كما يلي:from flask import Flask, redirect, render_template, request, session from flask_session import Session # Configure app app = Flask(__name__) # Configure session app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" Session(app) @app.route("/") def index(): return render_template("index.html", name=session.get("name")) @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": session["name"] = request.form.get("name") return redirect("/") return render_template("login.html") @app.route("/logout") def logout(): session.clear() return redirect("/")لاحظ التعديل الواردات في أعلى الملف، بما في ذلك
session، والذي سيسمح لك بدعم الجلسات. والأهم من ذلك، لاحظ كيف يتم استخدامsession["name"]فيloginوlogoutالطرق. ال سيقوم مسارloginبتعيين اسم تسجيل الدخول المقدم وتعيينه إليهsession["name"]. ومع ذلك، فيlogout، يتم تنفيذ تسجيل الخروج عن طريق مسح قيمةsession. - ال
يتم استخدام الدالة
sessionيسمح لك التجريد بالتأكد من أن مستخدمًا محددًا فقط لديه حق الوصول إلى بيانات وميزات محددة في تطبيقنا. فهو يسمح لك بالتأكد من عدم قيام أي شخص بالتصرف نيابة عن مستخدم آخر، سواء كان ذلك للخير أو للشر! - إذا كنت ترغب في ذلك، يمكنك التنزيل تنفيذنا من
login. - يمكنك قراءة المزيد عن الجلسات في توثيق القارورة.
سلة التسوق (Shopping Cart)
- ننتقل إلى المثال الأخير لاستخدام قدرة Flask على تمكين الجلسة.
-
قمنا بفحص الشيفرة التالي لـ
storeفيapp.py. تم عرض الشيفرة التالي: يتم تنفيذfrom cs50 import SQL from flask import Flask, redirect, render_template, request, session from flask_session import Session # Configure app app = Flask(__name__) # Connect to database db = SQL("sqlite:///store.db") # Configure session app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" Session(app) @app.route("/") def index(): books = db.execute("SELECT * FROM books") return render_template("books.html", books=books) @app.route("/cart", methods=["GET", "POST"]) def cart(): # Ensure cart exists if "cart" not in session: session["cart"] = [] # POST if request.method == "POST": book_id = request.form.get("id") if book_id: session["cart"].append(book_id) return redirect("/cart") # GET books = db.execute("SELECT * FROM books WHERE id IN (?)", session["cart"]) return render_template("cart.html", books=books)لاحظ ذلك تم الآن إنشاء
cartباستخدام القائمة. يمكن إضافة العناصر إلى هذه القائمة باستخدام أزرارAdd to Cartفيbooks.html. عند النقر على مثل هذا الزر، يتم استدعاء الأسلوبpost، حيث تم إلحاقidمن العنصر بـcart. عند عرض العربة، استدعاء طريقةget، يتم تنفيذ SQL لعرض قائمة بالكتب الموجودة في سلة التسوق. -
رأينا أيضًا محتويات
books.html:{% extends "layout.html" %} {% block body %} <h1>Books</h1> {% for book in books %} <h2>{{ book["title"] }}</h2> <form action="/cart" method="post"> <input name="id" type="hidden" value="{{ book['id'] }}"> <button type="submit">Add to Cart</button> </form> {% endfor %} {% endblock %}لاحظ كيف يؤدي ذلك إلى إنشاء القدرة على ذلك
Add to Cartلكل كتاب يستخدمfor book in books. - يمكنك رؤية بقية الملفات التي تدعم هذا
تنفيذ
flaskفي الشيفرة المصدرية.
عروض (Shows)
-
نظرنا إلى برنامج مصمم مسبقًا يسمى
shows، في يتيح مسارapp.py:# Searches for shows using LIKE from cs50 import SQL from flask import Flask, render_template, request app = Flask(__name__) db = SQL("sqlite:///shows.db") @app.route("/") def index(): return render_template("index.html") @app.route("/search") def search(): shows = db.execute("SELECT * FROM shows WHERE title LIKE ?", "%" + request.args.get("q") + "%") return render_template("search.html", shows=shows)لاحظ كيف يتم استدعاء الدالة
searchطريقة للبحث عن ملفshow. هذا البحث يبحث عن العناوينLIKEالذي قدمه المستخدم. -
لقد فحصنا أيضًا
index.html:{% extends "layout.html" %} {% block body %} <form action="/search" method="get"> <input autocomplete="off" autofocus name="q" placeholder="Query" type="search"> <button type="submit">Search</button> </form> {% endblock %} -
يمكنك رؤية بقية ملفات هذا التنفيذ في ملف الشيفرة المصدرية.
واجهات برمجة التطبيقات (APIs)
- أن واجهة برنامج التطبيق أو واجهة برمجة التطبيقات عبارة عن سلسلة من المواصفات التي تتيح لك التفاعل مع خدمة أخرى. على سبيل المثال، يمكننا استخدام واجهة برمجة تطبيقات IMDB للتفاعل مع قاعدة البيانات الخاصة بهم. قد نقوم أيضًا بدمج واجهات برمجة التطبيقات للتعامل مع أنواع معينة من البيانات التي يمكن تنزيلها من الخادم.
-
التحسين
shows، النظر في تحسينapp.py، رأينا ما يلي: ينفذ المسار# Searches for shows using Ajax from cs50 import SQL from flask import Flask, render_template, request app = Flask(__name__) db = SQL("sqlite:///shows.db") @app.route("/") def index(): return render_template("index.html") @app.route("/search") def search(): q = request.args.get("q") if q: shows = db.execute("SELECT * FROM shows WHERE title LIKE ? LIMIT 50", "%" + q + "%") else: shows = [] return render_template("search.html", shows=shows)لاحظ أن يتم استخدام كتلة
searchاستعلام SQL. -
ينظر
search.html، ستلاحظ أن الأمر بسيط جدًا:{% for show in shows %} <li>{{ show["title"] }}</li> {% endfor %}لاحظ أنه يوفر قائمة ذات تعداد نقطي.
-
أخيرًا، أنظر
index.html، لاحظ ذلك أجاكس يتم استخدام كود لتشغيل البحث:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>shows</title> </head> <body> <input autocomplete="off" autofocus placeholder="Query" type="search"> <ul></ul> <script> let input = document.querySelector('input'); input.addEventListener('input', async function() { let response = await fetch('/search?q=' + input.value); let shows = await response.text(); document.querySelector('ul').innerHTML = shows; }); </script> </body> </html>لاحظ أنه يتم استخدام مستمع الحدث للاستعلام ديناميكيًا عن الخادم لتوفير قائمة تتطابق مع العنوان المقدم. سيؤدي هذا إلى تحديد موقع ضع علامة
ulفي HTML وقم بتعديل صفحة الويب وفقًا لذلك لتضمين قائمة المطابقات. - يمكنك قراءة المزيد في وثائق أجاكس.
JSON
- تدوين كائن جافا سكريبت أو JSON هو ملف نصي يحتوي على قواميس تحتوي على مفاتيح وقيم. هذه طريقة أولية وصديقة للكمبيوتر للحصول على الكثير من البيانات.
- تعد JSON طريقة مفيدة جدًا لاستعادة البيانات من الخادم.
-
يمكنك رؤية هذا عمليًا في
index.htmlفحصنا معًا:<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="initial-scale=1, width=device-width"> <title>shows</title> </head> <body> <input autocomplete="off" autofocus placeholder="Query" type="text"> <ul></ul> <script> let input = document.querySelector('input'); input.addEventListener('input', async function() { let response = await fetch('/search?q=' + input.value); let shows = await response.json(); let html = ''; for (let i in shows) { let title = shows[i].title.replace('<', '<').replace('&', '&'); html += '<li>' + title + '</li>'; } document.querySelector('ul').innerHTML = html; }); </script> </body> </html>على الرغم من أن ما ورد أعلاه قد يكون غامضًا إلى حد ما، إلا أنه يوفر لك نقطة بداية للبحث عن JSON بنفسك لمعرفة كيف يمكن تنفيذه في تطبيقات الويب الخاصة بك.
-
علاوة على ذلك، قمنا بفحصها
app.pyلمعرفة كيفية الحصول على استجابة JSON: يتم استخدام# Searches for shows using Ajax with JSON from cs50 import SQL from flask import Flask, jsonify, render_template, request app = Flask(__name__) db = SQL("sqlite:///shows.db") @app.route("/") def index(): return render_template("index.html") @app.route("/search") def search(): q = request.args.get("q") if q: shows = db.execute("SELECT * FROM shows WHERE title LIKE ? LIMIT 50", "%" + q + "%") else: shows = [] return jsonify(shows)لاحظ كيف
jsonifyلتحويل النتيجة إلى تنسيق قابل للقراءة مقبول بواسطة تطبيقات الويب المعاصرة. - يمكنك قراءة المزيد في وثائق JSON.
- باختصار، لديك الآن القدرة على إكمال تطبيقات الويب الخاصة بك باستخدام Python وFlask وHTML وSQL.
التلخيص (Summing Up)
في هذا الدرس، تعلمت كيفية استخدام Python وSQL وFlask لإنشاء تطبيقات الويب. على وجه التحديد، ناقشنا…
- قارورة
- النماذج
- القوالب
- طرق الطلب
- القارورة وSQL
- ملفات تعريف الارتباط والجلسة
- واجهات برمجة التطبيقات
- JSON