Το προφίλ μας στο Google Plus
0

SQLite: Μια βάση και στα γρήγορα! [μέρος 2/2]

Στο πρώτο μέρος της μίνι σειράς μας ασχοληθήκαμε με το πιο θεωρητικό τμήμα SQLite, της περίφημης αυτής RDBMS/βιβλιοθήκης. Στο παρόν άρθρο, η λογική σειρά των πραγμάτων μάς καλεί να εφαρμόσουμε όσα μάθαμε μέχρι στιγμής στην πράξη.

Όπως ήδη είπαμε στο πρώτο μέρος της μίνι σειράς μας, κώδικα της SQLite μπορούμε να ενσωματώνουμε στις εφαρμογές μας. Κι αν δεν θέλουμε να ανακατευόμαστε με τη C επιλέγουμε κάποιον από τους wrappers που κυκλοφορούν, φέρνοντας έτσι τη λειτουργικότητα και τις δυνατότητες της SQLite στον εγγενή τρόπο διαχείρισης βάσεων δεδομένων της αγαπημένης μας γλώσσας. Σε μια προσπάθεια να ξεφύγουμε από τα παραδείγματα υλοποίησης web εφαρμογών και να σας αποδείξουμε ότι η SQLite δεν περιορίζεται μόνο σ’ αυτά τα περιβάλλοντα, αλλά κάνει και για την ανάπτυξη desktop προγραμμάτων, θα γράψουμε σε Python μια μικρή εφαρμογή διαχείρισης των όποιων domains έχουμε στην κατοχή μας. Στην εν λόγω εφαρμογή, η οποία θα λειτουργεί σε περιβάλλον κονσόλας κειμένου, θα εισάγουμε τα στοιχεία των domains μας: όνομα domain, καταχωρητής (registrar), name servers που το εξυπηρετούν, ημερομηνία λήξης και κόστος.

Ας ξεκινήσουμε από τη βάση. Θα χρειαστεί να κατασκευάσουμε έναν πίνακα με την ακόλουθη δομή:

==================================================
Πίνακας domains
==================================================
Πεδίο		|	Τύπος
--------------------------------------------------
id			|	INTEGER <-- primary key
domain		|	TEXT
registrar	|	TEXT
dns1		|	TEXT
dns2		|	TEXT
renew_date	|	TEXT
cost		| 	FLOAT
--------------------------------------------------

Για την υλοποίηση της βάσης μπορούμε να καταφύγουμε σε πάμπολλες μεθόδους, δύο από τις οποίες είδαμε στο πρώτο μέρος της μίνι σειράς μας. Η πρώτη είναι με τη χρήση του εργαλείου κονσόλας slqite3, η δεύτερη με τη χρήση του εργαλείου web UI ονόματι phpLiteAdmin. Επιδεικτικά κι ευθαρσώς αγνοούμε αμφότερες τις μεθόδους και φροντίζουμε ώστε η δημιουργία του πίνακα να γίνεται μέσα από το ίδιο το πρόγραμμά μας! Από τη μια επιθυμούμε να εξασκηθούμε στη χρήση της SQLite μέσω Python, από την άλλη θέλουμε η εφαρμογή μας να έχει μια εσάνς “αυτοΐασης”. Πιο συγκεκριμένα, όταν για οποιονδήποτε λόγο δεν βρίσκεται η βάση, αντί η εφρμογή μας να κρεμάει θα την αναδημιουργεί. Ίσως τώρα αναρωτιέστε πόσο δύσκολο είναι να υλοποιηθεί κάτι τέτοιο. Σας πληροφορούμε ότι δεν είναι καθόλου δύσκολο. Και για του λόγου το αληθές, ας πάμε να εξετάσουμε αποσπασματικά τον κώδικά μας.

import sqlite3
import os.path
import datetime
from dateutil.relativedelta import relativedelta
 
DB_NAME = "domains.db"
titles = ("Domain","Registrar","Primary DNS","Secondary DNS","Renewal Date","Cost")
max_titles_len = len(max(titles, key=len))

