قراءة موجّهة · الملاحظات

الأسبوع 9: Flask

اقرأ للفهم، ثم دوّن المصطلحات الإنجليزية التي تحتاج إلى تذكّرها أثناء التطبيق.

جلسة دراسة مقترحة: حتى 55 دقيقةWeek 9
محاور هذه الخطوة
  • Flask
  • القوالب
  • المسارات
  • الجلسات

ترجمة آلية تحت المراجعة

الأسبوع 9: Flask

المصدر الأصلي على CS50

المحاضرة التاسعة (Lecture 9)

مرحبًا! (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 لم يتم ملء الحقل بشكل صحيح.

  • بعد ذلك، قم بإنشاء ملف في ملف تم استدعاء المجلد templates index.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>
    

    لاحظ أن هذا يوفر تخطيطًا بسيطًا للغاية مع عنوان ونص.

  • ثالثًا، قم بإنشاء ملف في ملف تم استدعاء المجلد templates index.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('<', '&lt;').replace('&', '&amp;');
                        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
أنهيت قراءة الملاحظات؟

يمكنك قراءة الدورة كاملة دون حساب. يصبح حفظ التقدم متاحًا بعد تفعيل الحساب، ويبقى محفوظًا بعد انتهاء العضوية.