تمرين من المصدر الأصلي · تطبيق عملي

تمويل

استخدم الشرح العربي للفهم، واعتمد صفحة CS50 الأصلية مرجعًا نهائيًا للمواصفات والتسليم.

جلسة دراسة مقترحة: حتى 60 دقيقةالجهد الكلي التقريبي: 120 دقيقة · أكمل من حيث توقفت لاحقًا.Week 9
محاور هذه الخطوة
  • Flask
  • القوالب
  • المسارات
  • الجلسات

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

تمويل

المصدر الأصلي

قائمة تنفيذ التمرين

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

تمويل بقيمة 50 دولارًا كنديًا

إنشاء موقع ويب يمكن للمستخدمين من خلاله "شراء" و"بيع" الأسهم، على النحو الموضح أدناه.

C$50 Finance

الخلفية

إذا لم تكن متأكدًا تمامًا مما يعنيه شراء وبيع الأسهم (i.e.، أسهم شركة)، فتوجه إلى هنا للحصول على برنامج تعليمي.

أنت على وشك تنفيذ C$50 Finance، وهو تطبيق ويب يمكنك من خلاله إدارة محافظ الأسهم. لن تسمح لك هذه الأداة فقط بالتحقق من أسعار الأسهم الحقيقية وقيم المحافظ، بل ستتيح لك أيضًا شراء (حسنًا، "شراء") وبيع (حسنًا، "بيع") الأسهم عن طريق الاستعلام عن أسعار الأسهم.

في الواقع، هناك أدوات (تُعرف إحداها باسم IEX) تتيح لك تنزيل أسعار الأسهم عبر واجهة برمجة التطبيقات (واجهة برمجة التطبيقات) الخاصة بها باستخدام عناوين URL مثل https://api.iex.cloud/v1/data/core/quote/nflx?token=API_KEY. لاحظ كيف تم تضمين رمز Netflix (NFLX) في عنوان URL هذا؛ هذه هي الطريقة التي تعرف بها IEX البيانات التي سيتم إرجاعها. لن يقوم هذا الرابط فعليًا بإرجاع أي بيانات لأن IEX يتطلب منك استخدام مفتاح API، ولكن إذا حدث ذلك، فسترى استجابة بتنسيق JSON (JavaScript Object Notation) مثل هذا:

{
  "avgTotalVolume":6787785,
  "calculationPrice":"tops",
  "change":1.46,
  "changePercent":0.00336,
  "close":null,
  "closeSource":"official",
  "closeTime":null,
  "companyName":"Netflix Inc.",
  "currency":"USD",
  "delayedPrice":null,
  "delayedPriceTime":null,
  "extendedChange":null,
  "extendedChangePercent":null,
  "extendedPrice":null,
  "extendedPriceTime":null,
  "high":null,
  "highSource":"IEX real time price",
  "highTime":1699626600947,
  "iexAskPrice":460.87,
  "iexAskSize":123,
  "iexBidPrice":435,
  "iexBidSize":100,
  "iexClose":436.61,
  "iexCloseTime":1699626704609,
  "iexLastUpdated":1699626704609,
  "iexMarketPercent":0.00864679844447232,
  "iexOpen":437.37,
  "iexOpenTime":1699626600859,
  "iexRealtimePrice":436.61,
  "iexRealtimeSize":5,
  "iexVolume":965,
  "lastTradeTime":1699626704609,
  "latestPrice":436.61,
  "latestSource":"IEX real time price",
  "latestTime":"9:31:44 AM",
  "latestUpdate":1699626704609,
  "latestVolume":null,
  "low":null,
  "lowSource":"IEX real time price",
  "lowTime":1699626634509,
  "marketCap":192892118443,
  "oddLotDelayedPrice":null,
  "oddLotDelayedPriceTime":null,
  "open":null,
  "openTime":null,
  "openSource":"official",
  "peRatio":43.57,
  "previousClose":435.15,
  "previousVolume":2735507,
  "primaryExchange":"NASDAQ",
  "symbol":"NFLX",
  "volume":null,
  "week52High":485,
  "week52Low":271.56,
  "ytdChange":0.4790450244167119,
  "isUSMarketOpen":true
}

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