Για αρχή εισάγουμε τις απαραίτητες βιβλιοθήκες, στοιχεία των οποίων θα αξιοποιήσουμε στο συγκεκριμένο project μας. Η πρώτη απ’ αυτές είναι η sqlite3, η οποία δίνει πρόσβαση στα στοιχεία διαχείρισης του ομώνυμου συστήματος. Η δεύτερη είναι η os.path. Θα μας φανεί χρήσιμη για την υλοποίηση της λεγόμενης μεθόδου “αυτοΐασης”. H τρίτη βιβλιοθήκη θα μας χρησιμεύσει για τη διαχείριση των ημερομηνιών. Η τελευταία, με το ομώνυμο αντικείμενο, μας παρέχει πολύ μεγάλη ευελιξία στη διαχείριση των δεδομένων μεταξύ ημερομηνιών.

Κατόπιν της εισαγωγής των βιβλιοθηκών, αρχικοποιούμε κάποιες μεταβλητές. Η DB_NAME, την οποία θα χρησιμοποιήσουμε στη συνέχεια ως σταθερά, επιστρέφει τη διαδρομή προς το αρχείο που αποτελεί τη βάση δεδομένων. Αν δεν ορίσουμε μονοπάτι, αυτό νοείται ως ο τρέχων φάκελος μέσα στον οποίο βρίσκεται το πρόγραμμά μας. Στην επόμενη γραμμή, σε ένα tuple ορίζουμε μια σειρά λεκτικών που θα χρησιμοποιήσουμε σε διάφορες από τις μεθόδους μας. Όπως ίσως θα διαπιστώσατε ήδη, αφορούν στους τίτλους των πεδίων του μοναδικού πίνακα της βάσης μας. Στην τελευταία γραμμή του αποσπάσματος, χρησιμοποιώντας τη μέθοδο max εντοπίζουμε το μεγαλύτερο σε μήκος μέλος του tuple — και σε συνδυασμό με τη συνάρτηση len βρίσκουμε το μήκος αυτό. Ίσως εύλογα να απορείτε για το λόγο που μπαίνουμε σε μια τέτοια διαδικασία. Η αλήθεια είναι πως επιθυμούμε να έχουμε ένα όμορφο οπτικά αποτέλεσμα στην κονσόλα μας, οπότε το μέγεθος αυτό θα μας βοηθήσει να στοιχίσουμε σωστά τα στοιχεία στην οθόνη.

def init():
    if not os.path.exists(DB_NAME):
        conn = sqlite3.connect(DB_NAME)
        curs = conn.cursor()
        curs.execute("CREATE TABLE domains(id INTEGER PRIMARY KEY, domain TEXT, registrar TEXT, dns1 TEXT, dns2 TEXT, renew_date TEXT, cost FLOAT)")
        curs.close()
    print "myDomains management system - A pythonic sqlite example\nCopyright (c) 2016, Petros Kyladitis <multipetros.gr>\n\n"
    mainloop()

