
مرحباً بك في الدرس الخامس عشر من سلسلة تعلم بايثون وبناء API عملي. في الدروس السابقة، تعلمنا كيفية إنشاء endpoints بسيطة باستخدام FastAPI، وكيفية التعامل مع path parameters و query parameters، وأخيراً كيفية تعريف نماذج البيانات باستخدام Pydantic. الآن حان الوقت لتطبيق كل هذه المفاهيم معاً لبناء أول عملية CRUD كاملة.
CRUD هو اختصار لأربع عمليات أساسية في أي تطبيق يدير بيانات:
بدون CRUD، سيكون تطبيقك مجرد شاشة عرض ثابتة. هذه العمليات هي قلب أي API ديناميكي، سواء كان موقعاً للتجارة الإلكترونية، أو تطبيقاً لإدارة المهام، أو نظاماً لإدارة المحتوى.
سنقوم ببناء API صغير يدير قائمة مهام (To-Do List). سنستخدم قائمة بايثون عادية لتخزين البيانات مؤقتاً (في الدرس القادم سننتقل إلى قاعدة بيانات). هيا بنا نبدأ.
افتح مجلد مشروعك وأنشئ ملفاً جديداً باسم main.py. هذا الملف سيحتوي على كل الكود الخاص بنا.
سنبدأ باستيراد FastAPI وإنشاء التطبيق، ثم تعريف نموذج Pydantic للمهمة، وأخيراً إنشاء قائمة فارغة لتخزين المهام.
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# نموذج Pydantic للمهمة
class Task(BaseModel):
id: int
title: str
description: Optional[str] = None
completed: bool = False
# قاعدة بيانات مؤقتة (قائمة)
tasks_db = []
سنستخدم طلب POST لإضافة مهمة جديدة. سنقوم بإنشاء endpoint على المسار /tasks.
@app.post("/tasks")
def create_task(task: Task):
# نضيف المهمة إلى القاعدة المؤقتة
tasks_db.append(task)
return {"message": "Task created successfully", "task": task}
شرح الكود: عندما يرسل المستخدم طلب POST مع بيانات مهمة (JSON)، يقوم FastAPI بتحويلها تلقائياً إلى كائن من نوع Task بفضل Pydantic. ثم نضيف هذا الكائن إلى قائمتنا tasks_db ونعيد رسالة نجاح.
سنحتاج إلى endpoint لعرض جميع المهام، وآخر لعرض مهمة واحدة باستخدام id.
# قراءة جميع المهام
@app.get("/tasks")
def get_all_tasks():
return tasks_db
# قراءة مهمة واحدة بواسطة id
@app.get("/tasks/{task_id}")
def get_task(task_id: int):
for task in tasks_db:
if task.id == task_id:
return task
return {"error": "Task not found"}
شرح الكود: get_all_tasks يعيد القائمة كاملة. get_task يستخدم path parameter (task_id) ويبحث في القائمة عن مهمة تطابق هذا الرقم. إذا لم يجد، يعيد رسالة خطأ.
لتحديث مهمة، سنستخدم طلب PUT. سنحتاج إلى معرفة id المهمة التي نريد تحديثها، والبيانات الجديدة.
@app.put("/tasks/{task_id}")
def update_task(task_id: int, updated_task: Task):
for index, task in enumerate(tasks_db):
if task.id == task_id:
tasks_db[index] = updated_task
return {"message": "Task updated", "task": updated_task}
return {"error": "Task not found"}
شرح الكود: نستخدم enumerate للحصول على فهرس كل مهمة. عندما نجد المهمة المطلوبة، نستبدل العنصر في القائمة بالبيانات الجديدة.
للحذف، سنستخدم طلب DELETE.
@app.delete("/tasks/{task_id}")
def delete_task(task_id: int):
for index, task in enumerate(tasks_db):
if task.id == task_id:
del tasks_db[index]
return {"message": "Task deleted"}
return {"error": "Task not found"}
شرح الكود: مشابه للتحديث، لكننا نستخدم del لحذف العنصر من القائمة.
الآن، إليك الكود الكامل الذي يجب أن يكون في ملف main.py:
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Task(BaseModel):
id: int
title: str
description: Optional[str] = None
completed: bool = False
tasks_db = []
@app.post("/tasks")
def create_task(task: Task):
tasks_db.append(task)
return {"message": "Task created successfully", "task": task}
@app.get("/tasks")
def get_all_tasks():
return tasks_db
@app.get("/tasks/{task_id}")
def get_task(task_id: int):
for task in tasks_db:
if task.id == task_id:
return task
return {"error": "Task not found"}
@app.put("/tasks/{task_id}")
def update_task(task_id: int, updated_task: Task):
for index, task in enumerate(tasks_db):
if task.id == task_id:
tasks_db[index] = updated_task
return {"message": "Task updated", "task": updated_task}
return {"error": "Task not found"}
@app.delete("/tasks/{task_id}")
def delete_task(task_id: int):
for index, task in enumerate(tasks_db):
if task.id == task_id:
del tasks_db[index]
return {"message": "Task deleted"}
return {"error": "Task not found"}
لتشغيل التطبيق، استخدم الأمر التالي في terminal:
uvicorn main:app --reload
ثم افتح المتصفح على http://127.0.0.1:8000/docs لتجربة جميع العمليات عبر واجهة Swagger الجميلة.
{"id": 1, "title": "تعلم FastAPI", "description": "إكمال الدروس", "completed": false}
ثم استخدم GET لرؤية المهمة. بعد ذلك، جرب تحديثها أو حذفها.
id فريد. إذا أرسلت مهمتين بنفس id، فسيتم تخزينهما معاً. هذا شيء سنعالجه في الدروس القادمة عند استخدام قاعدة بيانات.title فقط)، فستفقد الحقول الأخرى. هذا يُسمى "PUT كامل". سنتعلم لاحقاً كيفية عمل تحديث جزئي (PATCH).الآن حان دورك لتطبيق ما تعلمته. قم بالتالي:
Task باسم priority من نوع int (قيمته الافتراضية 1).create_task لتتحقق من أن id المهمة الجديدة ليس مكرراً. إذا كان مكرراً، أعد رسالة خطأ مناسبة.هذا التمرين سيساعدك على فهم كيفية تعديل النماذج وإضافة منطق بسيط للتحقق من البيانات. في الدرس القادم، سنتعلم كيفية تنظيم هذا المشروع بشكل أفضل.
جاري تحميل التقييمات...