دعونا نوجه انتباهنا الآن إلى الحصول على كود التوزيع الخاص بهذه المشكلة!

البدء

قم بتسجيل الدخول cs50.dev، انقر على نافذتك الطرفية، وقم بالتنفيذ cd بمفرده. يجب أن تجد أن مطالبة النافذة الطرفية الخاصة بك تشبه ما يلي:

$

التنفيذ التالي

wget https://cdn.cs50.net/2026/x/psets/9/finance.zip

من أجل تنزيل ملف ZIP يسمى finance.zip في مساحة الشيفرة الخاصة بك.

ثم نفذ

unzip finance.zip

لإنشاء مجلد يسمى finance. لم تعد بحاجة إلى ملف ZIP، حتى تتمكن من التنفيذ

rm finance.zip

ثم قم بالرد بـ "y" متبوعًا بـ Enter عند المطالبة لإزالة ملف ZIP الذي قمت بتنزيله.

الآن اكتب

cd finance

متبوعًا بـ Enter للانتقال إلى (i.e.، open) هذا الدليل. يجب أن تشبه مطالبتك الآن ما يلي.

finance/ $

تنفيذ ls بمفرده، ويجب أن تشاهد بعض الملفات والمجلدات:

app.py  finance.db  helpers.py  requirements.txt  static/  templates/

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

قيد التشغيل

ابدأ تشغيل خادم الويب المدمج في Flask (داخل finance/):

$ flask run

قم بزيارة عنوان URL الذي تم إخراجه بواسطة flask لرؤية كود التوزيع أثناء العمل. ومع ذلك، لن تتمكن من تسجيل الدخول أو التسجيل حتى الآن!

داخل finance/، اركض sqlite3 finance.db للفتح finance.db مع sqlite3. إذا قمت بتشغيل .schema في موجه SQLite، لاحظ كيف finance.db يأتي مع جدول يسمى users. ألق نظرة على بنيته (i.e.، المخطط). لاحظ كيف سيحصل المستخدمون الجدد افتراضيًا على 10000 دولار نقدًا. ولكن إذا قمت بتشغيل SELECT * FROM users;، لا يوجد (حتى الآن!) أي مستخدمين (i.e.، صفوف) للتصفح.

طريقة أخرى للعرض finance.db مزود ببرنامج يسمى phpLiteAdmin. انقر فوق finance.db في متصفح الملفات الخاص بموقع codespace الخاص بك، ثم انقر فوق الرابط الموضح أسفل النص "يُرجى زيارة الرابط التالي للسماح بمعاينة GitHub". يجب أن تشاهد معلومات حول قاعدة البيانات نفسها، بالإضافة إلى جدول، users، تمامًا كما رأيت في sqlite3 موجه مع .schema.

الفهم

app.py

افتح app.py. يوجد أعلى الملف مجموعة من الواردات، من بينها وحدة SQL الخاصة بـ CS50 وبعض الوظائف المساعدة. المزيد عن تلك قريبا.

بعد التكوين قارورة، لاحظ كيف يقوم هذا الملف بتعطيل التخزين المؤقت للاستجابات (شريطة أن تكون في وضع تصحيح الأخطاء، وهو ما تكون عليه افتراضيًا في مساحة كود code50 الخاصة بك)، لئلا تقوم بإجراء تغيير على بعض الملفات ولكن متصفحك لا يلاحظ ذلك. لاحظ بعد ذلك كيفية تكوينه جينجا باستخدام "مرشح" مخصص، usd، دالة (تم تعريفها في helpers.py) مما سيسهل تنسيق القيم بالدولار الأمريكي (USD). ثم يقوم أيضًا بتكوين Flask للتخزين الجلسات على نظام الملفات المحلي (i.e.، القرص) بدلاً من تخزينها داخل ملفات تعريف الارتباط (الموقعة رقميًا)، وهو الإعداد الافتراضي لـ Flask. يقوم الملف بعد ذلك بتكوين وحدة SQL الخاصة بـ CS50 لاستخدامها finance.db.