Στη γραμμή 10 ξεκινά η αρχική συνάρτηση της εφαρμογής μας, η οποία είναι και υπεύθυνη για την αναδημιουργία της βάσης δεδομένων σε περίπτωση που αυτή δεν εντοπιστεί. Στην γραμμή 11 γίνεται ο σχετικός έλεγχος ύπαρξης του αρχείου της βάσης. Αν δεν βρεθεί, δημιουργούμε ένα αντικείμενο Connection της sqlite παρέχοντάς του τη σχετική διαδρομή της βάσης. Απ’ αυτό στη συνέχεια λαμβάνουμε ένα αντικείμενο Cursor, μέσω του οποίου θα χειριστούμε τη βάση μας εκτελώντας εντολές SQL και λαμβάνοντας τα αποτελέσματα της εκτέλεσής τους. Στη γραμμή 014 βλέπουμε την εκτέλεση μιας εντολής SQL για τη δημιουργία του πίνακα της βάσης μας, με τη χρήση της μεθόδου execute. Στη συνέχεια κλείνουμε τη σύνδεση του αντικειμένου Cursor με τη βοήθεια της μεθόδου close(). Προς το τέλος τώρα της συνάρτησής μας –κι ανεξαρτήτως της δημιουργίας ή όχι της βάσης–, εμφανίζουμε ένα μήνυμα με πληροφορίες για την εφαρμογή και καλούμε τη συνάρτηση mainloop(), η οποία είναι το βασικό μενού του προγράμματός μας.

 
def add_domain():
    print "Enter domain details. You can cancel the input by entering '.c'"
    details = ""
    details_data = [] 
    for i in range(6):
        while details == "":
            details = raw_input( titles[i].ljust( max_titles_len+2, ".") + ": "
        if details == ".c":
            return
        details_data.append(details)
        details = ""
    conn = sqlite3.connect(DB_NAME)
    curs = conn.cursor()
    curs.execute("INSERT INTO domains (id, domain, registrar, dns1, dns2, renew_date, cost) VALUES (null, ?, ?, ?, ?, ?, ?)", tuple(details_data))
    conn.commit()
    curs.close()

Ας περάσουμε τώρα στην add_domain(), το όνομα της οποίας μας προϊδεάζει ότι πρόκειται για τη συνάρτηση καταχώρισης ενός νέου domain στη βάση. Αρχικά εμφανίζουμε μια προτροπή προς τον χρήστη για την εισαγωγή των δεδομένων, η οποία μπορεί να διακοπεί δίνοντας το λεκτικό “.c” (χωρίς τα εισαγωγικά). Παλιομοδίτικος τρόπος χειρισμού, όμως στην περίπτωση του παραδείγματός μας λειτουργεί ικανοποιητικά. Στη γραμμή 22 έχουμε τη μεταβλητή details, την οποία αρχικοποιούμε εκχωρώντας της μια κενή συμβολοσειρά. Αυτή θα τη χρησιμοποιήσουμε προκειμένου να λαμβάνουμε την είσοδο του χρήστη, την οποία θα προσαρτούμε κάθε φορά στο τέλος του πίνακα details_data. Για καθένα λοιπόν από τα στοιχεία του πίνακα (έξι στο σύνολο), εκτελούμε το βρόχο που ξεκινά στη γραμμή 024 κι εμφανίζουμε μια σχετική προτροπή εισαγωγής δεδομένων, η οποία αποτελείται από τον τίτλο του εκάστοτε πεδίου στοιχισμένο σύμφωνα με το μήκος του μεγαλύτερου απ’ αυτά, όπως το βρήκαμε στη συνάρτηση init() και το αποθηκεύσαμε στη μεταβλητή max_titles_len. Για να πραγματοποιηθεί η στοίχιση χρησιμοποιούμε τη συνάρτηση ljust(), η οποία δέχεται ως παράμετρο το ελάχιστο μήκος που θέλουμε να έχει η συμβολοσειρά στην οποία την εφαρμόζουμε, καθώς και μια προαιρετική μεταβλητή με τον χαρακτήρα που θέλουμε να συμπληρώσει από τα δεξιά τη συμβολοσειρά ώστε να φτάσει στο επιθυμητό μήκος. Αν δεν δώσουμε αυτή τη δεύτερη μεταβλητή, τότε από προεπιλογή η συμβολοσειρά μας θα συμπληρωθεί με κενά. Προσέξτε ότι την εισαγωγή των δεδομένων την κλείνουμε σε ένα βρόχο, ο οποίος εκτελείται όσο η μεταβλητή details είναι μια κενή συμβολοσειρά. Όπως ίσως ήδη θα έχετε καταλάβει, ο βρόχος αυτός μπαίνει ώστε να αποτρέψουμε το χρήστη από την εισαγωγή κενών δεδομένων. Εντός του βρόχου τώρα, στη γραμμή 027, πραγματοποιούμε έλεγχο για το αν η συμβολοσειρά που εισήγαγε ο χρήστης είναι η συμβολοσειρά ακύρωσης της εισαγωγής. Αν είναι, τότε η συνάρτηση επιστρέφει άμεσα και η ροή του προγράμματος συνεχίζεται στον κεντρικό βρόχο/μενού. Αν η εισαγωγή των δεδομένων ολοκληρωθεί επιτυχώς, τότε αναλαμβάνουν δράση τα αντικείμενα της βιβλιοθήκης sqlite3. Όπως και στην init(), δημιουργούμε ένα Connection στο οποίο συνδέουμε το αρχείο της βάσης μας. Εξ’ αυτού λαμβάνουμε ένα Cursor, με τη βοήθεια του οποίου στη γραμμή 033 εκτελούμε ένα ερώτημα εισαγωγής στον πίνακα domains της βάσης. Αξίζει να προσέξετε ότι το ερώτημα που εκτελούμε δεν το δημιουργούμε με την κλασική μέθοδο της συνένωσης γραμματοσειράς, αλλά με τη χρήση παραμέτρων. Συγκεκριμένα, τα αγγλικά ερωτηματικά αντικαθίστανται από τη μέθοδο, με τις τιμές του tuple, με τη σειρά που υπάρχουν σ’ αυτό. Κάτι τέτοιο μας εξυπηρετεί στην περίπτωση που η σειρά των δεδομένων του tuple είναι ίδια με αυτή των παραμέτρων που θέλουμε να περάσουμε στο ερώτημα. Στην περίπτωση που αυτή ήταν μπερδεμένη, μπορούσαμε πάλι να χρησιμοποιήσουμε παραμέτρους αλλά ονομαστικές αυτή τη φορά, χρησιμοποιώντας αντί του tuple ένα λεξικό. Παράδειγμα:

curs.execute("INSERT INTO domains (id, domain, registrar, dns1, dns2, renew_date, cost)
VALUES (null, :id, :domain, :registrar, :dns1, :dns2, :renew_date, :cost)", {"id": details_data[0],
"domain": details_data[1], "registrar": details_data[2], "dns1": details_data[3], "dns2": details_data[4], 
"renew_date": details_data[5], "cost": details_data[6] })

