القائمة الرئيسية

الصفحات

نظام تسجيل الطلاب - برمجة مشروع تخرج - بايثون

برمجة مشروع تخرج نظام تسجيل الطلاب عبر لغة البرمجة بايثون

برمجة مشروع تخرج نظام تسجيل الطلاب عبر لغة البرمجة بايثون


نظام تسجيل الطلاب بايثون باستخدام مكتبة json البسيطة وبعض دوال بايثون الرائعة.

في لغات البرمجة عموماً تحتاج لتخزين البيانات لادارتها لاحقا واجراء التعديلات عليها اذا لزم الامر ليس فقط لادارة الطلاب او المخازن ولكن البيانات المخزنة هي ذاكرة برنامجك او نظامك.

ماذا سوف نتعلم في هذا الدرس:

  1. انشاء ملف json عبر بايثون
  2. برمجة سطر اوامر خاص لادارة النظام
  3. اضافة الطلاب
  4. تعديل الطلاب
  5. حذف الطلاب
  6. بحث عن طالب

ملاحظة هذا النظام سوف يتم ادارتة بالكامل عبر الـ terminal او command line او سطر الاوامر بمعني انه خالي تماما من الواجهات الرسومية GUI.

الخبرات المستفادة من هذا الدرس:

التعرف اكثر علي دالة الشرط واستخدامها مع حلقة التكرار ومتغيرات النصوص الثابتة والمتغيرة وقواميس البيانات وانشاء دوال خاصة طباعة الاخطاء وتفاديها.

رسم خريطة العمل:

في البداية سوف نستدعي مكتبة json حتي نستطيع القرائة والتعديل علي ملف json.

ثم نستدعي دالة path من مكتبة os للتحقق من وجود الملف اذا لم يكن موجود نقوم بانشائة وتخزين محتواة داخل متغير واذا كان الملف موجود بالفعل نقوم بقراءة وتخزين محتواة في المتغير.

انشاء دالة لحفظ اي بيانات يتم اضافتها حديثاً او تم تعديلها.

انشاء دالة للطباعة بالشكل المطلوب.

ثم انشاء دالة سطر الاوامر لتوجية اوامر الاضافة, والبحث, والحذف, والتعديل لبيانات الطلاب بالنظام.

واخيرا حلقة تكرار لاعادة تشغيل دالة سطر الاوامر.


الشروع في العمل:

قم بفتح محرر النصوص الذي تستخدمة وننصح باستخدام محرر النصوص visual studio code.

افتح ملف جديد باي اسم وليكن:

stud.py

استدعاء المكتبات المطلوبة

import json
from os import path

التحقق من وجود الملف وانشائة ان لم يكن موجود

انشاء متغير dfile لتخزين اسم ومسار الملف للاستخدام المتكرر.

dfile = './stud.json'

عبر دالة الشرط if ودالة path نتحقق من وجود الملف.

if path.exists(dfile):

اذا كان موجود نقوم بتحويلة الي كائن بايثون dictionary في متغير studFile.

studFile = json.loads(open(dfile, 'r', encoding='utf-8').read())

يتم استخدام json.loads لتحويل نص بتنسيق json الي قاموس بايثون او python dictionary او بمعني اخر deserializing.

وتقوم دالة json.dumps بتحويل كائن بايثون الي نص json وهو ما يعرف بالـ serializing.

اذا كان الملف غير موجود نقوم بانشاء كائن جديد باسم newFile وننشيء القائمة التي ستحتوي علي كل الطلاب باسم students كما بالشكل التالي.

newFile = '{"students" : []}'

هذا هو كائن الـ جسون students هو عبارة عن مصفوفة او array [] يمكن تشبيهة بجدول قواعد بيانات sql بدون اعمدة او خلايا وهذا ما سوف نضيفة لاحقا, ولكن حتي الان الكائن مجرد نص string عادي لن يقبل الاضافة او التعديل لذالك.

نقوم بتحويل القيمة النصية في متغير newFile الي كائن بايثون باستخدام دالة json.loads .

jloads = json.loads(newFile)

ثم نحفظ الملف الجديد ومن ثم نفتحة في متغير studFile.

dfile = './stud.json'
if path.exists(dfile):
    studFile = json.loads(open(dfile, 'r', encoding='utf-8').read())
else:
    newFile = '{"students" : []}'
    jloads = json.loads(newFile)

    with open(dfile, 'w', encoding='utf-8') as f:
        json.dump(jloads, f, ensure_ascii=False, indent=4)
        print('file created')
    studFile = json.loads(open(dfile, 'r', encoding='utf-8').read())