بعد ذلك هناك مجموعة كاملة من المسارات، اثنان منها فقط تم تنفيذهما بالكامل: login و logout. قراءة من خلال تنفيذ login أولاً. لاحظ كيف يستخدم db.execute (من مكتبة CS50) للاستعلام finance.db. ولاحظ كيف يستخدم check_password_hash لمقارنة تجزئات كلمات مرور المستخدمين. لاحظ أيضًا كيف login "يتذكر" أنه تم تسجيل دخول المستخدم عن طريق تخزين بياناته user_id، عدد صحيح، في session. بهذه الطريقة، يمكن لأي من مسارات هذا الملف التحقق من المستخدم الذي قام بتسجيل الدخول، إن وجد. وأخيرًا، لاحظ كيف أنه بمجرد قيام المستخدم بتسجيل الدخول بنجاح، سيتم إعادة التوجيه إلى login "/"، لنقل المستخدم إلى صفحته الرئيسية. وفي الوقت نفسه، لاحظ كيف logout يمسح ببساطة session، تسجيل خروج المستخدم بشكل فعال.

لاحظ كيف يتم "تزيين" معظم الطرق بها @login_required (وظيفة محددة في helpers.py أيضًا). يضمن مصمم الديكور هذا أنه إذا حاول المستخدم زيارة أي من هذه المسارات، فسيتم إعادة توجيهه إليه أولاً login لتسجيل الدخول.

لاحظ أيضًا كيف تدعم معظم المسارات GET وPOST. ومع ذلك، فإن معظمها (في الوقت الحالي!) يرد ببساطة "الاعتذار"، نظرًا لعدم تنفيذها بعد.

helpers.py

ألقِ نظرة بعد ذلك helpers.py. اه، هناك تنفيذ apology. لاحظ كيف يعرض القالب في النهاية، apology.html. ويحدث أيضًا أن يحدد داخل نفسه وظيفة أخرى، escape، الذي يستخدمه ببساطة لاستبدال الأحرف الخاصة في الاعتذارات. من خلال تحديد escape من الداخل apology، قمنا بحصر الأول في الأخير وحده؛ لن تتمكن (أو تحتاج) أي وظائف أخرى إلى الاتصال بها.

التالي في الملف هو login_required. لا داعي للقلق إذا كان هذا الأمر غامضًا بعض الشيء، ولكن إذا كنت قد تساءلت يومًا كيف يمكن لوظيفة ما إرجاع وظيفة أخرى، فإليك مثال!

بعد ذلك lookup، دالة، نظرا ل symbol (e.g.، NFLX)، يُرجع سعر أسهم شركة ما في شكل dict بثلاثة مفاتيح: name، وقيمته أ str; price، وقيمته أ float; و symbol، وقيمته أ str، نسخة أساسية (أحرف كبيرة) من رمز السهم، بغض النظر عن كيفية كتابة هذا الرمز بالأحرف الكبيرة عند تمريره إلى lookup. لاحظ أن هذه ليست أسعار "في الوقت الفعلي" ولكنها تتغير بمرور الوقت، تمامًا كما هو الحال في العالم الحقيقي!

الأخير في الملف هو usd، دالة قصيرة تقوم ببساطة بتنسيق ملف float بالدولار الأمريكي (e.g., تم تنسيق 1234.56 بالشكل $1,234.56).

requirements.txt

بعد ذلك، قم بإلقاء نظرة سريعة على requirements.txt. يصف هذا الملف ببساطة الحزم التي سيعتمد عليها هذا التطبيق.

static/

ألق نظرة سريعة أيضًا static/، بداخله styles.css. هذا هو المكان الذي تعيش فيه بعض CSS الأولية. فنحن نرحب بتعديله كما تراه مناسبًا.