Μετά την εκτέλεση του ερωτήματος, προσέξτε τη χρήση της συνάρτησης commit(). Αυτή είναι απαραίτητη σε ερωτήματα που τροποποιούν τα δεδομένα της βάσης (εκτός της δημιουργίας πινάκων), ώστε αυτά να γραφτούν στο αρχείο. Αν καλέσουμε τη συνάρτηση close(), προτού κάνουμε commit, παρότι το ερώτημά μας θα έχει εκτελεστεί επιτυχώς τα δεδομένα δεν θα γραφτούν στο αρχείο. Ίσως θυμάστε από το προηγούμενο άρθρο μας ότι η SQLite υποστηρίζει συναλλαγές, εξ ου και η αναγκαιότητα της χρήσης του commit.

def del_domain():
    domain = ""
    while domain == "":
        domain = raw_input("Domain to delete: ")
    if domain == ".c":
        return
    conn = sqlite3.connect(DB_NAME)
    curs = conn.cursor()
    curs.execute("DELETE FROM domains WHERE domain='" + domain + "'")
    if curs.rowcount > 0:
        print "\nDomain '" + domain + "' deleted!"
    else:
        print "\n'" + domain + "' not found! Nothing deleted."
    curs.close()

Συνεχίζοντας, στη συνάρτηση del_domain(), την οποία χρησιμοποιούμε για να διαγράψουμε μια καταχώριση από τη βάση μας, δε θα εντοπίσουμε σημαντικές διαφορές στη λογική μας σε σχέση με τη μέθοδο add_domain(). Εδώ, αντί να ζητούμε πλήρη στοιχεία, παίρνουμε από τον χρήστη το όνομα του domain και με βάση αυτό εκτελούμε ένα ερώτημα διαγραφής. Για την εκτέλεση του ερωτήματος δεν χρησιμοποιούμε παραμέτρους, αλλά συνθέτουμε απευθείας τη συμβολοσειρά του ερωτήματος. Τέλος, στη γραμμή 046 εκτελούμε έναν έλεγχο της ιδιότητας rowcount, του αντικειμένου Cursor. Η συγκεκριμένη ιδιότητα επιστρέφει το πλήθος των στοιχείων που επηρεάστηκαν από την εκτέλεση του ερωτήματος. Αν λοιπόν αυτή έχει τιμή μεγαλύτερη από 0, τότε εμφανίζουμε ένα μήνυμα επιτυχούς διαγραφής. Διαφορετικά, επειδή το πιθανότερο είναι να μην υπήρχε το domain, εμφανίζουμε ένα σχετικό μήνυμα.

