ترجمة آلية تحت المراجعة
أعياد الميلاد
المصدر الأصليقائمة تنفيذ التمرين
تُحفظ علامات هذه القائمة على هذا الجهاز والمتصفح فقط. أنشئ حسابًا مفعّلًا لحفظ إنجاز التمرين في مسارك.
أعياد الميلاد

مشكلة بحاجة إلى حل
قم بإنشاء تطبيق ويب لتتبع أعياد ميلاد الأصدقاء.
البدء
قم بتنزيل كود التوزيع
مفتوح cs50.dev.
ابدأ بالنقر داخل النافذة الطرفية، ثم قم بالتنفيذ cd بمفرده. يجب أن تجد أن "المطالبة" الخاصة بها تشبه ما يلي.
$
انقر داخل تلك النافذة الطرفية ثم قم بالتنفيذ
wget https://cdn.cs50.net/2026/x/psets/9/birthdays.zip
متبوعًا بـ Enter لتنزيل ملف مضغوط يسمى birthdays.zip في مساحة الشيفرة الخاصة بك. احرص على عدم إغفال المسافة بينهما wget وعنوان URL التالي، أو أي حرف آخر في هذا الشأن!
نفذ الآن
unzip birthdays.zip
لإنشاء مجلد يسمى birthdays. لم تعد بحاجة إلى ملف ZIP، حتى تتمكن من التنفيذ
rm birthdays.zip
ثم قم بالرد بـ "y" متبوعًا بـ Enter عند المطالبة لإزالة ملف ZIP الذي قمت بتنزيله.
الآن اكتب
cd birthdays
متبوعًا بـ Enter للانتقال إلى (i.e.، open) هذا الدليل. يجب أن تشبه مطالبتك الآن ما يلي.
birthdays/ $
إذا كان كل شيء ناجحًا، فيجب عليك التنفيذ
ls
ومن المفترض أن تشاهد الملفات والمجلدات التالية:
app.py birthdays.db static/ templates/
إذا واجهت أي مشكلة، فاتبع نفس الخطوات مرة أخرى لترى ما إذا كان بإمكانك تحديد الخطأ الذي ارتكبته!
الفهم
في app.py، ستجد بداية تطبيق ويب Flask. يحتوي التطبيق على طريق واحد (/) الذي يقبل كليهما
طلبات POST (بعد if) و
طلبات GET (بعد else). حاليا، عندما
يتم طلب طريق / عبر
تم عرض القالب GET, index.html . عندما
يتم طلب طريق / عبر POST، تتم إعادة توجيه المستخدم مرة أخرى إلى / عبر GET.
birthdays.db هي قاعدة بيانات SQLite تحتوي على جدول واحد، birthdays، الذي يحتوي على أربعة أعمدة: id, name, monthو day. يوجد عدد قليل من الصفوف بالفعل في هذا الجدول، على الرغم من أن تطبيق الويب الخاص بك سيدعم في النهاية القدرة على إدراج صفوف في هذا الجدول!
دليل
في
وظيفة static هو أ styles.css ملف يحتوي على رمز CSS لتطبيق الويب هذا. لا حاجة لتحرير هذا الملف، على الرغم من أنك مرحب بك إذا كنت ترغب في ذلك!
في
وظيفة templates هو index.html الملف الذي سيتم عرضه عندما يقوم المستخدم بعرض تطبيق الويب الخاص بك.
تفاصيل التنفيذ
أكمل تنفيذ تطبيق الويب للسماح للمستخدمين بتخزين وتتبع أعياد الميلاد.
- عندما
يتم طلب طريق
/عبرGET، يجب أن يعرض تطبيق الويب الخاص بك، في جدول، جميع الأشخاص في قاعدة البيانات الخاصة بك بالإضافة إلى أعياد ميلادهم.- أولاً، في
app.py، أضف المنطق في ملفكGETمعالجة الطلب للاستعلام عنbirthdays.dbقاعدة بيانات لجميع أعياد الميلاد. قم بتمرير كل تلك البيانات إلى حسابكindex.htmlالقالب. - ثم، في
index.html، أضف منطقًا لعرض كل عيد ميلاد كصف في الجدول. يجب أن يحتوي كل صف على عمودين: عمود لاسم الشخص وعمود آخر لعيد ميلاد الشخص.
- أولاً، في
- عندما
يتم طلب طريق
/عبرPOST، يجب أن يضيف تطبيق الويب الخاص بك تاريخ ميلاد جديدًا إلى قاعدة البيانات الخاصة بك ثم يعيد عرض صفحة الفهرس.- أولاً، في
index.html، أضف نموذج HTML. يجب أن يسمح النموذج للمستخدمين بكتابة الاسم وشهر عيد الميلاد ويوم عيد الميلاد. تأكد من إرسال النموذج إلى/("الإجراء") بطريقةpost. - ثم، في
app.py، أضف المنطق في ملفكPOSTمعالجة الطلب لINSERTصف جديد فيbirthdaysيعتمد على البيانات المقدمة من قبل المستخدم.
- أولاً، في
اختياريًا، يمكنك أيضًا:
- أضف القدرة على حذف و/أو تعديل إدخالات عيد الميلاد.
- أضف أي ميزات إضافية من اختيارك!
تلميحات
قم بإنشاء نموذج يمكن للمستخدمين من خلاله إرسال أعياد الميلاد
في index.html، لاحظ المهام التالية:
<!-- TODO: Create a form for users to submit a name, a month, and a day -->
تذكر أنه لإنشاء نموذج، يمكنك استخدام form عنصر HTML. يمكنك إنشاء form عنصر HTML مع علامتي الفتح والإغلاق التاليتين:
<form>
</form>
بالطبع، لا يزال النموذج بحاجة إلى حقول الإدخال (وزر يمكن للمستخدم من خلاله إرسال النموذج!). أذكر أن HTML
تقوم عناصر input بإنشاء، من بين أشياء أخرى، مربعات إدخال داخل النموذج. يمكنك تحديد بهم
سمة type للسماح لهم بالقبول text أو numberس. أعط أيضًا input العناصر أ name حتى تتمكن من التمييز بينها.
<form>
<input name="name" type="text">
<input name="month" type="number">
<input name="day" type="number">
</form>
قد يستفيد النموذج الخاص بك من زر يمكن للمستخدم النقر عليه لإرسال بياناته. أضف input عنصر من النوع submit، والذي سيسمح للمستخدم بالقيام بذلك. إذا كنت تريد أن يحتوي الزر نفسه على نص توضيحي، فحاول تعيين
سمة value .
<form>
<input name="name" type="text">
<input name="month" type="number">
<input name="day" type="number">
<input type="submit" value="Add Birthday">
</form>
أين سيتم إرسال بيانات المستخدم؟ حاليا، في أي مكان! تذكر أنه يمكنك تحديد النموذج
سمة action لتحديد المسار الذي يجب طلبه بعد إرسال النموذج. سيتم إرسال بيانات النموذج مع الطلب الناتج. ال
تحدد سمة method طريقة طلب HTTP التي سيتم استخدامها عند إرسال النموذج.
<form action="/" method="post">
<input name="name" type="text">
<input name="month" type="number">
<input name="day" type="number">
<input type="submit" value="Add Birthday">
</form>
وبهذا، يجب أن يكون النموذج الخاص بك يعمل بشكل مثالي، على الرغم من أنه لا يزال من الممكن تحسينه! النظر في إضافة
قيم placeholder لتوضيح الأمور قليلاً:
<form action="/" method="post">
<input name="name" placeholder="Name" type="text">
<input name="month" placeholder="Month" type="number">
<input name="day" placeholder="Day" type="number">
<input type="submit" value="Add Birthday">
</form>
وفكر في إضافة البعض التحقق من جانب العميل، لضمان تعاون المستخدم مع غرض النموذج الخاص بك. على سبيل المثال، أ input حقل النوع
يمكن أن يحتوي number أيضًا على
تم تحديد سمة min و max ، والتي تحدد الحد الأدنى والحد الأقصى للقيمة التي يمكن للمستخدم إدخالها.
<form action="/" method="post">
<input name="name" placeholder="Name" type="text">
<input name="month" placeholder="Month" type="number" min="1" max="12">
<input name="day" placeholder="Day" type="number" min="1" max="31">
<input type="submit" value="Add Birthday">
</form>
إضافة نموذج إرسال المستخدم إلى قاعدة البيانات
في app.py، لاحظ المهام التالية:
# TODO: Add the user's entry into the database
تذكر أن Flask لديه بعض الطرق المفيدة للوصول إلى بيانات النموذج المرسلة عبر POST! على وجه الخصوص:
# Access form data
request.form.get(NAME)
حيث NAME يشير إلى name السمة الخاصة input عنصر يحتوي على البيانات المرسلة. إذا كان لديك
تمت تسمية عناصر input name, monthو day، يمكنك الوصول إلى (وخزن!) قيمها على التوالي باستخدام ما يلي:
# Access form data
name = request.form.get("name")
month = request.form.get("month")
day = request.form.get("day")
الآن القيم التي أرسلها المستخدم في name, monthو day عناصر الإدخال متاحة لك كمتغيرات بايثون.
الخطوة التالية هي إضافة هذه القيم إلى قاعدة البيانات الخاصة بك! بفضل هذا الخط بالذات قام
db = SQL("sqlite:///birthdays.db")
app.py بالفعل بإنشاء اتصال بـ birthdays.db تحت الاسم db. يمكنك الآن تنفيذ استعلامات SQL عن طريق الاتصال db.execute باستخدام استعلام SQL صالح. إذا أردت إضافة عيد ميلاد كارتر في الأول من يناير، فيمكنك تشغيل عبارة SQL التالية:
INSERT INTO birthdays (name, month, day) VALUES('Carter', 1, 1);
تكوين app.py لتشغيل نفس الاستعلام، ولكن مع العناصر النائبة للقيم المراد إدراجها، كما يلي:
# Access form data
name = request.form.get("name")
month = request.form.get("month")
day = request.form.get("day")
# Insert data into database
db.execute("INSERT INTO birthdays (name, month, day) VALUES(?, ?, ?)", name, month, day)
وهذا ينبغي أن يفعل ذلك! حاول إرسال النموذج، فتح birthdays.db، وباستخدام أ SELECT لعرض محتويات birthdays الجدول. يجب أن تشاهد بيانات النموذج المقدم المتاحة لك.
أثناء قيامك بإنشاء المزيد من التطبيقات المتقدمة، ستحتاج أيضًا إلى إضافتها التحقق من جانب الخادم: أي طريقة للتحقق من صحة بيانات المستخدم من قبل افعل أي شيء آخر! إحدى عمليات التحقق الأولى التي قد تقوم بها هي ما إذا كان المستخدم قد أرسل أي بيانات على الإطلاق! هل يجب أن تحاول استرداد بيانات النموذج باستخدام request.form.get حيث لم يرسل المستخدم أي شيء، request.form.get سيُرجع سلسلة فارغة. يمكنك التحقق من هذه القيمة في بايثون على النحو التالي:
# Access form data
name = request.form.get("name")
if not name:
return redirect("/")
month = request.form.get("month")
if not month:
return redirect("/")
day = request.form.get("day")
if not day:
return redirect("/")
# Insert data into database
db.execute("INSERT INTO birthdays (name, month, day) VALUES(?, ?, ?)", name, month, day)
الآن، لن تقوم بإدراج صف حتى تتأكد من أن المستخدم قد قدم جميع البيانات التي تحتاجها.
لا يزال من الممكن أن تسوء بعض الأمور! ماذا لو لم يقدم المستخدم، في الواقع، قيمة رقمية لـ month أو day؟ طريقة واحدة للتحقق هي try لتحويل القيمة إلى عدد صحيح باستخدام int ، وإذا فشل التحويل، لإعادة توجيه المستخدم مرة أخرى إلى الصفحة الرئيسية.
# Access form data
name = request.form.get("name")
if not name:
return redirect("/")
month = request.form.get("month")
if not month:
return redirect("/")
try:
month = int(month)
except ValueError:
return redirect("/")
day = request.form.get("day")
if not day:
return redirect("/")
try:
day = int(day)
except ValueError:
return redirect("/")
# Insert data into database
db.execute("INSERT INTO birthdays (name, month, day) VALUES(?, ?, ?)", name, month, day)
وحتى إذا قام المستخدم بإدخال رقم، فمن الأفضل التحقق من أنه في النطاق الصحيح!
# Access form data
name = request.form.get("name")
if not name:
return redirect("/")
month = request.form.get("month")
if not month:
return redirect("/")
try:
month = int(month)
except ValueError:
return redirect("/")
if month < 1 or month > 12:
return redirect("/")
day = request.form.get("day")
if not day:
return redirect("/")
try:
day = int(day)
except ValueError:
return redirect("/")
if day < 1 or day > 31:
return redirect("/")
# Insert data into database
db.execute("INSERT INTO birthdays (name, month, day) VALUES(?, ?, ?)", name, month, day)
عرض أعياد الميلاد في birthdays.db
بمجرد أن يتمكن المستخدم من إرسال أعياد الميلاد وتخزينها فيه birthdays.db، مهمتك التالية هي التأكد من عرض أعياد الميلاد هذه index.html.
أولاً، ستحتاج إلى استرداد جميع أعياد الميلاد من birthdays.db. يمكنك ذلك باستخدام استعلام SQL:
SELECT * FROM birthdays;
راجع المهام التالية في app.py:
# TODO: Display the entries in the database on index.html
فكر في التهيئة app.py لتشغيل استعلام SQL هذا في كل مرة يتم فيها تحميل الصفحة بـ
طلب GET :
# Query for all birthdays
birthdays = db.execute("SELECT * FROM birthdays")
الآن، جميع أعياد الميلاد في birthdays جدول birthdays.db متاحة لك في متغير Python المسمى birthdays. على وجه الخصوص، يتم تخزين نتائج استعلام SQL كقائمة من القواميس. يمثل كل قاموس صفًا واحدًا يتم إرجاعه بواسطة الاستعلام، ويتوافق كل مفتاح في القاموس مع اسم عمود من القاموس
جدول birthdays (i.e.، "الاسم"، "الشهر"، و"اليوم").
لعرض أعياد الميلاد هذه index.html، يمكنك الاعتماد على Flask
وظيفة render_template . يمكنك تحديد ذلك
يجب أن يتم عرض index.html باستخدام ملف birthdays متغير عن طريق تحديد وسيطة الكلمة الرئيسية، وتسمى أيضًا birthdays، وتعيينه يساوي birthdays المتغير الذي قمت بإنشائه مؤخرًا.
# Query for all birthdays
birthdays = db.execute("SELECT * FROM birthdays")
# Render birthdays page
return render_template("index.html", birthdays=birthdays)
للتوضيح، الاسم الموجود على الجانب الأيسر من =, birthdays، هو الاسم الذي يمكنك من خلاله الوصول إلى بيانات أعياد الميلاد الموجودة بداخله index.html نفسها.
الآن
يتم عرض index.html مع إمكانية الوصول إلى بيانات أعياد الميلاد، ويمكنك استخدام Jinja لعرض البيانات بشكل صحيح. يمكن لـ Jinja، مثل Python، التكرار عبر عناصر القائمة. ويمكن لـ Jinja، مثل Python، الوصول إلى العناصر في القاموس من خلال مفاتيحها. في هذه الحالة، بناء جملة Jinja للقيام بذلك هو اسم القاموس، متبوعًا بـ a .، ثم اسم مفتاح الوصول.
{% for birthday in birthdays %}
<tr>
<td>{{ birthday.name }}</td>
<td>{{ birthday.month }}/{{ birthday.day }}</td>
</tr>
{% endfor %}
وهذا كل شيء! حاول إعادة تحميل الصفحة لرؤية أعياد الميلاد المعروضة.
الإرشادات التفصيلية
تم تسجيل هذا الفيديو عندما كانت الدورة التدريبية لا تزال تستخدم CS50 IDE لكتابة الشيفرة. على الرغم من أن الواجهة قد تبدو مختلفة عن مساحة الشيفرة الخاصة بك، إلا أن سلوك البيئتين يجب أن يكون متشابهًا إلى حد كبير!
لست متأكدًا من كيفية الحل؟
الاختبار
لا check50 لمجموعة المشاكل هذه! ولكن تأكد من اختبار تطبيق الويب الخاص بك عن طريق إضافة بعض أعياد الميلاد والتأكد من ظهور البيانات في جدولك كما هو متوقع.
دليل
تشغيل flask run في جهازك الطرفي أثناء تواجدك في
دليل birthdays لبدء خادم ويب يخدم تطبيق Flask الخاص بك.
كيفية الإرسال
في جهازك الطرفي، قم بتنفيذ ما يلي لإرسال عملك، والإجابة على المطالبات التي تظهر أيضًا.
submit50 cs50/problems/2026/x/birthdays