templates/

انظر الآن templates/. في login.html هو، في الأساس، مجرد نموذج HTML، منمق باستخدام التمهيد. في apology.html، في هذه الأثناء، هو نموذج للاعتذار. أذكر ذلك apology في helpers.py أخذ وسيطتين: message، والذي تم تمريره إلى render_template كقيمة bottom، واختياريًا، code، والذي تم تمريره إلى render_template كقيمة top. لاحظ في apology.html كيف يتم استخدام هذه القيم في النهاية! و إليكم السبب 0:-)

آخر ما يصل هو layout.html. إنه أكبر قليلاً من المعتاد، ولكن هذا يرجع في الغالب إلى أنه يأتي مزودًا بـ "شريط التنقل" (شريط التنقل) الرائع والمتوافق مع الأجهزة المحمولة، والذي يعتمد أيضًا على Bootstrap. لاحظ كيف يتم تعريف الكتلة، main، بداخلها قوالب (بما في ذلك apology.html و login.html) يجب أن يذهب. ويتضمن أيضًا دعمًا لـ Flask تومض الرسالة بحيث يمكنك ترحيل الرسائل من مسار إلى آخر ليشاهدها المستخدم.

المواصفات

register

أكمل تنفيذ register بطريقة تسمح للمستخدم بالتسجيل للحصول على حساب عبر النموذج.

  • يتطلب من المستخدم إدخال اسم مستخدم، ويتم تنفيذه كحقل نصي name هو username. اعتذر إذا كان إدخال المستخدم فارغًا أو كان اسم المستخدم موجودًا بالفعل.
    • لاحظ ذلك cs50.SQL.execute سوف يرفع أ ValueError استثناء إذا حاولت ذلك INSERT اسم مستخدم مكرر لأننا أنشأنا UNIQUE INDEX على users.username. تأكد إذن من الاستخدام try و except لتحديد ما إذا كان اسم المستخدم موجودًا بالفعل.
  • يتطلب من المستخدم إدخال كلمة مرور، ويتم تنفيذها كحقل نصي name هو password، ثم نفس كلمة المرور مرة أخرى، يتم تنفيذها كحقل نصي name هو confirmation. اعتذر إذا كان أي من الإدخالين فارغًا أو كانت كلمات المرور غير متطابقة.
  • أرسل مدخلات المستخدم عبر POST إلى /register.
  • INSERT المستخدم الجديد إلى users، لتخزين تجزئة كلمة مرور المستخدم، وليس كلمة المرور نفسها. قم بتجزئة كلمة مرور المستخدم مع generate_password_hash من المحتمل أنك ستحتاج إلى إنشاء قالب جديد (e.g., register.html) يشبه تمامًا login.html.

بمجرد التنفيذ register بشكل صحيح، يجب أن تكون قادرًا على التسجيل للحصول على حساب وتسجيل الدخول (منذ login و logout يعمل بالفعل)! ويجب أن تكون قادرًا على رؤية صفوفك عبر phpLiteAdmin أو sqlite3.

quote

أكمل تنفيذ quote بطريقة تسمح للمستخدم بالبحث عن السعر الحالي للسهم.

  • يتطلب من المستخدم إدخال رمز السهم، والذي يتم تنفيذه كحقل نصي name هو symbol.
  • أرسل مدخلات المستخدم عبر POST إلى /quote.
  • من المحتمل أنك ستحتاج إلى إنشاء نموذجين جديدين (e.g., quote.html و quoted.html). عندما يزور المستخدم /quote عبر GET، قم بعرض أحد هذه القوالب، والتي يجب أن يكون داخلها نموذج HTML يتم إرساله إلى /quote عبر POST. ردًا على مشاركة، quote عرض هذا القالب الثاني، مع تضمين قيمة واحدة أو أكثر بداخله من lookup.

buy