def edit_domain():
    conn = sqlite3.connect(DB_NAME)
    curs = conn.cursor()
    domain = ""
    while domain == "":
        domain = raw_input("Domain to edit: ")
        if domain == ".c":
            return
        else:
            curs.execute("SELECT id, domain, registrar, dns1, dns2, renew_date, cost FROM domains WHERE domain='" + domain + "'")
            domain_data = curs.fetchone()
            if domain_data is None :
                print "Domain '" + domain + "' not found!"
                domain = ""
    details = ""
    details_data = []   
    print "Enter new data, or leave it blank to keep the existing values"
    for i in range(1,7):
        details = raw_input(titles[i-1].ljust(max_titles_len+1) + "[" + str(domain_data[i]) + "]: ")
        if details == "":
            details = domain_data[i]
        if details == ".c":
            return
        details_data.append(details)
    details_data.append(domain_data[0])
    curs.execute("UPDATE domains SET domain=?, registrar=?, dns1=?, dns2=?, renew_date=?, cost=? WHERE id=?", tuple(details_data))
    conn.commit()
    curs.close()

Η συνάρτηση edit_domain(), ρόλος της οποίας είναι η επεξεργασία μιας υπάρχουσας εγγραφής, έχει λίγο μεγαλύτερη έκταση από τις υπόλοιπες. Αυτό είναι φυσικό, αφού με μια προσεκτική ματιά μπορούμε να διαπιστώσουμε ότι γίνονται δύο αλληλεπιδράσεις με τη βάση. Αρχικά εκτελούμε ένα ερώτημα επιλογής, όπου το ζητούμενο αντικείμενο είναι τα στοιχεία για το domain που εισάγει ο χρήστης. Τα στοιχεία αυτά αποθηκεύονται σε έναν πίνακα με όνομα domains_data, αξιοποιώντας τη μέθοδο fetchone() από το αντικείμενο Cursor, η οποία επιστρέφει το πρώτο από τη λίστα των αποτελεσμάτων εκτέλεσης της εντολής select. Στη συνέχεια, στη γραμμή 069, ξεκινάμε έναν βρόχο προτρέποντας τον χρήστη να εισάγει τα νέα στοιχεία για το συγκεκριμένο domain. Αξιοποιώντας τα δεδομένα που αντλήσαμε γι’ αυτό μαζί με τις προτροπές, εμφανίζουμε και τις τρέχουσες τιμές των στοιχείων. Σε αντίθεση με τις άλλες συναρτήσεις, η εισαγωγή κενής συμβολοσειράς λαμβάνει την έννοια τις διατήρησης των υπαρχόντων δεδομένων. Τα δεδομένα αυτά, ένα προς ένα τοποθετούνται στην ουρά του πίνακα details_data με τη βοήθεια της συνάρτησης append. Παρατηρείστε ότι μετά το πέρας του βρόχου εισάγουμε στο τέλος του πίνακα ένα ακόμα στοιχείο, το id της συγκεκριμένης εγγραφής. Δεν είναι τυχαία η επιλογή της θέσης, καθώς αμέσως μετά, στη γραμμή 077 εκτελούμε το ερώτημα με τη βοήθεια των παραμέτρων και των ερωτηματικών, αξιοποιώντας ένα tuple το οποίο φτιάχνουμε από τον πίνακα details_data με τη βοήθεια της συνάρτησης μετατροπής tuple().

def search_domain():
    domain = ""
    while domain == "":
        domain = raw_input("Domain to show: ")
        print "\n"
    if domain == ".c":
        return
    conn = sqlite3.connect(DB_NAME)
    curs = conn.cursor()
    curs.execute("SELECT domain, registrar, dns1, dns2, renew_date, cost FROM domains WHERE domain='" + domain + "'")
    entry = curs.fetchone()
    if entry is None :
        print "Domain '" + domain + "' not found!"
    else:
        for i in range(6):
            if i != 4:
                print titles[i].ljust(max_titles_len+2, ".") + ": " +  str(entry[i])
            else:
                today = datetime.date.today()
                endday = datetime.datetime.strptime(entry[i], "%Y-%m-%d")
                rd = relativedelta(endday, today)
                time_left = " [%(years)d years, %(months)d months, %(days)d days left]" % rd.__dict__
                print titles[i].ljust(max_titles_len+2, ".") + ": "  +  str(entry[i]) + time_left
    curs.close()