انشاء دالة حفظ البيانات

دالة تحديث البيانات سوف نستخدمها لحفظ الكائن في كل مرة نقوم بالتعديل او الاضافة او الحذف.

savedata():

تحويل كائن بايثون studFile الي نص json.

jdumps = json.dumps(studFile)

تحويل نص json الي كائن python.

jloads = json.loads(jdumps)

ثم حفظ الملف بترميز utf-8 بحيث يمكنه حفظ وعرض أحرف من جميع الثقافات في العالم.

with open(dfile, 'w', encoding='utf-8') as f:

لاحظ اننا استخدمنا json.dump اثناء الكتابة داخل الملف وهي تختلف عن json.dumps.

json.dump(jloads, f, ensure_ascii=False, indent=4)

يتم استخدام طريقة dump لتحويل كائنات Python إلى كائنات json مناسبة للحفظ في ملف.

يتم استخدام dumps لتحويل objects او كائنات بايثون الي تنسيق json نصي حتي يتم استخدامه للتحليل والطباعة وما إلى ذلك.


def savedata():
    jdumps = json.dumps(studFile)
    jloads = json.loads(jdumps)
    with open(dfile, 'w', encoding='utf-8') as f:
        json.dump(jloads, f, ensure_ascii=False, indent=4)

انشاء دالة الطباعة

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

تاخذ الدالة معاملين او 2 prameters وهما (كائن الطالب - std) , ( id - رقم الطالب ) وسوف نعتمد علي متغير حلقة التكرار لترقيم الطلاب.
customPrint(id,std)
مثال علي شكل كائن الطالب std والذي يمكن تطويره واضافة المزيد من الصفات والابناء اليه من int, str, arr, dic واكثر.
{
     "first_name": "",
     "last_name": "",
     "score": ""
 }

 نستخدم دالة print لطباعة الكائن بالتنسيق المطلوب عبر عامل او operator ( % ).

%s تعني نص ويتم طباعة المتغيرات حسب ترتيبهم بعد علامة % .

print('''
    id: %s
    first name: %s
    last_name: %s
    score: %s
    ------''' % (id, std["first_name"], std["last_name"], std["score"]))

 

def customPrint(id,std):
    print('''
    id: %s
    first name: %s
    last_name: %s
    score: %s
    ------''' % (id, std["first_name"], std["last_name"], std["score"]))

انشاء دالة سطر الاوامر

بما ان بايثون لها انتشار واسع جدا علي انظمة التشغيل ومدعومة في معظم استضافات المواقع المدفوعة مثل امازون او علي بابا او هوستينجر.


اذا يمكنك استضافة هذا السكربت اونلاين بمقابل رمزي شهرياً والتحكم به من اي مكان بالعالم عبر ssh والوصول للبيانات في اي وقت ومن اي مكان لانه لا يحتوي علي واجهة رسومية مثل برمجيات مستر روبوت.


والان حتي نعطي اوامر لهذا السكربت علينا انشاء دالة تكون مثل الروبوت المبرمج مسبقاً علي بعض الطلبات التي سنكتبها له.

مقادير عمل سطر اوامر:

  • متغيرات - variables
  • array
  • strings
  • دالة الشرط ودالة split

لنبدا بالشرح

دالة cmdline سوف تنفذ بمجرد عمل السكربت وبعد تنفيذ كل امر.


اول شىء نطلب من المستخدم ان يكتب الامر وسوف يظل السكربت متوقف حتي الضغط علي enter وهو ايضا ما سيجعل البرنامج او السكربت في وضع التشغيل المستمر وتلقي الاوامر.

useri = input('CMD line :>')

عند ادخال البيانات من طرف المستخدم نقوم بتحويل النص الي مصفوفة array بواسطة دالة split.

x = useri.split()

فاذا ادخل المستخدم السطر التالي

-edit -id 123

سوف نجد قيمة x هي

["-edit","-id","123"]

والان لنكتب اول امر وهو امر اضافة طالب جديد وسوف نسمية -add.

بواسطة دالة الشرط نتحقق من وجود كلمة -add في متغير x[].

 if '-add' in x:

في حالة وجود كلمة -add في المصفوفة x يتم انشاء كائن بايثون كالتالي:

studObj = {
        "first_name": "",
        "last_name": "",
        "score": ""
        }

حتي نقوم بتعبئتة بالبيانات بواسطة حلقة التكرار التالية:

for k, v in studObj.items():

قمنا بعمل حلقة التكرار السابقة علي عناصر الكائن للحصول علي المفتاح والقيمة (key - value) وذالك للطباعة والتعديل علي العنصر.

مع كل تكرار يتم طباعة اسم العنصر المطلوب ونحصل علي المدخلات من المستخدم عبر input.

studObj[k] = input(k + ': ')

في السطر السابق متغير k هو مفتاح العنصر اي انه في اول حلقة تكرار يكون first_name.

بعد الخروج من حلقة التكرار نقوم باضافة كائن studObj الي نهاية كائن students.

 studFile["students"].append(studObj)

ثم تنفيذ دالة حفظ البيانات لحفظ الطالب الجديد في ملف json.

savedata()

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

customPrint(len(studFile["students"]) + 1,studObj)

len(studFile["students"]) عد عدد الطلاب وزيادة 1 لنعرف رقم الطالب الجديد.

    if '-add' in x:

        studObj = {
        "first_name": "",
        "last_name": "",
        "score": ""
        }
       
        for k, v in studObj.items():
            studObj[k] = input(k + ': ')
        studFile["students"].append(studObj)
        savedata()
        customPrint(len(studFile["students"]) + 1,studObj)

والان لنكتب امر التعديل -edit في هذا الشرط يجب وجود -id ايضا يمكن الاستغناء عنها ولكن وتركناها لتكمل بناء الامر.

if '-edit' in x:
        if '-id' in x:

اذا تحقق الشرط نقوم بعمل حلقة تكرار علي كائن الطلاب students.

for i in range(len(studFile["students"])):

داخل حلقة التكرار نضيف كائن الطالب الحالي لمتغير باسم قصير.

std = studFile["students"][i]

 ثم نتحقق اذا كان الـ id الذي ادخلة المستخدم يساوي i الحالي.

if int(x[x.index("-id") + 1]) == i:

اذا تحقق الشرط السابق نطبع كائن الطالب الحالي ثم نقوم بعمل حلقة تكرار علي عناصر كائن الطالب الحالي لتعديلها واحدة تلو الاخري.

 for k, v in std.items():

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

newdata = input('old %s : %s : new: ' % (k,v))

 اذا كانت قيمة newdata ليست فارغة يتم استبدال البيانات الجديدة بالقديمة.

if newdata != "":
    std[k] = newdata

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

savedata()
customPrint(i, std)
break

ليكون بهذا الشكل 

    if '-edit' in x:
        if '-id' in x:
            print('help[edit]: add new data and hit enter or leave empty')
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if int(x[x.index("-id") + 1]) == i:
                    print(std)
                    for k, v in std.items():
                        newdata = input('old %s : %s : new: ' % (k,v))
                        if newdata != "":
                            std[k] = newdata
                    savedata()
                    customPrint(i, std)
                    break


والان لنكتب امر عرض كل الطلاب -view

لا تحتاج لشرح فقط التحقق من كلمة -view في x وعمل حلقة تكرار علي كائن students وطباعة البيانات في كل تكرار.

    if '-view' in x:
        for i in range(len(studFile["students"])):
            std = studFile["students"][i]
            customPrint(i, std)

بعد ذالك نكتب امر البحث عن الطلاب -find.

دخل الشرط نتحقق من وجود اسم واحد علي الاقل بعد امر -find.

if len(x) < 2:
    print('help[find]: -find firstname lastname')
اذا كان يوجد اسم واحد او اكثر نقوم بعمل حلقة تكرار كما في الامر السابق وبداخلها شرطين الاول اذا كان البحث بالاسم الاول فقط والثاني اذا كان البحث بالاسم الاول والثاني.
if len(x) < 3:
   if x[1] == std["first_name"]:
      customPrint(i, std)
   elif len(x) >= 3:
       if x[1] == std["first_name"] and x[2] == std["last_name"]:
          customPrint(i, std)

    if '-find' in x:
        if len(x) < 2:
            print('help[find]: -find firstname lastname')
        else:
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if len(x) < 3:
                    if x[1] == std["first_name"]:
                        customPrint(i, std)
                elif len(x) >= 3:
                    if x[1] == std["first_name"] and x[2] == std["last_name"]:
                        customPrint(i, std)