أكمل تنفيذ buy بطريقة تمكن المستخدم من شراء الأسهم.

  • يتطلب من المستخدم إدخال رمز السهم، والذي يتم تنفيذه كحقل نصي name هو symbol. قم بتقديم اعتذار إذا كان الإدخال فارغًا أو كان الرمز غير موجود (وفقًا لقيمة الإرجاع الخاصة بـ lookup).
  • يتطلب من المستخدم إدخال عدد من المشاركات، ويتم تنفيذها كحقل نصي name هو shares. اعتذر إذا لم يكن الإدخال عددًا صحيحًا موجبًا.
  • أرسل مدخلات المستخدم عبر POST إلى /buy.
  • عند الانتهاء، قم بإعادة توجيه المستخدم إلى الصفحة الرئيسية.
  • من المحتمل أنك تريد الاتصال lookup للبحث عن السعر الحالي للسهم.
  • من المحتمل أنك سترغب في ذلك SELECT مقدار الأموال النقدية التي يمتلكها المستخدم حاليًا users.
  • قم بإضافة جدول جديد أو أكثر إلى finance.db والتي يمكن من خلالها متابعة عملية الشراء. قم بتخزين معلومات كافية حتى تعرف من اشترى ماذا وبأي سعر ومتى.
    • استخدم أنواع SQLite المناسبة.
    • تعريف UNIQUE يفهرس أي حقول يجب أن تكون فريدة.
    • تعريف (غير-UNIQUE) يفهرس أي حقول ستبحث من خلالها (مثل عبر SELECT مع WHERE).
  • تقديم اعتذار، دون إكمال عملية الشراء، إذا كان المستخدم لا يستطيع تحمل عدد الأسهم بالسعر الحالي.
  • لا داعي للقلق بشأن ظروف السباق (أو استخدام المعاملات).

بمجرد التنفيذ buy بشكل صحيح، من المفترض أن تكون قادرًا على رؤية مشتريات المستخدمين في جدولك (جداولك) الجديدة عبر phpLiteAdmin أو sqlite3.

index

أكمل تنفيذ index بطريقة تعرض جدول HTML يلخص، للمستخدم الذي قام بتسجيل الدخول حاليًا، الأسهم التي يمتلكها المستخدم، وعدد الأسهم المملوكة، والسعر الحالي لكل سهم، والقيمة الإجمالية لكل حيازة (i.e.، سعر السهم مضروبًا). اعرض أيضًا الرصيد النقدي الحالي للمستخدم بالإضافة إلى الإجمالي الكلي (i.e.، القيمة الإجمالية للأسهم بالإضافة إلى النقد).

  • من المحتمل أنك ستحتاج إلى تنفيذ عدة عمليات SELECTق. اعتمادًا على كيفية تنفيذ جدولك (جداولك)، قد تجد المجموعة حسب, موجود, المجموعو/أو أين من الفائدة.
  • من المحتمل أنك سترغب في الاتصال lookup لكل سهم.

sell

أكمل تنفيذ sell بطريقة تمكن المستخدم من بيع أسهم الأسهم (التي يملكها).

  • يتطلب من المستخدم إدخال رمز السهم، والذي يتم تنفيذه كـ select القائمة التي name هو symbol. قم بتقديم اعتذار إذا فشل المستخدم في تحديد سهم أو إذا (بطريقة أو بأخرى، بمجرد إرساله) لا يمتلك المستخدم أي أسهم في هذا السهم.
  • يتطلب من المستخدم إدخال عدد من المشاركات، ويتم تنفيذها كحقل نصي name هو shares. قم بتقديم اعتذار إذا لم يكن الإدخال عددًا صحيحًا موجبًا أو إذا كان المستخدم لا يمتلك هذا العدد من الأسهم في السهم.
  • أرسل مدخلات المستخدم عبر POST إلى /sell.
  • عند الانتهاء، قم بإعادة توجيه المستخدم إلى الصفحة الرئيسية.
  • لا داعي للقلق بشأن ظروف السباق (أو استخدام المعاملات).

