كيفية استعلام الجداول وتقسيم البيانات في Flask-SQLAlchemy

اختار الكاتب صندوق البرمجيات الحرة والمفتوحة المصدر ليتلقى تبرعًا كجزء من برنامج الكتابة من أجل التبرعات.

مقدمة

فلاسك هو إطار عمل خفيف للويب بلغة Python يوفر أدوات وميزات مفيدة لإنشاء تطبيقات ويب باستخدام لغة Python. SQLAlchemy هو مجموعة أدوات SQL توفر وصولًا فعّالًا وذو أداء عالٍ إلى قواعد البيانات العلاقية. يوفر طرقًا للتفاعل مع عدة محركات قواعد بيانات مثل SQLite و MySQL و PostgreSQL. يمنحك الوصول إلى وظائف SQL في قاعدة البيانات. ويمنحك أيضًا محول بيانات موضوعية (ORM)، الذي يسمح لك بإجراء الاستعلامات ومعالجة البيانات باستخدام كائنات Python بسيطة وطرق. Flask-SQLAlchemy هو امتداد Flask الذي يجعل استخدام SQLAlchemy مع Flask أسهل، حيث يوفر لك أدوات وطرقًا للتفاعل مع قاعدة البيانات في تطبيقات Flask الخاصة بك من خلال SQLAlchemy.

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

ستستخدم واجهة السطر لـ Flask للاستعلام عن جدول، والحصول على سجلات الجدول استنادًا إلى قيمة العمود (على سبيل المثال، البريد الإلكتروني). ستسترد سجلات الموظفين بشروط معينة، مثل الحصول فقط على الموظفين النشطين أو الحصول على قائمة بالموظفين الخارجين عن العمل. سترتب النتائج حسب قيمة العمود، وتحسب وتحدد نتائج الاستعلام. وأخيرًا، ستستخدم ترقيم الصفحات لعرض عدد معين من الموظفين في كل صفحة في تطبيق ويب.

المتطلبات المسبقة

الخطوة 1 — إعداد قاعدة البيانات والنموذج

في هذه الخطوة، ستقوم بتثبيت الحزم اللازمة، وإعداد تطبيق Flask الخاص بك، وقاعدة بيانات Flask-SQLAlchemy، والنموذج الخاص بالموظفين الذي يمثل جدول الموظفين حيث ستقوم بتخزين بيانات الموظفين الخاصة بك. ستقوم بإدراج عدد قليل من الموظفين في جدول الموظفين، وإضافة مسار وصفحة حيث يتم عرض جميع الموظفين على صفحة الفهرس لتطبيقك.

أولاً، مع تنشيط بيئتك الظاهرية، قم بتثبيت Flask و Flask-SQLAlchemy:

  1. pip install Flask Flask-SQLAlchemy

عندما يكتمل التثبيت، ستتلقى إخراجًا يحتوي على السطر التالي في النهاية:

Output
Successfully installed Flask-2.1.2 Flask-SQLAlchemy-2.5.1 Jinja2-3.1.2 MarkupSafe-2.1.1 SQLAlchemy-1.4.37 Werkzeug-2.1.2 click-8.1.3 greenlet-1.1.2 itsdangerous-2.1.2

مع التطبيقات المطلوبة المثبتة، قم بفتح ملف جديد يسمى app.py في دليل flask_app الخاص بك. سيحتوي هذا الملف على الشيفرة لإعداد قاعدة البيانات ومسارات Flask الخاصة بك:

  1. nano app.py

أضف الشيفرة التالية إلى app.py. ستقوم هذه الشيفرة بإعداد قاعدة بيانات SQLite ونموذج قاعدة بيانات للموظف يمثل جدول employee الذي ستستخدمه لتخزين بيانات موظفيك:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy


basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Employee(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    age = db.Column(db.Integer, nullable=False)
    hire_date = db.Column(db.Date, nullable=False)
    active = db.Column(db.Boolean, nullable=False)

    def __repr__(self):
        return f'<Employee {self.firstname} {self.lastname}>'

احفظ وأغلق الملف.

هنا، تقوم بتوريد موديول os، الذي يمنحك الوصول إلى واجهات نظام التشغيل المتنوعة. ستستخدمه لإنشاء مسار ملف لقاعدة بياناتك database.db.

من حزمة flask، قم بتوريد المساعدين الذين تحتاجهم لتطبيقك: فئة Flask لإنشاء مثيل تطبيق Flask، render_template() لعرض القوالب، كائن request لمعالجة الطلبات، url_for() لإنشاء عناوين URL، ودالة redirect() لتوجيه المستخدمين. لمزيد من المعلومات حول المسارات والقوالب، انظر كيفية استخدام القوالب في تطبيق Flask.

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

لبناء مسار لملف قاعدة البيانات الخاص بك، يجب عليك تعريف دليل أساسي كدليل حالي. تستخدم دالة os.path.abspath() للحصول على المسار المطلق لدليل ملف الحالي. المتغير الخاص __file__ يحتوي على مسار ملف app.py الحالي. تقوم بتخزين المسار المطلق للدليل الأساسي في متغير يسمى basedir.

ثم تنشئ مثيلًا لتطبيق Flask يُسمى app، الذي تستخدمه لتكوين مفتاحين لتكوين Flask-SQLAlchemy:

  • SQLALCHEMY_DATABASE_URI: هو رابط URI لقاعدة البيانات التي ترغب في إنشاء اتصال بها. في هذه الحالة، يتبع الرابط الشكل sqlite:///المسار/إلى/قاعدة/البيانات.db. تستخدم دالة os.path.join() للانضمام بذكاء إلى الدليل الأساسي الذي قمت ببنائه وتخزينه في المتغير basedir مع اسم ملف database.db. سيتم الاتصال بملف قاعدة بيانات database.db في دليل flask_app الخاص بك. سيتم إنشاء الملف بمجرد بدء تشغيل قاعدة البيانات.

  • SQLALCHEMY_TRACK_MODIFICATIONS: تكوين لتمكين أو تعطيل تتبع التعديلات على الكائنات. يتم تعيينه على False لتعطيل التتبع، مما يستخدم أقل كمية من الذاكرة. لمزيد من المعلومات، انظر صفحة التكوين في توثيق Flask-SQLAlchemy.

بعد تكوين SQLAlchemy عن طريق تحديد عنوان URI لقاعدة البيانات وتعطيل التتبع، يتم إنشاء كائن قاعدة بيانات باستخدام فئة SQLAlchemy، وتمرير نموذج التطبيق لتوصيل تطبيق Flask الخاص بك بـ SQLAlchemy. يتم تخزين كائن قاعدة البيانات في متغير يُسمى db، والذي ستستخدمه للتفاعل مع قاعدة البيانات الخاصة بك.

بعد إعداد مثيل التطبيق وكائن قاعدة البيانات، يتمتع بتركيبك من الفئة db.Model لإنشاء نموذج قاعدة بيانات يُسمى Employee. يمثل هذا النموذج الجدول employee، ويحتوي على الأعمدة التالية:

  • id: معرف الموظف، وهو مفتاح أساسي صحيح.
  • firstname: اسم الموظف الأول، سلسلة نصية بحد أقصى 100 حرف. تُعنى nullable=False بأن هذه العمود يجب ألا يكون فارغاً.
  • lastname: اسم العائلة للموظف، سلسلة نصية بحد أقصى 100 حرف. تُعنى nullable=False بأن هذا العمود يجب ألا يكون فارغاً.
  • email: بريد الموظف الإلكتروني، سلسلة نصية بحد أقصى 100 حرف. unique=True تُعنى بأن كل بريد إلكتروني يجب أن يكون فريداً. nullable=False تُعنى بأن قيمته لا يجب أن تكون فارغة.
  • age: عمر الموظف، قيمة عددية صحيحة.
  • hire_date: تاريخ تعيين الموظف. تقوم بتعيين db.Date كنوع للعمود لتعلن عنه كعمود يحتوي على تواريخ.
  • active: عمود يحمل قيمة منطقية للدلالة على ما إذا كان الموظف نشطًا حاليًا أم خارج المكتب.

الدالة __repr__ الخاصة تسمح لك بإعطاء كل كائن تمثيل نصي لتمييزه لأغراض التصحيح. في هذه الحالة، تستخدم الاسم الأول واسم العائلة للموظف لتمثيل كل كائن موظف.

الآن بعد أن قمت بتعيين اتصال قاعدة البيانات ونموذج الموظف، ستقوم بكتابة برنامج Python لإنشاء قاعدة بياناتك وجدول employee وملء الجدول ببعض بيانات الموظفين.

افتح ملفًا جديدًا يسمى init_db.py في دليلك flask_app:

  1. nano init_db.py

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

flask_app/init_db.py
from datetime import date
from app import db, Employee

db.drop_all()
db.create_all()

e1 = Employee(firstname='John',
              lastname='Doe',
              email='[email protected]',
              age=32,
              hire_date=date(2012, 3, 3),
              active=True
              )

e2 = Employee(firstname='Mary',
              lastname='Doe',
              email='[email protected]',
              age=38,
              hire_date=date(2016, 6, 7),
              active=True
              )

e3 = Employee(firstname='Jane',
              lastname='Tanaka',
              email='[email protected]',
              age=32,
              hire_date=date(2015, 9, 12),
              active=False
              )

e4 = Employee(firstname='Alex',
              lastname='Brown',
              email='[email protected]',
              age=29,
              hire_date=date(2019, 1, 3),
              active=True
              )

e5 = Employee(firstname='James',
              lastname='White',
              email='[email protected]',
              age=24,
              hire_date=date(2021, 2, 4),
              active=True
              )

e6 = Employee(firstname='Harold',
              lastname='Ishida',
              email='[email protected]',
              age=52,
              hire_date=date(2002, 3, 6),
              active=False
              )

e7 = Employee(firstname='Scarlett',
              lastname='Winter',
              email='[email protected]',
              age=22,
              hire_date=date(2021, 4, 7),
              active=True
              )

e8 = Employee(firstname='Emily',
              lastname='Vill',
              email='[email protected]',
              age=27,
              hire_date=date(2019, 6, 9),
              active=True
              )

e9 = Employee(firstname='Mary',
              lastname='Park',
              email='[email protected]',
              age=30,
              hire_date=date(2021, 8, 11),
              active=True
              )

db.session.add_all([e1, e2, e3, e4, e5, e6, e7, e8, e9])

db.session.commit()

هنا، تقوم باستيراد فئة date() من وحدة datetime لاستخدامها لتحديد تواريخ تعيين الموظفين.

تقوم باستيراد كائن قاعدة البيانات ونموذج Employee. تقوم بالاتصال بوظيفة db.drop_all() لحذف جميع الجداول الحالية لتجنب فرصة وجود جدول employee ممتلئ بالفعل في قاعدة البيانات، مما قد يسبب مشاكل. يقوم هذا بحذف جميع بيانات قاعدة البيانات كلما قمت بتنفيذ برنامج init_db.py. لمزيد من المعلومات حول إنشاء وتعديل وحذف جداول قاعدة البيانات، انظر كيفية استخدام Flask-SQLAlchemy للتفاعل مع قواعد البيانات في تطبيق Flask.

ثم تقوم بإنشاء عدة مثيلات من نموذج Employee، والتي تمثل الموظفين الذين ستقوم بالاستعلام عنهم في هذا البرنامج التعليمي، وتضيفهم إلى جلسة قاعدة البيانات باستخدام الدالة db.session.add_all(). وأخيرًا، تقوم بتأكيد العملية وتطبيق التغييرات على قاعدة البيانات باستخدام db.session.commit().

احفظ وأغلق الملف.

قم بتنفيذ برنامج init_db.py:

  1. python init_db.py

للتحقق من البيانات التي أضفتها إلى قاعدة البيانات الخاصة بك، تأكد من تفعيل البيئة الافتراضية الخاصة بك، وافتح محرر Flask للاستعلام عن جميع الموظفين وعرض بياناتهم:

  1. flask shell

قم بتشغيل الكود التالي للاستعلام عن جميع الموظفين وعرض بياناتهم:

  1. from app import db, Employee
  2. employees = Employee.query.all()
  3. for employee in employees:
  4. print(employee.firstname, employee.lastname)
  5. print('Email:', employee.email)
  6. print('Age:', employee.age)
  7. print('Hired:', employee.hire_date)
  8. if employee.active:
  9. print('Active')
  10. else:
  11. print('Out of Office')
  12. print('----')

تستخدم الطريقة all() للوصول إلى جميع الموظفين. تكرر النتائج، وعرض معلومات الموظف. بالنسبة للعمود active، تستخدم عبارة شرطية لعرض الحالة الحالية للموظف، إما 'Active' أو 'Out of Office'.

ستتلقى الناتج التالي:

Output
John Doe Email: [email protected] Age: 32 Hired: 2012-03-03 Active ---- Mary Doe Email: [email protected] Age: 38 Hired: 2016-06-07 Active ---- Jane Tanaka Email: [email protected] Age: 32 Hired: 2015-09-12 Out of Office ---- Alex Brown Email: [email protected] Age: 29 Hired: 2019-01-03 Active ---- James White Email: [email protected] Age: 24 Hired: 2021-02-04 Active ---- Harold Ishida Email: [email protected] Age: 52 Hired: 2002-03-06 Out of Office ---- Scarlett Winter Email: [email protected] Age: 22 Hired: 2021-04-07 Active ---- Emily Vill Email: [email protected] Age: 27 Hired: 2019-06-09 Active ---- Mary Park Email: [email protected] Age: 30 Hired: 2021-08-11 Active ----

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

اخرج من محرر Flask:

  1. exit()

بعد ذلك، ستقوم بإنشاء مسار Flask لعرض الموظفين. افتح app.py للتحرير:

  1. nano app.py

أضف المسار التالي في نهاية الملف:

flask_app/app.py
...

@app.route('/')
def index():
    employees = Employee.query.all()
    return render_template('index.html', employees=employees)

احفظ وأغلق الملف.

يستعلم عن جميع الموظفين، ويقوم بتقديم قالب index.html، ويمرر له الموظفين الذين استرجعتهم.

إنشاء دليل للقوالب وقالب أساسي:قالب القاعدة:

  1. mkdir templates
  2. nano templates/base.html

أضف ما يلي إلى base.html:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .title {
            margin: 5px;
        }

        .content {
            margin: 5px;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }

        .employee {
            flex: 20%;
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3;
            inline-size: 100%;
        }

        .name {
            color: #00a36f;
            text-decoration: none;
        }

        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .pagination {
            margin: 0 auto;
        }

        .pagination span {
            font-size: 2em;
            margin-right: 10px;
        }

        .page-number {
            color: #d64161;
            padding: 5px;
            text-decoration: none;
        }

        .current-page-number {
            color: #666
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

احفظ وأغلق الملف.

هنا، تستخدم كتلة العنوان وتضيف بعض التنسيق بـ CSS. تضيف شريطًا تنقليًا يحتوي على عنصرين، أحد لصفحة الفهرس، والآخر لصفحة حول غير نشطة. سيتم إعادة استخدام هذا الشريط التنقل في جميع أنحاء التطبيق في القوالب التي ترث من هذا القالب الأساسي. سيتم استبدال كتلة المحتوى بمحتوى كل صفحة. لمزيد من المعلومات حول القوالب، تحقق من كيفية استخدام القوالب في تطبيق Flask.

بعد ذلك، افتح قالب index.html الجديد الذي قمت بتقديمه في app.py:

  1. nano templates/index.html

أضف الكود التالي إلى الملف:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1 class="title">{% block title %} Employees {% endblock %}</h1>
    <div class="content">
        {% for employee in employees %}
            <div class="employee">
                <p><b>#{{ employee.id }}</b></p>
                <b>
                    <p class="name">{{ employee.firstname }} {{ employee.lastname }}</p>
                </b>
                <p>{{ employee.email }}</p>
                <p>{{ employee.age }} years old.</p>
                <p>Hired: {{ employee.hire_date }}</p>
                {% if employee.active %}
                    <p><i>(Active)</i></p>
                {% else %}
                    <p><i>(Out of Office)</i></p>
                {% endif %}
            </div>
        {% endfor %}
    </div>
{% endblock %}

هنا، تكرر عبر الموظفين وتعرض معلومات كل موظف. إذا كان الموظف نشطًا، فستضيف علامة (نشط)، وإلا فستعرض علامة (خارج المكتب).

احفظ وأغلق الملف.

أثناء وجودك في دليل flask_app وتفعيل بيئتك الظاهرية، قم بإخبار Flask بالتطبيق (app.py في هذه الحالة) باستخدام متغير البيئة FLASK_APP. ثم قم بتعيين متغير البيئة FLASK_ENV إلى development لتشغيل التطبيق في وضع التطوير والحصول على الوصول إلى مصحح الأخطاء. لمزيد من المعلومات حول مصحح الأخطاء في Flask، انظر كيفية التعامل مع الأخطاء في تطبيق Flask. استخدم الأوامر التالية للقيام بذلك:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

بعد ذلك، قم بتشغيل التطبيق:

  1. flask run

بمجرد تشغيل خادم التطوير، افتح الرابط التالي باستخدام متصفحك:

http://127.0.0.1:5000/

سترى الموظفين الذين تمت إضافتهم إلى قاعدة البيانات في صفحة مماثلة للصفحة التالية:

اترك الخادم يعمل، افتح نافذة أوامر جديدة، وتابع إلى الخطوة التالية.

لقد عرضت الموظفين الذين لديك في قاعدة البيانات على الصفحة الرئيسية. في الخطوة التالية، ستستخدم محطة Flask للاستعلام عن الموظفين باستخدام طرق وشروط مختلفة.

الخطوة 2 — الاستعلام عن السجلات

في هذه الخطوة، ستستخدم محطة Flask للاستعلام عن السجلات، وتصفية النتائج واستردادها باستخدام طرق وشروط متعددة.

بعد تنشيط بيئة البرمجة الخاصة بك، قم بتعيين متغيرات FLASK_APP و FLASK_ENV، وافتح محطة Flask:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development
  3. flask shell

استيراد كائن db ونموذج Employee:

  1. from app import db, Employee

استرجاع جميع السجلات

كما رأيت في الخطوة السابقة، يمكنك استخدام الطريقة all() على السمة query للحصول على جميع السجلات في جدول:

  1. all_employees = Employee.query.all()
  2. print(all_employees)

سيكون الإخراج قائمة من الكائنات تمثل جميع الموظفين:

Output
[<Employee John Doe>, <Employee Mary Doe>, <Employee Jane Tanaka>, <Employee Alex Brown>, <Employee James White>, <Employee Harold Ishida>, <Employee Scarlett Winter>, <Employee Emily Vill>, <Employee Mary Park>]

استرجاع السجل الأول

بالمثل، يمكنك استخدام الطريقة first() للحصول على السجل الأول:

  1. first_employee = Employee.query.first()
  2. print(first_employee)

سيكون الإخراج كائن يحمل بيانات أول موظف:

Output
<Employee John Doe>

استرجاع سجل بواسطة معرف

في معظم جداول قواعد البيانات، يتم تحديد السجلات بمعرف فريد. Flask-SQLAlchemy يسمح لك بجلب سجل باستخدام معرفه باستخدام الطريقة get():

  1. employee5 = Employee.query.get(5)
  2. employee3 = Employee.query.get(3)
  3. print(f'{employee5} | ID: {employee5.id}')
  4. print(f'{employee3} | ID: {employee3.id}')
Output
<Employee James White> | ID: 5 <Employee Jane Tanaka> | ID: 3

استرجاع سجل أو سجلات متعددة بواسطة قيمة العمود

للحصول على سجل باستخدام قيمة أحد أعمدته، استخدم الطريقة filter_by(). على سبيل المثال، للحصول على سجل باستخدام قيمة الهوية الخاصة به، بشكل مشابه لطريقة get():

  1. employee = Employee.query.filter_by(id=1).first()
  2. print(employee)
Output
<Employee John Doe>

تستخدم first() لأن filter_by() قد تُرجع نتائج متعددة.

ملاحظة: للحصول على سجل بواسطة الهوية، استخدام الطريقة get() هو أفضل.

على سبيل المثال آخر، يمكنك الحصول على موظف باستخدام عمره:

  1. employee = Employee.query.filter_by(age=52).first()
  2. print(employee)
Output
<Employee Harold Ishida>

لمثال آخر حيث تحتوي نتيجة الاستعلام على أكثر من سجل مطابق، استخدم العمود firstname والاسم الأول Mary، الذي هو اسم مشترك بين موظفين:

  1. mary = Employee.query.filter_by(firstname='Mary').all()
  2. print(mary)
Output
[<Employee Mary Doe>, <Employee Mary Park>]

هنا، تستخدم all() للحصول على القائمة الكاملة. يمكنك أيضًا استخدام first() للحصول على النتيجة الأولى فقط:

  1. mary = Employee.query.filter_by(firstname='Mary').first()
  2. print(mary)
Output
<Employee Mary Doe>

لقد جلبت السجلات من خلال قيم الأعمدة. في الخطوة التالية، ستستعلم الجدول الخاص بك باستخدام شروط منطقية.

الخطوة 3 — تصفية السجلات باستخدام شروط منطقية

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

يساوي

أبسط مشغل منطقي يمكنك استخدامه هو مشغل المساواة ==، الذي يتصرف بطريقة مماثلة لـ filter_by(). على سبيل المثال، للحصول على جميع السجلات حيث يكون قيمة العمود firstname هي Mary، يمكنك استخدام طريقة filter() مثل هذا:

  1. mary = Employee.query.filter(Employee.firstname == 'Mary').all()
  2. print(mary)

هنا تستخدم بنية النموذج.العمود == القيمة كوسيطة لطريقة filter(). طريقة filter_by() هي اختصار لهذه الصيغة.

النتيجة هي نفس النتيجة التي تم الحصول عليها باستخدام طريقة filter_by() بنفس الشرط:

Output
[<Employee Mary Doe>, <Employee Mary Park>]

مثل filter_by()، يمكنك أيضًا استخدام طريقة first() للحصول على النتيجة الأولى:

  1. mary = Employee.query.filter(Employee.firstname == 'Mary').first()
  2. print(mary)
Output
<Employee Mary Doe>

لا تساوي

تسمح طريقة filter() لك باستخدام مشغل Python != للحصول على السجلات. على سبيل المثال، للحصول على قائمة بالموظفين الذين غير متواجدين في المكتب، يمكنك استخدام النهج التالي:

  1. out_of_office_employees = Employee.query.filter(Employee.active != True).all()
  2. print(out_of_office_employees)
Output
[<Employee Jane Tanaka>, <Employee Harold Ishida>]

هنا تستخدم شرط Employee.active != True لتصفية النتائج.

أقل من

يمكنك استخدام المشغل < للحصول على سجل حيث قيمة العمود المعطى أقل من القيمة المعطاة. على سبيل المثال، للحصول على قائمة بالموظفين دون سن 32:

  1. employees_under_32 = Employee.query.filter(Employee.age < 32).all()
  2. for employee in employees_under_32:
  3. print(employee.firstname, employee.lastname)
  4. print('Age: ', employee.age)
  5. print('----')
Output
Alex Brown Age: 29 ---- James White Age: 24 ---- Scarlett Winter Age: 22 ---- Emily Vill Age: 27 ---- Mary Park Age: 30 ----

استخدم المشغل <= للسجلات التي تكون أقل من أو تساوي القيمة المعطاة. على سبيل المثال، لتضمين الموظفين البالغين 32 سنة في الاستعلام السابق:

  1. employees_32_or_younger = Employee.query.filter(Employee.age <=32).all()
  2. for employee in employees_32_or_younger:
  3. print(employee.firstname, employee.lastname)
  4. print('Age: ', employee.age)
  5. print('----')
Output
John Doe Age: 32 ---- Jane Tanaka Age: 32 ---- Alex Brown Age: 29 ---- James White Age: 24 ---- Scarlett Winter Age: 22 ---- Emily Vill Age: 27 ---- Mary Park Age: 30 ----

أكثر من

بالمثل، يحصل المشغل > على سجل حيث قيمة العمود المعطى أكبر من القيمة المعطاة. على سبيل المثال، للحصول على الموظفين الذين تتجاوز أعمارهم 32 سنة:

  1. employees_over_32 = Employee.query.filter(Employee.age > 32).all()
  2. for employee in employees_over_32:
  3. print(employee.firstname, employee.lastname)
  4. print('Age: ', employee.age)
  5. print('----')
Output
Mary Doe Age: 38 ---- Harold Ishida Age: 52 ----

والمشغل >= مخصص للسجلات التي تكون أكبر من أو تساوي القيمة المعطاة. على سبيل المثال، يمكنك مرة أخرى تضمين الموظفين البالغين 32 سنة في الاستعلام السابق:

  1. employees_32_or_older = Employee.query.filter(Employee.age >=32).all()
  2. for employee in employees_32_or_older:
  3. print(employee.firstname, employee.lastname)
  4. print('Age: ', employee.age)
  5. print('----')
Output
John Doe Age: 32 ---- Mary Doe Age: 38 ---- Jane Tanaka Age: 32 ---- Harold Ishida Age: 52 ----

في

SQLAlchemy توفر أيضًا طريقة للحصول على السجلات التي يتطابق فيها قيمة العمود مع قيمة من قائمة معينة باستخدام الطريقة in_() على العمود مثل هذا:

  1. names = ['Mary', 'Alex', 'Emily']
  2. employees = Employee.query.filter(Employee.firstname.in_(names)).all()
  3. print(employees)
Output
[<Employee Mary Doe>, <Employee Alex Brown>, <Employee Emily Vill>, <Employee Mary Park>]

هنا، تستخدم شرطًا بالصيغة Model.column.in_(iterable)، حيث أن iterable يمكن أن يكون أي نوع من الكائنات التي يمكنك تكرارها. على سبيل المثال، يمكنك استخدام دالة range() في Python للحصول على الموظفين من نطاق عمر معين. الاستعلام التالي يحصل على جميع الموظفين الذين في عقدهم الثالث.

  1. employees_in_30s = Employee.query.filter(Employee.age.in_(range(30, 40))).all()
  2. for employee in employees_in_30s:
  3. print(employee.firstname, employee.lastname)
  4. print('Age: ', employee.age)
  5. print('----')
Output
John Doe Age: 32 ---- Mary Doe Age: 38 ---- Jane Tanaka Age: 32 ---- Mary Park Age: 30 ----

Not In

بشكل مماثل لطريقة in_()، يمكنك استخدام الطريقة not_in() للحصول على السجلات التي لا تكون قيمة العمود فيها ضمن مجموعة معينة:

  1. names = ['Mary', 'Alex', 'Emily']
  2. employees = Employee.query.filter(Employee.firstname.not_in(names)).all()
  3. print(employees)
Output
[<Employee John Doe>, <Employee Jane Tanaka>, <Employee James White>, <Employee Harold Ishida>, <Employee Scarlett Winter>]

هنا، تحصل على جميع الموظفين ما عدا تلك التي لها اسم أول في القائمة names.

And

يمكنك دمج عدة شروط معًا باستخدام دالة db.and_()، التي تعمل مثل عامل and في Python.

على سبيل المثال، لنفترض أنك ترغب في الحصول على جميع الموظفين البالغين من العمر 32 عامًا والذين يعملون حاليًا. أولاً، يمكنك التحقق ممن هم في السن 32 باستخدام طريقة filter_by() (يمكنك أيضًا استخدام filter() إذا كنت ترغب):

  1. for employee in Employee.query.filter_by(age=32).all():
  2. print(employee)
  3. print('Age:', employee.age)
  4. print('Active:', employee.active)
  5. print('-----')
Output
<Employee John Doe> Age: 32 Active: True ----- <Employee Jane Tanaka> Age: 32 Active: False -----

هنا، ترى أن جون وجين هم الموظفين البالغين من العمر 32 عامًا. جون نشط، وجين خارج المكتب.

للحصول على الموظفين البالغين من العمر 32 و نشطين، ستستخدم شرطين مع طريقة filter():

  • Employee.age == 32
  • Employee.active == True

لدمج هاتين الشروطين معًا، استخدم وظيفة db.and_() كالتالي:

  1. active_and_32 = Employee.query.filter(db.and_(Employee.age == 32,
  2. Employee.active == True)).all()
  3. print(active_and_32)
Output
[<Employee John Doe>]

هنا، تستخدم الصيغة filter(db.and_(condition1, condition2)).

باستخدام all() على الاستعلام، سيتم إرجاع قائمة بجميع السجلات التي تطابق الشرطين. يمكنك استخدام طريقة first() للحصول على النتيجة الأولى:

  1. active_and_32 = Employee.query.filter(db.and_(Employee.age == 32,
  2. Employee.active == True)).first()
  3. print(active_and_32)
Output
<Employee John Doe>

لمثال أكثر تعقيدًا، يمكنك استخدام db.and_() مع وظيفة date() للحصول على الموظفين الذين تم توظيفهم في نطاق زمني محدد. في هذا المثال، تحصل على جميع الموظفين الذين تم توظيفهم في عام 2019:

  1. from datetime import date
  2. hired_in_2019 = Employee.query.filter(db.and_(Employee.hire_date >= date(year=2019, month=1, day=1), Employee.hire_date < date(year=2020, month=1, day=1))).all()
  3. for employee in hired_in_2019:
  4. print(employee, ' | Hired: ', employee.hire_date)
Output
<Employee Alex Brown> | Hired: 2019-01-03 <Employee Emily Vill> | Hired: 2019-06-09

هنا تقوم بإستيراد وظيفة date()، وتصفي النتائج باستخدام وظيفة db.and_() لدمج الشرطين التاليين:

  • Employee.hire_date >= date(year=2019, month=1, day=1): هذا يكون True للموظفين الذين تم توظيفهم في الأول من يناير 2019 أو بعد ذلك.
  • Employee.hire_date < date(year=2020, month=1, day=1): هذا صحيح للموظفين الذين تم توظيفهم قبل الأول من يناير 2020.

من خلال جمع الشرطين يتم الحصول على الموظفين الذين تم توظيفهم من اليوم الأول من عام 2019 وقبل اليوم الأول من عام 2020.

أو

بشكل مشابه لـ db.and_()، تقوم وظيفة db.or_() بجمع شرطين، وتتصرف مثل مشغل or في Python. فهي تحصل على جميع السجلات التي تستوفي أحد الشروطين. على سبيل المثال، للحصول على الموظفين الذين تبلغ أعمارهم 32 أو 52، يمكنك جمع شرطين باستخدام وظيفة db.or_() على النحو التالي:

  1. employees_32_or_52 = Employee.query.filter(db.or_(Employee.age == 32, Employee.age == 52)).all()
  2. for e in employees_32_or_52:
  3. print(e, '| Age:', e.age)
Output
<Employee John Doe> | Age: 32 <Employee Jane Tanaka> | Age: 32 <Employee Harold Ishida> | Age: 52

يمكنك أيضًا استخدام الأساليب startswith() و endswith() على قيم السلسلة في الشروط التي تمررها إلى الطريقة filter(). على سبيل المثال، للحصول على جميع الموظفين الذين يبدأ اسمهم بالسلسلة 'M' والذين ينتهي اسمهم بالسلسلة 'e':

  1. employees = Employee.query.filter(db.or_(Employee.firstname.startswith('M'), Employee.lastname.endswith('e'))).all()
  2. for e in employees:
  3. print(e)
Output
<Employee John Doe> <Employee Mary Doe> <Employee James White> <Employee Mary Park>

هنا يتم دمج الشرطين التاليين:

  • Employee.firstname.startswith('M'): يطابق الموظفين الذين لديهم اسم يبدأ بـ 'M'.
  • Employee.lastname.endswith('e'): يطابق الموظفين الذين لديهم اسم ينتهي بـ 'e'.

يمكنك الآن تصفية نتائج الاستعلام باستخدام الشروط المنطقية في تطبيقات Flask-SQLAlchemy الخاصة بك. فيما يلي، ستقوم بترتيب وتحديد النتائج وعد عددها من قاعدة البيانات.

الخطوة ٤ — ترتيب، تحديد الحدود، وعد النتائج

في تطبيقات الويب، غالبًا ما تحتاج إلى ترتيب السجلات الخاصة بك عند عرضها. على سبيل المثال، قد تكون لديك صفحة لعرض أحدث التوظيفات في كل قسم لإعلام بقية الفريق عن التوظيفات الجديدة، أو يمكنك ترتيب الموظفين عن طريق عرض أقدم التوظيفات أولاً للاعتراف بالموظفين ذوي فترة خدمة طويلة. كما ستحتاج أيضًا إلى تحديد حدود النتائج في حالات معينة، مثل عرض آخر ثلاث توظيفات فقط على شريط جانبي صغير. وغالبًا ما تحتاج أيضًا إلى عد النتائج لاستعراض عدد الموظفين النشطين حاليًا. في هذه الخطوة، ستتعلم كيفية ترتيب وتحديد الحدود وعد النتائج.

ترتيب النتائج

لترتيب النتائج باستخدام قيمة عمود معين، استخدم الطريقة order_by(). على سبيل المثال، لترتيب النتائج حسب اسم الموظف الأول:

  1. employees = Employee.query.order_by(Employee.firstname).all()
  2. print(employees)
Output
[<Employee Alex Brown>, <Employee Emily Vill>, <Employee Harold Ishida>, <Employee James White>, <Employee Jane Tanaka>, <Employee John Doe>, <Employee Mary Doe>, <Employee Mary Park>, <Employee Scarlett Winter>]

كما يظهر الإخراج، تم ترتيب النتائج ترتيبًا أبجديًا حسب اسم الموظف الأول.

يمكنك أيضًا الترتيب حسب أعمدة أخرى. على سبيل المثال، يمكنك استخدام اسم العائلة لترتيب الموظفين:

  1. employees = Employee.query.order_by(Employee.lastname).all()
  2. print(employees)
Output
[<Employee Alex Brown>, <Employee John Doe>, <Employee Mary Doe>, <Employee Harold Ishida>, <Employee Mary Park>, <Employee Jane Tanaka>, <Employee Emily Vill>, <Employee James White>, <Employee Scarlett Winter>]

يمكنك أيضًا ترتيب الموظفين حسب تاريخ توظيفهم:

  1. em_ordered_by_hire_date = Employee.query.order_by(Employee.hire_date).all()
  2. for employee in em_ordered_by_hire_date:
  3. print(employee.firstname, employee.lastname, employee.hire_date)
Output
Harold Ishida 2002-03-06 John Doe 2012-03-03 Jane Tanaka 2015-09-12 Mary Doe 2016-06-07 Alex Brown 2019-01-03 Emily Vill 2019-06-09 James White 2021-02-04 Scarlett Winter 2021-04-07 Mary Park 2021-08-11

كما يوضح الناتج، يُرتب النتائج من أقدم توظيف إلى أحدث توظيف. لعكس الترتيب وجعله تنازلياً من آخر توظيف إلى أول توظيف، استخدم الطريقة desc() كما يلي:

  1. em_ordered_by_hire_date_desc = Employee.query.order_by(Employee.hire_date.desc()).all()
  2. for employee in em_ordered_by_hire_date_desc:
  3. print(employee.firstname, employee.lastname, employee.hire_date)
Output
Mary Park 2021-08-11 Scarlett Winter 2021-04-07 James White 2021-02-04 Emily Vill 2019-06-09 Alex Brown 2019-01-03 Mary Doe 2016-06-07 Jane Tanaka 2015-09-12 John Doe 2012-03-03 Harold Ishida 2002-03-06

يمكنك أيضًا دمج الطريقة order_by() مع الطريقة filter() لترتيب النتائج المُنقاة. يُظهر المثال التالي جميع الموظفين الذين تم توظيفهم في عام 2021 ويُرتبهم حسب العمر:

  1. from datetime import date
  2. hired_in_2021 = Employee.query.filter(db.and_(Employee.hire_date >= date(year=2021, month=1, day=1), Employee.hire_date < date(year=2022, month=1, day=1))).order_by(Employee.age).all()
  3. for employee in hired_in_2021:
  4. print(employee.firstname, employee.lastname,
  5. employee.hire_date, '| Age', employee.age)
Output
Scarlett Winter 2021-04-07 | Age 22 James White 2021-02-04 | Age 24 Mary Park 2021-08-11 | Age 30

هنا، يُستخدم الدالة db.and_() مع شرطين: Employee.hire_date >= date(year=2021, month=1, day=1) للموظفين الذين تم توظيفهم في اليوم الأول من عام 2021 أو لاحقًا، و Employee.hire_date < date(year=2022, month=1, day=1) للموظفين الذين تم توظيفهم قبل اليوم الأول من عام 2022. بعد ذلك، يتم استخدام الطريقة order_by() لترتيب الموظفين الناتجين حسب أعمارهم.

تقييد النتائج

في معظم الحالات الواقعية، عند استعلام جدول قاعدة البيانات، قد تحصل على ملايين النتائج المُطابقة، ومن الضروري في بعض الأحيان تقييد النتائج إلى عدد معين. لتقييد النتائج في Flask-SQLAlchemy، يمكنك استخدام الطريقة limit(). يقوم المثال التالي باستعلام جدول employee ويعيد فقط أول ثلاث نتائج مُطابقة:

  1. employees = Employee.query.limit(3).all()
  2. print(employees)
Output
[<Employee John Doe>, <Employee Mary Doe>, <Employee Jane Tanaka>]

يمكنك استخدام limit() مع طرق أخرى، مثل filter و order_by. على سبيل المثال، يمكنك الحصول على آخر موظفين اثنين تم توظيفهم في عام 2021 باستخدام الطريقة limit() على النحو التالي:

  1. from datetime import date
  2. hired_in_2021 = Employee.query.filter(db.and_(Employee.hire_date >= date(year=2021, month=1, day=1), Employee.hire_date < date(year=2022, month=1, day=1))).order_by(Employee.age).limit(2).all()
  3. for employee in hired_in_2021:
  4. print(employee.firstname, employee.lastname,
  5. employee.hire_date, '| Age', employee.age)
Output
Scarlett Winter 2021-04-07 | Age 22 James White 2021-02-04 | Age 24

هنا، تستخدم نفس الاستعلام في القسم السابق مع استدعاء طريقة limit(2) إضافية.

عد النتائج

لحساب عدد نتائج الاستعلام، يمكنك استخدام الطريقة count(). على سبيل المثال، للحصول على عدد الموظفين الموجودين حاليًا في قاعدة البيانات:

  1. employee_count = Employee.query.count()
  2. print(employee_count)
Output
9

يمكنك دمج طريقة count() مع طرق الاستعلام الأخرى مشابهة لـ limit(). على سبيل المثال، للحصول على عدد الموظفين الذين تم توظيفهم في عام 2021:

  1. from datetime import date
  2. hired_in_2021_count = Employee.query.filter(db.and_(Employee.hire_date >= date(year=2021, month=1, day=1), Employee.hire_date < date(year=2022, month=1, day=1))).order_by(Employee.age).count()
  3. print(hired_in_2021_count)
Output
3

هنا تستخدم نفس الاستعلام الذي استخدمته سابقًا للحصول على جميع الموظفين الذين تم توظيفهم في عام 2021. وتستخدم الطريقة count() لاسترجاع عدد الإدخالات، والذي هو 3.

لقد قمت بترتيب وتقييد وعد النتائج للاستعلامات في Flask-SQLAlchemy. فيما يلي، ستتعلم كيفية تقسيم نتائج الاستعلام إلى عدة صفحات وكيفية إنشاء نظام ترقيم الصفحات في تطبيقات Flask الخاصة بك.

الخطوة 5 — عرض قوائم التسجيل الطويلة على عدة صفحات

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

أولاً، ستستخدم واجهة Flask لرؤية عرض لكيفية استخدام ميزة الترقيم في Flask-SQLAlchemy. افتح واجهة Flask إذا لم تفعل بالفعل:

  1. flask shell

لنفترض أنك تريد تقسيم سجلات الموظفين في جدولك إلى صفحات متعددة، مع عنصرين في كل صفحة. يمكنك القيام بذلك باستخدام طريقة الاستعلام paginate() كما يلي:

  1. page1 = Employee.query.paginate(page=1, per_page=2)
  2. print(page1)
  3. print(page1.items)
Output
<flask_sqlalchemy.Pagination object at 0x7f1dbee7af80> [<Employee John Doe>, <Employee Mary Doe>]

تستخدم معلمة page لطريقة الاستعلام paginate() لتحديد الصفحة التي تريد الوصول إليها، والتي هي الصفحة الأولى في هذه الحالة. تحدد معلمة per_page عدد العناصر التي يجب أن تحتوي عليها كل صفحة. في هذه الحالة، يتم تعيينها إلى 2 لجعل كل صفحة تحتوي على عنصرين.

المتغير page1 هنا هو كائن الترقيم، الذي يمنحك الوصول إلى السمات والأساليب التي ستستخدمها لإدارة الترقيم.

يمكنك الوصول إلى عناصر الصفحة باستخدام السمة items.

للوصول إلى الصفحة التالية، يمكنك استخدام الطريقة next() لكائن الترقيم كما يلي، النتيجة المُرجعة أيضًا كائن ترقيم:

  1. page2 = page1.next()
  2. print(page2.items)
  3. print(page2)
Output
[<Employee Jane Tanaka>, <Employee Alex Brown>] <flask_sqlalchemy.Pagination object at 0x7f1dbee799c0>

يمكنك الحصول على كائن ترقيم للصفحة السابقة باستخدام الطريقة prev(). في المثال التالي، تصل إلى كائن الترقيم للصفحة الرابعة، ثم تصل إلى كائن الترقيم لصفحتها السابقة، التي هي الصفحة 3:

  1. page4 = Employee.query.paginate(page=4, per_page=2)
  2. print(page4.items)
  3. page3 = page4.prev()
  4. print(page3.items)
Output
[<Employee Scarlett Winter>, <Employee Emily Vill>] [<Employee James White>, <Employee Harold Ishida>]

يمكنك الوصول إلى رقم الصفحة الحالية باستخدام السمة page كما يلي:

  1. print(page1.page)
  2. print(page2.page)
Output
1 2

للحصول على إجمالي عدد الصفحات، استخدم سمة pages لكائن الترقيم. في المثال التالي، كلاً من page1.pages و page2.pages يعيدان نفس القيمة لأن إجمالي عدد الصفحات هو ثابت:

  1. print(page1.pages)
  2. print(page2.pages)
Output
5 5

بالنسبة إلى العدد الإجمالي للعناصر، استخدم سمة total لكائن الترقيم:

  1. print(page1.total)
  2. print(page2.total)
Output
9 9

هنا، نظرًا لأنك تستعلم عن جميع الموظفين، فإن العدد الإجمالي للعناصر في الترقيم هو 9، لأن هناك تسعة موظفين في قاعدة البيانات.

فيما يلي بعض السمات الأخرى التي تحتوي عليها كائنات الترقيم:

  • prev_num: رقم الصفحة السابقة.
  • next_num: رقم الصفحة التالية.
  • has_next: True إذا كان هناك صفحة تالية.
  • has_prev: True إذا كانت هناك صفحة سابقة.
  • per_page: عدد العناصر في كل صفحة.

كما أن لدى كائن الترقيم طريقة iter_pages() يمكنك الاستمرار في الحلق عبرها للوصول إلى أرقام الصفحات. على سبيل المثال، يمكنك طباعة جميع أرقام الصفحات كما يلي:

  1. pagination = Employee.query.paginate(page=1, per_page=2)
  2. for page_num in pagination.iter_pages():
  3. print(page_num)
Output
1 2 3 4 5

التالي هو عرض لكيفية الوصول إلى جميع الصفحات وعناصرها باستخدام كائن الترقيم وطريقة iter_pages():

  1. pagination = Employee.query.paginate(page=1, per_page=2)
  2. for page_num in pagination.iter_pages():
  3. print('PAGE', pagination.page)
  4. print('-')
  5. print(pagination.items)
  6. print('-'*20)
  7. pagination = pagination.next()
Output
PAGE 1 - [<Employee John Doe>, <Employee Mary Doe>] -------------------- PAGE 2 - [<Employee Jane Tanaka>, <Employee Alex Brown>] -------------------- PAGE 3 - [<Employee James White>, <Employee Harold Ishida>] -------------------- PAGE 4 - [<Employee Scarlett Winter>, <Employee Emily Vill>] -------------------- PAGE 5 - [<Employee Mary Park>] --------------------

هنا، تنشئ كائن ترقيم يبدأ من الصفحة الأولى. تحلق عبر الصفحات باستخدام حلقة for مع طريقة ترقيم iter_pages(). تطبع رقم الصفحة وعناصر الصفحة، وتعيد تعيين كائن pagination إلى كائن الترقيم للصفحة التالية باستخدام الطريقة next().

يمكنك أيضًا استخدام الطرق filter() و order_by() مع الطريقة paginate() لتقسيم نتائج الاستعلام المُصفَّاة والمُرتبة. على سبيل المثال، يمكنك الحصول على الموظفين الذين تزيد أعمارهم عن ثلاثين عامًا وترتيب النتائج حسب العمر وتقسيم النتائج كالتالي:

  1. pagination = Employee.query.filter(Employee.age > 30).order_by(Employee.age).paginate(page=1, per_page=2)
  2. for page_num in pagination.iter_pages():
  3. print('PAGE', pagination.page)
  4. print('-')
  5. for employee in pagination.items:
  6. print(employee, '| Age: ', employee.age)
  7. print('-'*20)
  8. pagination = pagination.next()
Output
PAGE 1 - <Employee John Doe> | Age: 32 <Employee Jane Tanaka> | Age: 32 -------------------- PAGE 2 - <Employee Mary Doe> | Age: 38 <Employee Harold Ishida> | Age: 52 --------------------

الآن بعد أن لديك فهمًا قويًا لكيفية عمل التقسيم في Flask-SQLAlchemy، ستقوم بتحرير صفحة الفهرس في تطبيقك لعرض الموظفين على صفحات متعددة لسهولة التنقل.

انس الطرفية الخاصة بـ Flask:

  1. exit()

للوصول إلى صفحات مختلفة، ستستخدم معلمات عنوان URL، المعروفة أيضًا باسم سلاسل الاستعلام لعنوان URL، وهي طريقة لتمرير المعلومات إلى التطبيق عبر عنوان URL. يتم تمرير المعلمات إلى التطبيق في عنوان URL بعد رمز ؟. على سبيل المثال، لتمرير معلمة page بقيم مختلفة، يمكنك استخدام عناوين URL التالية:

http://127.0.0.1:5000/?page=1
http://127.0.0.1:5000/?page=3

هنا، تمرر العنوان الأول قيمة 1 إلى معلمة عنوان URL page. يمرر العنوان الثاني قيمة 3 إلى نفس المعلمة.

افتح ملف app.py:

  1. nano app.py

عدّل مسار الفهرس ليبدو كما يلي:

@app.route('/')
def index():
    page = request.args.get('page', 1, type=int)
    pagination = Employee.query.order_by(Employee.firstname).paginate(
        page, per_page=2)
    return render_template('index.html', pagination=pagination)

هنا، تحصل على قيمة معلمة عنوان URL page باستخدام كائن request.args وطريقته get(). على سبيل المثال /?page=1 سيحصل على القيمة 1 من معلمة عنوان URL page. تمرر 1 كقيمة افتراضية، وتمرر نوع بيثون int كوسيطة للمعلمة type للتأكد من أن القيمة هي عدد صحيح.

ثم تقوم بإنشاء كائن pagination، مرتباً نتائج الاستعلام حسب الاسم الأول. تمرر قيمة معلمة عنوان page إلى طريقة paginate()، وتقسم النتائج إلى عنصرين لكل صفحة عن طريق تمرير القيمة 2 إلى المعلمة per_page.

وأخيرًا، تمرر الكائن pagination الذي قمت بإنشائه إلى قالب index.html المرتجع.

احفظ الملف وأغلقه.

ثم، قم بتعديل قالب index.html لعرض عناصر الترقيم:

  1. nano templates/index.html

قم بتغيير علامة الفقرة div بإضافة عنوان h2 يشير إلى الصفحة الحالية، وقم بتغيير حلقة for لتكرار كائن pagination.items بدلاً من كائن employees الذي لم يعد متاحًا:

<div class="content">
    <h2>(Page {{ pagination.page }})</h2>
    {% for employee in pagination.items %}
        <div class="employee">
            <p><b>#{{ employee.id }}</b></p>
            <b>
                <p class="name">{{ employee.firstname }} {{ employee.lastname }}</p>
            </b>
            <p>{{ employee.email }}</p>
            <p>{{ employee.age }} years old.</p>
            <p>Hired: {{ employee.hire_date }}</p>
            {% if employee.active %}
                <p><i>(Active)</i></p>
            {% else %}
                <p><i>(Out of Office)</i></p>
            {% endif %}
        </div>
    {% endfor %}
</div>

احفظ الملف وأغلقه.

إذا لم تقم بذلك بالفعل، قم بتعيين متغيرات البيئة FLASK_APP و FLASK_ENV وتشغيل خادم التطوير:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development
  3. flask run

الآن، انتقل إلى صفحة الفهرس بقيم مختلفة لمعلمة عنوان page:

http://127.0.0.1:5000/
http://127.0.0.1:5000/?page=2
http://127.0.0.1:5000/?page=4
http://127.0.0.1:5000/?page=19

سترى صفحات مختلفة تحتوي على عنصرين لكل منها، وعناصر مختلفة على كل صفحة، كما رأيت سابقاً في محطة Flask.

إذا كان رقم الصفحة المعطى غير موجود، ستحصل على خطأ HTTP 404 Not Found، وهذا هو الحال مع آخر عنوان URL في القائمة السابقة.

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

سيبدو عنصر واجهة مستخدم الترقيم كالتالي:


لإضافته، قم بفتح ملف index.html:

  1. nano templates/index.html

قم بتعديل الملف عن طريق إضافة العنصر div المظلل أدناه إلى داخل عنصر الـ div الخاص بالمحتوى:

flask_app/templates/index.html
<div class="content">
    {% for employee in pagination.items %}
        <div class="employee">
            <p><b>#{{ employee.id }}</b></p>
            <b>
                <p class="name">{{ employee.firstname }} {{ employee.lastname }}</p>
            </b>
            <p>{{ employee.email }}</p>
            <p>{{ employee.age }} years old.</p>
            <p>Hired: {{ employee.hire_date }}</p>
            {% if employee.active %}
                <p><i>(Active)</i></p>
            {% else %}
                <p><i>(Out of Office)</i></p>
            {% endif %}
        </div>
    {% endfor %}
</div>

<div class="pagination">
    {% if pagination.has_prev %}
        <span>
            <a class='page-number' href="{{ url_for('index', page=pagination.prev_num) }}">
                {{ '<<<' }}
            </a>
        </span>
    {% endif %}

    {% for number in pagination.iter_pages() %}
        {% if pagination.page != number %}
            <span>
                    <a class='page-number'
                        href="{{ url_for('index', page=number) }}">
                    {{ number }}
                    </a>
            </span>
        {% else %}
            <span class='current-page-number'>{{ number }}</span>
        {% endif %}
    {% endfor %}

    {% if pagination.has_next %}
        <span>
            <a class='page-number'
                href="{{ url_for('index', page=pagination.next_num) }}">
                {{ '>>>' }}
            </a>
        </span>
    {% endif %}
</div>

احفظ وأغلق الملف.

هنا، ستستخدم الشرط if pagination.has_prev لإضافة رابط <<< للصفحة السابقة إذا لم تكن الصفحة الحالية هي الصفحة الأولى. ستقوم بربطه بالصفحة السابقة باستخدام استدعاء الدالة url_for('index', page=pagination.prev_num)، حيث ستربط بدالة عرض الفهرس، وستمرر قيمة pagination.prev_num كمعلمة URL page.

لعرض روابط إلى جميع أرقام الصفحات المتاحة، ستقوم بتكرار عناصر الطريقة pagination.iter_pages() التي تعيد لك رقم صفحة في كل دورة.

تستخدم شرط if pagination.page != number لمعرفة ما إذا كان رقم الصفحة الحالية ليس نفس الرقم في الحلقة الحالية. إذا كان الشرط صحيحًا، فستقوم بربط الصفحة للسماح للمستخدم بتغيير الصفحة الحالية إلى صفحة أخرى. وإذا كانت الصفحة الحالية هي نفس رقم الحلقة، فستعرض الرقم بدون رابط. هذا يتيح للمستخدمين معرفة رقم الصفحة الحالية في عنصر واجهة التصفح.

أخيرًا، تستخدم شرط pagination.has_next لمعرفة ما إذا كانت الصفحة الحالية تحتوي على صفحة للأمام، في هذه الحالة ستقوم بربطها باستخدام استدعاء url_for('index', page=pagination.next_num) ورابط >>>.

انتقل إلى صفحة الفهرس في متصفحك: http://127.0.0.1:5000/

سترى عنصر واجهة التصفح يعمل بشكل كامل:


هنا، تستخدم >>> للانتقال إلى الصفحة التالية و <<< للصفحة السابقة، لكن يمكنك أيضًا استخدام أي رموز أخرى تفضلها، مثل > و < أو صور في علامات <img>.

لقد قمت بعرض الموظفين على عدة صفحات وتعلمت كيفية التعامل مع الترقيم في Flask-SQLAlchemy. ويمكنك الآن استخدام عنصر واجهة التصفح هذا في تطبيقات Flask الأخرى التي تقوم ببنائها.

الاستنتاج

استخدمت Flask-SQLAlchemy لإنشاء نظام إدارة الموظفين. قمت باستعلام جدول وفرز النتائج استنادًا إلى قيم الأعمدة والشروط المنطقية البسيطة والمعقدة. وقمت بترتيب وعد وتقييد نتائج الاستعلام. وقمت بإنشاء نظام ترقيم الصفحات لعرض عدد معين من السجلات في كل صفحة في تطبيق الويب الخاص بك، والتنقل بين الصفحات.

يمكنك استخدام ما تعلمته في هذا البرنامج التعليمي بالاقتران مع المفاهيم المشروحة في بعض برامج البرمجة النصية الأخرى لـ Flask-SQLAlchemy لإضافة المزيد من الوظائف إلى نظام إدارة الموظفين الخاص بك:

إذا كنت ترغب في قراءة المزيد حول Flask، فقم بالتحقق من البرامج التعليمية الأخرى في سلسلة كيفية بناء تطبيقات الويب باستخدام Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-query-tables-and-paginate-data-in-flask-sqlalchemy