كتابة امر حذف طالب -del يشبة امر التعديل ولكن هنا سوف نحذف كائن الطالب بالكامل بعد التاكيد علي المستخدم ثم الحفظ والخروج من حلقة التكرار في كلا الاحوال سواء تم حذف المستخدم ام لا.
confirm = input("type y to delete or c to cancel: ")
if confirm == 'y':
    del studFile["students"][i]
    savedata()
    break
else:
     break

if '-del' in x:
        if '-id' in x:
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if int(x[x.index("-id") + 1]) == i:
                    customPrint(i, std)
                    confirm = input("type y to delete or c to cancel: ")
                    if confirm == 'y':
                        del studFile["students"][i]
                        savedata()
                        break
                    else:
                        break
        else:
            print('help[delete]: -del -id number')
    else:
        cmdline()

تكرار سطر الاوامر

بعد ذالك نضع دالة سطر الاوامر في حلقة تكرار لبقاء عملها طيلة عمل النظام

while True:
    try:
        cmdline()
    except KeyboardInterrupt:
        cmdline()
    finally:
        cmdline()

ادارة النظام

سوف نقوم بادارة هذا النظام البسيط عبر الاوامر التي كتبناها سابقا.

  • -add
  • -edit
  • -view
  • -del

لاضافة طالب جديد نكتب -add ونضغط زر enter ثم نكتب بيانات الطالب بالتسلسل.

لعرض كل الطلاب نكتب -view

ولتعديل بيانات طالب نكتب

-edit -id ونكتب هنا رقم الطالب

ولحذف طالب

-del -id ونكتب رقم الطالب

وللتاكيد نضغط حر y ونضغط زر enter او c للالغاء.


والي هنا انتهي الدرس للاستفسار وطلب المساعدة ضع تعليق بالاسفل.

وشكرا للمتابعة

وهذا هو السكربت بالكامل
stud.py

import json
from os import path

dfile = './stud.json'
if path.exists(dfile):
    studFile = json.loads(open(dfile, 'r', encoding='utf-8').read())
else:
    newFile = '{"students" : []}'
    jloads = json.loads(newFile)

    with open(dfile, 'w', encoding='utf-8') as f:
        json.dump(jloads, f, ensure_ascii=False, indent=4)
        print('file created')
    studFile = json.loads(open(dfile, 'r', encoding='utf-8').read())


def savedata():
    jdumps = json.dumps(studFile)
    jloads = json.loads(jdumps)
    with open(dfile, 'w', encoding='utf-8') as f:
        json.dump(jloads, f, ensure_ascii=False, indent=4)

def customPrint(id,std):
    print('''
    id: %s
    first name: %s
    last_name: %s
    score: %s
    ------''' % (id, std["first_name"], std["last_name"], std["score"]))

def cmdline():
     
    useri = input('CMD line :>')
    commandline = useri.split()
    x = commandline
   
    if '-add' in x:

        studObj = {
        "first_name": "",
        "last_name": "",
        "score": ""
        }
       
        for k, v in studObj.items():
            studObj[k] = input(k + ': ')
        studFile["students"].append(studObj)
        savedata()
        customPrint(len(studFile["students"]) + 1,studObj)

    if '-edit' in x:
        if '-id' in x:
            print('help[edit]: add new data and hit enter or leave empty')
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if int(x[x.index("-id") + 1]) == i:
                    print(std)
                    for k, v in std.items():
                        newdata = input('old %s : %s : new: ' % (k,v))
                        if newdata != "":
                            std[k] = newdata
                    savedata()
                    customPrint(i, std)
                    break
           

    if '-view' in x:
        for i in range(len(studFile["students"])):
            std = studFile["students"][i]
            customPrint(i, std)

    if '-find' in x:
        if len(x) < 2:
            print('help[find]: -find firstname lastname')
        else:
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if len(x) < 3:
                    if x[1] == std["first_name"]:
                        customPrint(i, std)
                elif len(x) >= 3:
                    if x[1] == std["first_name"] and x[2] == std["last_name"]:
                        customPrint(i, std)
   
    if '-del' in x:
        if '-id' in x:
            for i in range(len(studFile["students"])):
                std = studFile["students"][i]
                if int(x[x.index("-id") + 1]) == i:
                    customPrint(i, std)
                    confirm = input("type y to delete or c to cancel: ")
                    if confirm == 'y':
                        del studFile["students"][i]
                        savedata()
                        break
                    else:
                        break
        else:
            print('help[delete]: -del -id number')
    else:
        cmdline()

while True:
    try:
        cmdline()
    except KeyboardInterrupt:
        cmdline()
    finally:
        cmdline()








تعليقات

التنقل السريع