history

أكمل تنفيذ history بطريقة تعرض جدول HTML يلخص جميع معاملات المستخدم على الإطلاق، ويسرد صفًا تلو الآخر كل عملية شراء وكل عملية بيع.

  • لكل صف، وضح ما إذا كان السهم قد تم شراؤه أو بيعه وقم بإدراج رمز السهم وسعر (الشراء أو البيع) وعدد الأسهم المشتراة أو المباعة وتاريخ ووقت حدوث المعاملة.
  • قد تحتاج إلى تغيير الجدول الذي قمت بإنشائه من أجله buy أو أكمله بجدول إضافي. حاول تقليل التكرار.

لمسة شخصية

قم بتنفيذ لمسة شخصية واحدة على الأقل من اختيارك:

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

الإرشادات التفصيلية

محتوى خارجي من YouTube

لن نتصل بهذه الخدمة قبل موافقتك. يمكنك فتح المصدر في نافذة مستقلة بدل تحميله هنا.

فتح المصدر

الاختبار

تأكد من اختبار تطبيق الويب الخاص بك يدويًا، كما هو الحال من خلال

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

اختبر أيضًا بعض الاستخدام غير المتوقع، مثل

  • إدخال سلاسل أبجدية في النماذج عند توقع أرقام فقط،
  • إدخال أرقام صفرية أو سالبة في النماذج عند توقع أرقام موجبة فقط،
  • إدخال قيم الفاصلة العائمة في النماذج عند توقع الأعداد الصحيحة فقط،
  • محاولة إنفاق أموال أكثر مما يملكه المستخدم،
  • محاولة بيع أسهم أكثر مما يملكه المستخدم،
  • إدخال رمز سهم غير صالح، و
  • بما في ذلك الشخصيات التي يحتمل أن تكون خطرة مثل ' و ; في استعلامات SQL.

يمكنك أيضًا التحقق من صحة HTML الخاص بك عن طريق النقر فوق أنا ♥ المدقق زر الموجود في تذييل كل صفحة من صفحاتك، والذي سيؤدي إلى نشر HTML الخاص بك إلى validator.w3.org.

بمجرد الرضا، لاختبار الشيفرة الخاص بك check50، قم بتنفيذ ما يلي.

check50 cs50/problems/2026/x/finance

النمط

style50 app.py

الحل الخاص بفريق العمل

نرحب بتصميم تطبيقك بشكل مختلف، ولكن إليك ما يبدو عليه الحل الذي قدمه فريق العمل!

https://finance.cs50.net/

لا تتردد في التسجيل للحصول على حساب واللعب. افعل لا استخدم كلمة المرور التي تستخدمها في المواقع الأخرى.

إنه كذلك معقول لإلقاء نظرة على HTML وCSS الخاصين بالموظفين.