Σειρά στις συναρτήσεις που εξετάζουμε έχει η search_domain(), μια συνάρτηση αναζήτησης κι εμφάνισης πληροφοριών ενός domain. Η αναζήτηση γίνεται με τον γνωστό πλέον τρόπο εκτέλεσης ερωτημάτων επιλογής και, στην περίπτωση που βρεθεί η ζητούμενη καταχώριση, εμφανίζονται ένα προς ένα τα στοιχεία του domain. Μια ιδιαιτερότητα αφορά στο στοιχείο της ημερομηνίας λήξης του domain, όπου προς διευκόλυνση των χρηστών της εφαρμογής μας υπολογίζουμε το χρονικό διάστημα που απομένει ως τη λήξη αυτού. Για τον υπολογισμό του χρησιμοποιούμε τη μεταβλητή today, στην οποία αποθηκεύουμε ένα αντικείμενο date με τη τρέχουσα ημερομηνία. Για τη μεταβλητή endday, η οποία αφορά στην ημερομηνία λήξης του domain, δημιουργούμε ένα αντικείμενο date από τη συμβολοσειρά που είναι αποθηκευμένη στη βάση, στη μορφή “ΕΕΕΕ-ΜΜ-ΗΗ” κι αξιοποιώντας τη συνάρτηση μετατροπής strptime(). Στη συνέχεια, στη γραμμή 101, δημιουργούμε ένα αντικείμενο relativedelta, για τον υπολογισμό τις χρονικής διαφοράς αρχικοποιώντας το με τις δύο παραπάνω μεταβλητές. Τέλος, στην επόμενη γραμμή, εξάγουμε τα δεδομένα του δημιουργηθέντος αντικειμένου relativedelta με τη βοήθεια της ιδιότητας dict και τις τοποθετούμε συνδυαστικά σε μια συμβολοσειρά που πληροφορεί το χρήστη για τα χρόνια, τους μήνες και τις μέρες που απομένουν έως τη λήξη του domain.

 
def list_domain():
    conn = sqlite3.connect(DB_NAME)
    curs = conn.cursor()
    curs.execute("SELECT domain, registrar, dns1, dns2, renew_date, cost FROM domains ORDER BY renew_date ASC")
    rows = curs.fetchall()
    if rows is None :
        print "No domain found!"
    else:
        max_cols_len = []
        for title in titles:
            max_cols_len.append(len(title))
        for row in rows:
            for i in range(len(row)):
                if max_cols_len[i] < len(str(row[i])):
                    max_cols_len[i] = len(str(row[i]))
        line = ""
        for i in range(len(titles)):
            line = line + titles[i].ljust(max_cols_len[i]+2)
        print line
        print '='*len(line)
        for row in rows:
            line = ""
            for i in range(len(row)):
                if i != 5:
                    line = line + row[i].ljust(max_cols_len[i]+2)
                else:
                    line = line + str(row[i]).rjust(max_cols_len[i])
            print line

Επόμενη συνάρτηση είναι η list_domain, σκοπός της οποίας είναι η εμφάνιση μιας λίστας με όλα τα καταχωρημένα domains, μαζί φυσικά με τις πληροφορίες τους. Το ερώτημα που εκτελούμε συλλέγει όλες τις εγγραφές του πίνακα, παρατάσσοντάς τες κατά την ημερομηνία λήξης σε αύξουσα σειρά. Εδώ, αντί της fetchone καλούμε τη συνάρτηση fetchall, η οποία φέρνει όλα τα αποτελέσματα της εκτέλεσης του ερωτήματος σε έναν πολυδιάστατο πίνακα. Με τη βοήθεια τριών βρόχων, στις γραμμές 115, 117 και 118, βρίσκουμε το μέγιστο μήκος για τη κάθε στήλη του πίνακά μας, εξετάζοντας τους τίτλους καθώς κι όλα τα αποτελέσματα. Το μέγιστο μήκος το αποθηκεύουμε στον πίνακα max_cols_len και το αξιοποιούμε στη συνέχεια για να στοιχίσουμε τ’ αποτελέσματα με την ljust. Τα αποτελέσματα τα ανακαλούμε εκ νέου, λίγο παρακάτω, με τη βοήθεια δύο βρόχων, η αρχή των οποίων φαίνεται στις γραμμές 126 και 128.