تلميحات

  • لتنسيق قيمة كقيمة بالدولار الأمريكي (مع إدراج السنتات بمنزلتين عشريتين)، يمكنك استخدام usd قم بتصفية قوالب Jinja الخاصة بك (طباعة القيم كـ {{ value | usd }} بدلاً من {{ value }}.
  • داخل cs50.SQL هو execute الطريقة التي يجب أن تكون الوسيطة الأولى لها هي a str من SQL. إذا كان ذلك يحتوي str على معلمات علامة الاستفهام التي يجب ربط القيم بها، ويمكن توفير هذه القيم كمعلمات مسماة إضافية execute. شاهد تنفيذ login لأحد هذه الأمثلة. قيمة الإرجاع execute كالتالي:

    • إذا str هو أ SELECTإذن يجب طباعة execute يُرجع أ list من صفر أو أكثر كائنات dict ، بداخلها مفاتيح وقيم تمثل حقول وخلايا الجدول، على التوالي.
    • إذا str هو INSERT، والجدول الذي تم إدراج البيانات فيه يحتوي على زيادة تلقائية PRIMARY KEYإذن يجب طباعة execute يُرجع قيمة المفتاح الأساسي للصف المدرج حديثًا.
    • إذا str هو أ DELETE أو UPDATEإذن يجب طباعة execute يُرجع عدد الصفوف المحذوفة أو المحدثة بواسطة سيقوم str.
  • تذكر ذلك يمكن cs50.SQL بتسجيل أي استعلامات يتم تنفيذها عبر نافذتك الطرفية execute (حتى تتمكن من تأكيد ما إذا كانت على النحو المنشود).
  • تأكد من استخدام المعلمات المرتبطة بعلامة الاستفهام (i.e.، a بارامستايل من named) عند الاتصال بـ CS50 طريقة execute ، على غرار ذلك WHERE ?. افعل لا استخدم سلاسل f، format أو + (i.e.، التسلسل)، لئلا تتعرض لهجوم حقن SQL.
  • إذا (وفقط إذا) كنت مرتاحًا بالفعل لاستخدام SQL، فنحن نرحب بك لاستخدامها SQLAlchemy الأساسية أو قارورة SQLAlchemy (i.e., SQLAlchemy ORM) بدلاً من cs50.SQL.
  • تذكر أنه بينما يمكنك التحقق من صحة القيم المدخلة في نموذج HTML، إلا أنه يمكن للمستخدمين الأذكياء تجاوز تلك القيم. تأكد من التحقق من صحة القيم من جانب الخادم أيضًا. وعلى نفس المنوال، إذا اخترت استخدام Javascript في الحل الخاص بك، فتأكد من أن التطبيق الخاص بك لا يزال يعمل إذا قام المستخدم بتعطيل Javascript.
  • نرحب بإضافة ملفات ثابتة إضافية إلى static/.
  • في حالة إضافة وظائف إضافية helpers.py، تأكد من عدم فتح اتصال قاعدة بيانات جديد. إذا كانت إحدى الوظائف المساعدة تتطلب استخدام قاعدة البيانات، فقم بتمريرها كمعلمة بدلاً من إعادة الاتصال.
  • من المحتمل أنك ستحتاج إلى استشارة توثيق جينجا عند تنفيذ القوالب الخاصة بك.
  • إنه كذلك معقول لمطالبة الآخرين بتجربة (ومحاولة إثارة الأخطاء) في موقعك.
  • نرحب بتغيير جماليات المواقع، مثل عبر
  • قد تجد توثيق القارورة و توثيق جينجا مفيد!

الأسئلة الشائعة

خطأ الاستيراد: لا توجد وحدة باسم "التطبيق"

بشكل افتراضي، يبحث flask عن ملف يسمى app.py في دليل العمل الحالي الخاص بك (لأننا قمنا بتكوين قيمة FLASK_APP، متغير البيئة، ليكون app.py). إذا رأيت هذا الخطأ، فمن المحتمل أنك قد قمت بالتشغيل flask في الدليل الخطأ!

خطأ في نظام التشغيل: [Errno 98] العنوان قيد الاستخدام بالفعل

إذا، عند التشغيل flask، ترى هذا الخطأ، من المحتمل (لا يزال) لديك flask قيد التشغيل في علامة تبويب أخرى. تأكد من إنهاء تلك العملية الأخرى، كما هو الحال مع ctrl-c، قبل البدء flask مرة أخرى. إذا لم يكن لديك أي علامة تبويب أخرى، قم بالتنفيذ fuser -k 8080/tcp لقتل أي عمليات (لا تزال) تستمع على منفذ TCP 8080.

كيفية الإرسال

في جهازك الطرفي، قم بتنفيذ ما يلي لإرسال عملك، والإجابة على المطالبات التي تظهر أيضًا.

submit50 cs50/problems/2026/x/finance

أنهيت التطبيق؟

راجع عناصر التنفيذ أعلاه، ثم احفظ إنجازك وانتقل إلى التمرين التالي.

حفظ إنجاز التمرين

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

العودة إلى جميع التمارين