def mainloop():
    action = ""
    cmds_msg = "  Action commands\n===================\nAdd new domain  [a]\nEdit a domain   [e]\nDelete a domain [d]\nSearch domain   [s]\nDomains list    [l]\nQuit program    [q]"
    while action != "q":
        print cmds_msg
        action = raw_input("Action.........: ")
        print "\n"
        if action == "a":
            add_domain()
            raw_input("> ")
        elif action == "e":
            edit_domain()
            raw_input("> ")
        elif action == "d":
            del_domain()
            raw_input("> ")
        elif action == "s":
            search_domain()
            raw_input("> ")
        elif action == "l":
            list_domain()
            raw_input("> ")
        print "\n"
    print "Thanks for reading deltaHacker!"
    exit

if __name__ == "__main__":
    init()

Η τελευταία συνάρτηση που θα εξετάσουμε αποτελεί τον κεντρικό βρόχο του προγράμματος — ή αλλιώς το βασικό του μενού. Πολύ απλά, εμφανίζει μια σειρά επιλογών και στη συνέχεια αναμένει την είσοδο του χρήστη. Ξεκινάει μια σειρά ελέγχων, όπου εξετάζεται αν η είσοδος είναι κάποια από τις προβλεπόμενες τιμές κι αν ναι τότε καλείται η σχετική μέθοδος.

Όλα όσα παρουσιάσαμε επιδέχονται βελτιώσεις και δεν αποτελούν το πιο απλό παράδειγμα. Πιστεύουμε όμως ότι η παρουσίασή μας είναι μια άριστη ευκαιρία ώστε να εξοικειωθούμε με τη χρήση βάσεων δεδομένων σε εφαρμογές μας, χωρίς την ανάγκη για παρουσία server. Όπως πάντα σας προτρέπουμε να πειραματιστείτε άφοβα, δοκιμάζοντας όχι μόνο να τροποποιήσετε αλλά και να μεταφέρετε το πρότζεκτ με τα domains στις αγαπημένες σας γλώσσες προγραμματισμού, όποιες κι αν είναι αυτές. Σε κάθε περίπτωση, ολόκληρο τον κώδικα του παρόντος άρθρου θα τον βρείτε στο http://bit.ly/dH056mydomains. Καλή σας διασκέδαση!

Κατά την έναρξη του προγράμματος εμφανίζεται ένα μήνυμα καλωσορίσματος και φυσικά το κεντρικό μενού επιλογών. Ίσως σας φαίνεται παλιομοδίτικη προσέγγιση, εμάς πάντως μας αρέσει πολύ αυτός ο ρετρό χαρακτήρας.

Κατά την έναρξη του προγράμματος εμφανίζεται ένα μήνυμα καλωσορίσματος και φυσικά το κεντρικό μενού επιλογών. Ίσως σας φαίνεται παλιομοδίτικη προσέγγιση, εμάς πάντως μας αρέσει πολύ αυτός ο ρετρό χαρακτήρας.

Προσθέτοντας ένα νέο --κι εντελώς τυχαίο-- domain.

Προσθέτοντας ένα νέο –κι εντελώς τυχαίο– domain.

Η λειτουργία αναζήτησης επιστρέφει άμεσα τα αποτελέσματα στην οθόνη μας, καθώς και το χρονικό διάστημα έως την επόμενη ανανέωση του domain (σε χρήσιμη μορφή).

Η λειτουργία αναζήτησης επιστρέφει άμεσα τα αποτελέσματα στην οθόνη μας, καθώς και το χρονικό διάστημα έως την επόμενη ανανέωση του domain (σε χρήσιμη μορφή).

Μετά την αλλαγή καταχωρητή, επεξεργαστήκαμε και τις ήδη καταχωρημένες πληροφορίες για το domain μας.

Μετά την αλλαγή καταχωρητή, επεξεργαστήκαμε και τις ήδη καταχωρημένες πληροφορίες για το domain μας.

Leave a Reply

You must be logged in to post a comment.

Σύνδεση

Αρχείο δημοσιεύσεων