Γράφοντας το πρώτο σας Django app, μέρος 2

Ο οδηγός αυτός ξεκινά εκεί που τελειώνει ο οδηγός 1. Εδώ, θα ασχοληθούμε με τις ρυθμίσεις της βάσης δεδομένων, θα δημιουργήσουμε το πρώτο μας μοντέλο και θα κάνουμε μια μικρή εισαγωγή στο διαχειριστικό site (admin site) του Django, το οποίο δημιουργείται αυτόματα.

Που να ψάξετε για βοήθεια

If you’re having trouble going through this tutorial, please head over to the Getting Help section of the FAQ.

Ρύθμιση της Βάσης Δεδομένων

Στον προηγούμενο οδηγό δεν ασχοληθήκαμε καθόλου με το αρχείο mysite/settings.py παρόλο που είπαμε ότι αποτελεί την καρδιά ενός project. Το αρχείο αυτό αποτελεί ένα κοινό Python module στου οποίου οι μεταβλητές (variables) αναπαριστούν τις ρυθμίσεις του Django. Ανοίξτε το αρχείο αυτό.

Προεπιλεγμένα, οι ρυθμίσεις αφορούν την βάση δεδομένων SQLite. Αν είστε νέος στις βάσεις δεδομένων ή απλά ενδιαφέρεστε στο να δοκιμάσετε το Django, τότε αυτή είναι η πιο εύκολη επιλογή. Η SQLite περιλαμβάνεται στην Python, με αποτέλεσμα να μην χρειάζεται να εγκαταστήσετε τίποτε άλλο για να υποστηρίξετε την βάση δεδομένων σας. Όταν ξεκινήσετε το πρώτο σας πραγματικό project, ωστόσο, ίσως χρειαστεί να χρησιμοποιήσετε από την αρχή μια πιο εύρωστη (robust) βάση δεδομένων όπως η PostgreSQL, για να αποφύγετε τυχόν πονοκεφάλους που θα προκύψουν κατά την αλλαγή βάσεων δεδομένων (από SQLite στην PostgreSQL) στο μέλλον.

Αν επιθυμείτε να χρησιμοποιήσετε διαφορετική βάση δεδομένων από την SQLite, εγκαταστήστε πρώτα τις κατάλληλες βιβλιοθήκες βάσης δεδομένων και μετά αλλάξτε τα ακόλουθα keys στη ρύθμιση DATABASES 'default' ούτως ώστε να ταιριάζουν με τη δική σας σύνδεση στη βάση δεδομένων:

  • ENGINE – Είτε 'django.db.backends.sqlite3', 'django.db.backends.postgresql', 'django.db.backends.mysql', ή 'django.db.backends.oracle'. Άλλα backends είναι επίσης διαθέσιμα.
  • NAME – Το όνομα της βάσης δεδομένων σας. Αν χρησιμοποιείτε την SQLite, το όνομα της βάσης θα είναι το ίδιο με το όνομα του αρχείου στον υπολογιστή σας. Σε αυτή την περίπτωση, το NAME θα είναι το πλήρες μονοπάτι (path) συμπεριλαμβανομένου και του ονόματος+κατάληξη του αρχείου. Η προεπιλεγμένη τιμή, os.path.join(BASE_DIR, 'db.sqlite3'), θα αποθηκεύσει το αρχείο στο root φάκελο του project σας.

Αν δεν χρησιμοποιείτε την SQLite, τότε θα πρέπει να δηλώσετε επιπρόσθετα στοιχεία όπως USER, PASSWORD και HOST. Για περισσότερες πληροφορίες, δείτε στην αντίστοιχη ενότητα του εγχειριδίου (documentation) σχετικά με DATABASES.

Για βάσεις δεδομένων πλην της SQLite

Αν χρησιμοποιείτε βάση δεδομένων διαφορετική από την SQLite, σιγουρευτείτε ότι έχετε δημιουργήσει κάποια βάση πριν προχωρήσετε. Κάντε το με την εντολή «CREATE DATABASE database_name;» μέσα από την interactive κονσόλα της βάσης δεδομένων σας.

Επίσης σιγουρευτείτε ότι ο χρήστης (user) που δηλώσατε στην ρύθμιση USER στο αρχείο mysite/settings.py έχει δικαιώματα «create database». Αυτό θα μας επιτρέψει την αυτόματη δημιουργία μιας test database η οποία θα μας χρειαστεί αργότερα στον οδηγό.

Αν χρησιμοποιείτε την SQLite, δεν χρειάζεται να δημιουργήσετε τίποτα εκ των προτέρων. Το αρχείο της βάσης δεδομένων θα δημιουργηθεί αυτόματα όταν χρειαστεί.

Όσο επεξεργάζεστε το αρχείο mysite/settings.py, θέστε τη ρύθμιση TIME_ZONE στη δική σας ζώνη ώρας (π.χ για την Ελλάδα αυτό θα γίνει 'Europe/Athens').

Επίσης, σημειώστε τη ρύθμιση INSTALLED_APPS στην αρχή του αρχείου. Αυτή η ρύθμιση κρατάει τα ονόματα όλων των Django applications που θα ενεργοποιηθούν κατά τη λειτουργία του Django (με άλλα λόγια αυτά που θα είναι διαθέσιμα). Τα apps μπορουν να χρησιμοποιηθούν σε πολλαπλά projects και μπορείτε επίσης να τα πακετάρετε και να τα διανέμετε για χρήση από άλλους χρήστες στα δικά τους projects.

Από προεπιλογή, η ρύθμιση INSTALLED_APPS περιέχει τα ακόλουθα apps, όπου όλα έρχονται προεγκατεστημένα με το Django:

Αυτά τα applications συμπεριλαμβάνονται στο Django ως διευκόλυνση καθώς χρησιμοποιούνται όλα συνήθως.

Επιπροσθέτως, μερικά από αυτά τα applications χρειάζονται τουλάχιστον έναν πίνακα στη βάση δεδομένων (database table). Για το λόγο αυτό, θα πρέπει να δημιουργήσουμε αυτούς του πίνακες στη βάση μας, πριν ξεκινήσουμε να τα χρησιμοποιούμε. Για να το κάνετε αυτό, τρέξτε την ακόλουθη εντολή (από κονσόλα και ευρισκόμενοι στο root φάκελο του project σας):

$ python manage.py migrate
...\> py manage.py migrate

The migrate command looks at the INSTALLED_APPS setting and creates any necessary database tables according to the database settings in your mysite/settings.py file and the database migrations shipped with the app (we’ll cover those later). You’ll see a message for each migration it applies. If you’re interested, run the command-line client for your database and type \dt (PostgreSQL), SHOW TABLES; (MariaDB, MySQL), .schema (SQLite), or SELECT TABLE_NAME FROM USER_TABLES; (Oracle) to display the tables Django created.

Για τους μινιμαλιστές

Όπως είπαμε παραπάνω, οι προεπιλεγμένες εφαρμογές περιλαμβάνονται επειδή χρησιμοποιούνται συχνά, αλλά δεν τις χρειάζονται όλοι. Αν δεν χρειάζεστε κάποια ή καμία από αυτές, μπορείτε ελεύθερα να τις ορίσετε ως σχόλιο ή να διαγράψετε την αντίστοιχη γραμμή (γραμμές) από τη ρύθμιση INSTALLED_APPS πριν τρέξετε την εντολή migrate. Η djadmin:migrate θα τρέξει τα migrations μόνο για τις εφαρμογές που βρίσκονται στη ρύθμιση INSTALLED_APPS (και φυσικά δεν είναι σχόλια).

Δημιουργώντας τα μοντέλα

Σε αυτό το στάδιο θα ορίσουμε τα μοντέλα – κατ” ουσίαν, το layout της βάσης δεδομένων, με μερικά πρόσθετα metadata.

Φιλοσοφία

Ένα μοντέλο είναι η μοναδική και απόλυτη πηγή των πραγματικών δεδομένων σας. Περιέχει τα ουσιώδη χαρακτηριστικά (πεδία) και συμπεριφορές (μέθοδοι) των δεδομένων που αποθηκεύετε. Το Django ακολουθεί την αρχή του DRY. Ο στόχος είναι να ορίσετε (δηλώσετε) τα μοντέλα σας σε ένα μέρος και αυτόματα να αντλείτε πράγματα από εκεί.

This includes the migrations - unlike in Ruby On Rails, for example, migrations are entirely derived from your models file, and are essentially a history that Django can roll through to update your database schema to match your current models.

In our poll app, we’ll create two models: Question and Choice. A Question has a question and a publication date. A Choice has two fields: the text of the choice and a vote tally. Each Choice is associated with a Question.

These concepts are represented by Python classes. Edit the polls/models.py file so it looks like this:

polls/models.py
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

Here, each model is represented by a class that subclasses django.db.models.Model. Each model has a number of class variables, each of which represents a database field in the model.

Κάθε πεδίο αναπαρίσταται από ένα instance της Field class – π.χ, η κλάση CharField δηλώνει πεδίο χαρακτήρων ενώ η κλάση DateTimeField δηλώνει πεδίο για ημερομηνίες. Αυτό λέει στο Django τον τύπο των δεδομένων που θα διατηρεί κάθε πεδίο. Με αυτό τον τρόπο, δηλαδή, χτίζουμε το schema της database μας. Τα δύο αυτά μοντέλα είναι στην ουσία δύο πίνακες στην βάση δεδομένων, τα attributes τους είναι οι στήλες στον εκάστοτε πίνακα και ο τύπος των δεδομένων που θα κρατάει κάθε στήλη δηλώνεται με τα instances της κλάσης Field. Βεβαίως κάθε instance της κλάσης Field δέχεται κάποια ορίσματα (όπως, πχ, το μέγιστο αριθμό χαρακτήρων που θα μπορεί να κρατάει κάθε ερώτηση κλπ) τα οποία θέτουν κάποια επιπλέον χαρακτηριστικά (άλλα είναι απαραίτητα, άλλα προαιρετικά).

Το όνομα κάθε Field instance (π.χ``question_text`` ή pub_date) αποτελεί και το όνομα του field , σε μια φιλική προς τη μηχανή μορφή. Θα τη χρησιμοποιήσετε αυτή την τιμή όποτε αναφέρεστε σε αυτή τη στήλη στον Python κώδικα σας ενώ το ίδιο όνομα θα χρησιμοποιηθεί ως όνομα στήλης στην βάση δεδομένων.

Μπορείτε να χρησιμοποιήσετε ένα προαιρετικό πρώτο positional argument στη κλάση Field για να καθορίσετε το όνομα του για τον χρήστη (όχι για τη μηχανή, όπως πριν). Αυτό χρησιμοποιείται σε μερικά εσωτερικά μέρη του Django και βοηθάει στο να αναγνωρίζει κανείς το πεδίο αυτό. Αν αυτό το πεδίο δεν οριστεί τότε το Django θα χρησιμοποιήσει τη μορφή για τη μηχανή. Σε αυτό το παράδειγμα, έχουμε ορίσει το φιλικό-προς-τον-χρήστη όνομα μόνο για το πεδίο Question.pub_date. Για όλα τα υπόλοιπα πεδία αυτού του μοντέλου (Question.question_text) θα χρησιμοποιηθεί το φιλικό-προς-τη-μηχανή όνομα.

Όπως είπαμε παραπάνω, μερικά Field classes απαιτούν να έχουν κάποια arguments συμπληρωμένα. Για παράδειγμα το CharField, απαιτεί να το δώσετε ένα max_length. Αυτό δεν χρησιμοποιείται μόνο για το schema της βάσης δεδομένων αλλά και για το validation, όπως θα δούμε σύντομα.

Ένα Field μπορεί να έχει διάφορα προαιρετικά arguments. Σε αυτό το παράδειγμα έχουμε θέσει στο votes πεδίο την τιμή 0 (μηδέν) μέσω του argument default.

Τέλος, σημειώστε ότι η συσχέτιση (μεταξύ των δύο μοντέλων) επιτυγχάνεται χρησιμοποιώντας την κλάση ForeignKey. Αυτό λέει στο Django ότι κάθε Choice σχετίζεται με μια Question ενώ αντίστροφα κάθε Question μπορεί να συσχετίζεται με πολλά Choice``s. Αυτό, βέβαια, γίνεται διότι η στήλη ``question του πίνακα Choice κρατάει το ID της στήλης ID του πίνακα Question. Έτσι, κάθε choice δεν μπορεί να αντιστοιχίσει σε παραπάνω από μια ερώτηση καθώς αυτό θα θεωρηθεί διπλή καταχώρηση (duplicate entry). Το Django υποστηρίζει όλου του είδους των κοινών συσχετίσεων μεταξύ βάσεων δεδομένων: many-to-one, many-to-many και one-to-one.

Ενεργοποιώντας τα μοντέλα

Αυτό το μικρό κομμάτι κώδικα δίνει στο Django πολλές πληροφορίες. Με αυτό, το Django μπορεί να:

  • Δημιουργήσει το database schema (CREATE TABLE statements) για αυτό το app.
  • Δημιουργήσει ένα Python database-access API για να έχετε πρόσβαση στα objects Question και Choice.

Αλλά πρώτα θα πρέπει να πούμε στο project μας ότι η εφαρμογή polls έχει εγκατασταθεί.

Φιλοσοφία

Τα apps στο Django είναι «επαναχρησιμοποιήσιμα»: Μπορείτε να χρησιμοποιήσετε το ίδιο app σε πολλά projects και επίσης μπορείτε να διανέμετε τα apps σας (να τα χρησιμοποιήσουν άλλοι προγραμματιστές), επειδή δεν είναι απαραίτητο να είναι συνδεδεμένα με κάποια συγκεκριμένη Django εγκατάσταση (περιβάλλον).

Για να συμπεριλάβουμε την εφαρμογή στο project μας, θα χρειαστεί να προσθέσουμε μια αναφορά (reference) στην κλάση παραμετροποίησης (configuration class) της εφαρμογής μέσα στη ρύθμιση-λίστα INSTALLED_APPS. Εφόσον η κλάση PollsConfig υπάρχει μέσα στο αρχείο polls/apps.py, το μονοπάτι για την αναφορά σε αυτή την κλάση είναι 'polls.apps.PollsConfig'. Σημειώστε ότι αναφερόμαστε σε αυτό χρησιμοποιώντας ένα string. Επεξεργαστείτε το γενικό αρχείο ρυθμίσεων του project σας, mysite/settings.py και προσθέστε το παραπάνω μονοπάτι (path) στη ρύθμιση-λίστα INSTALLED_APPS. Θα δείχνει κάπως έτσι:

mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Τώρα το Django ξέρει ότι θα πρέπει να συμπεριλάβει, μεταξύ άλλων και την εφαρμογή με το όνομα polls. Ας τρέξουμε μια άλλη εντολή:

$ python manage.py makemigrations polls
...\> py manage.py makemigrations polls

Θα δείτε κάτι παρόμοιο με αυτό:

Migrations for 'polls':
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice

Τρέχοντας την εντολή makemigrations, λέτε στο Django ότι έχετε κάνει κάποιες αλλαγές στο μοντέλο σας (σε αυτή την περίπτωση, έχετε δημιουργήσει καινούργια μοντέλα) και ότι θα θέλατε αυτές οι αλλαγές να αποθηκευτούν ως migration.

Migrations are how Django stores changes to your models (and thus your database schema) - they’re files on disk. You can read the migration for your new model if you like; it’s the file polls/migrations/0001_initial.py. Don’t worry, you’re not expected to read them every time Django makes one, but they’re designed to be human-editable in case you want to manually tweak how Django changes things.

Μέχρι τώρα, δηλαδή, έχουμε ορίσει τα μοντέλα μας, έχουμε δημιουργήσει τα migrations αλλά δεν έχει γραφτεί τίποτα στη βάση δεδομένων. Όπως καταλάβατε, για να δημιουργήσουμε τους πίνακες στη βάση (δημιουργία schema) δεν έχουμε παρά να τρέξουμε μια εντολή που θα τα τακτοποιήσει όλα αυτά για εμάς. Η εντολή αυτή λέγεται migrate και θα έρθουμε σε αυτή σε λίγο – αλλά πρώτα, ας ρίξουμε μια ματιά στην εντολή SQL που θα τρέξει στην ουσία. Η database δεν καταλαβαίνει Python κώδικα παρά μόνο SQL εντολές. Επομένως, για να δούμε την SQL εντολή που θα δοθεί (από το Django) στην βάση δεδομένων για τη δημιουργία των πινάκων (στην ουσία γίνεται μια μετάφραση του αρχείου polls/migrations/0001_initial.py σε SQL) δεν έχουμε παρά να τρέξουμε την Django εντολή sqlmigrate η οποία παίρνει ως όρισμα ονόματα migrations και επιστρέφει την μετάφραση τους σε SQL:

$ python manage.py sqlmigrate polls 0001
...\> py manage.py sqlmigrate polls 0001

Θα δείτε κάτι παρόμοιο με το ακόλουθο (έχουμε αλλοιώσει λίγο την έξοδο για λόγους αναγνωσιμότητας):

BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL,
    "question_id" integer NOT NULL
);
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

COMMIT;

Σημειώστε τα ακόλουθα:

  • Η ακριβής έξοδος της εντολής sqlmigrate θα διαφέρει αναλόγως την βάση δεδομένων που χρησιμοποιείτε. Το ανωτέρω παράδειγμα χρησιμοποίησε την PostgreSQL.
  • Table names are automatically generated by combining the name of the app (polls) and the lowercase name of the model – question and choice. (You can override this behavior.)
  • Τα primary keys (IDs) προστέθηκαν αυτόματα (μπορείτε να το παρακάμψετε και αυτό!).
  • Από προεπιλογή, το Django προσθέτει τη λέξη "_id" σε κάθε πεδίο foreign key (ω ναι, μπορείτε να το παρακάμψετε και αυτό!)
  • The foreign key relationship is made explicit by a FOREIGN KEY constraint. Don’t worry about the DEFERRABLE parts; it’s telling PostgreSQL to not enforce the foreign key until the end of the transaction.
  • Η εντολή αυτή (sqlmigrate) είναι βασισμένη στην βάση δεδομένων που χρησιμοποιείτε. Επομένως, συγκεκριμένα database πεδία όπως auto_increment (MySQL), serial (PostgreSQL) ή integer primary key autoincrement (SQLite) διαχειρίζονται από το Django για σας, αυτόματα. Το ίδιο ισχύει και για το quoting των field names – π.χ, αν χρησιμοποιείτε διπλά quotes (””) ή μονά (’’).
  • The sqlmigrate command doesn’t actually run the migration on your database - instead, it prints it to the screen so that you can see what SQL Django thinks is required. It’s useful for checking what Django is going to do or if you have database administrators who require SQL scripts for changes.

Αν ενδιαφέρεστε μπορείτε να τρέξετε την εντολή python manage.py check. Η εντολή αυτή ελέγχει όλο το project σας για τυχόν λάθη (συντακτικά, λογικά κλπ) δίχως να δημιουργεί migrations ή να αλληλεπιδρά με την database σας.

Τώρα μπορείτε να τρέξετε την εντολή migrate για να δημιουργήσετε τους πίνακες και τις συσχετίσεις μεταξύ τους στην βάση δεδομένων σας:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK
...\> py manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK

Η εντολή migrate λαμβάνει υπόψη της όλα τα migrations τα οποία δεν έχουν εφαρμοστεί (το Django γνωρίζει ποια migrations έχουν εφαρμοστεί χρησιμοποιώντας έναν ειδικό πίνακα στην βάση δεδομένων υπό το όνομα django_migrations) και τα τρέχει ένα-ένα - στη ουσία, πραγματοποιεί ένα είδους συγχρονισμό μεταξύ των αλλαγών των μοντέλων σας και του schema της βάσης σας.

Τα migrations είναι εξαιρετικά δυνατό χαρακτηριστικό του Django και σας επιτρέπει να αλλάζετε τα μοντέλα σας (όποτε το κρίνεται απαραίτητο) χωρίς να χρειαστεί να διαγράφετε κάθε φορά τη βάση ή τους πίνακες σας και να τους δημιουργείτε εκ νέου. Ειδικεύεται στο να εκσυγχρονίζει την βάση σας σε πραγματικό χρόνο χωρίς να χάνετε τα ήδη αποθηκευμένα δεδομένα σας. Θα καλύψουμε τα migrations, εκτενώς, σε επόμενο μέρος του οδηγού, αλλά προς το παρόν θυμηθείτε τα τρία βήματα που πρέπει να ακολουθήσετε για να αλλάζετε τα μοντέλα σας:

  • Αλλάξτε τα μοντέλα σας (στο αρχείο models.py).
  • Τρέξτε την εντολή python manage.py makemigrations για να δημιουργηθούν τα migrations για τις αλλαγές που κάνατε.
  • Τρέξτε την εντολή python manage.py migrate για να εκτελέσετε τις αλλαγές στη βάση δεδομένων.

The reason that there are separate commands to make and apply migrations is because you’ll commit migrations to your version control system and ship them with your app; they not only make your development easier, they’re also usable by other developers and in production.

Διαβάστε στο άρθρο εγχειρίδιο (documentation) του django-admin για περισσότερες πληροφορίες των δυνατοτήτων της εντολής manage.py. Εναλλακτικά μπορείτε να γράψετε στην κονσόλα την εντολή python manage.py για να ρίξετε μια γρήγορη ματιά στις διαθέσιμες εντολές.

Παίζοντας με το API

Ας μεταβούμε τώρα στην interactive Python κονσόλα (shell) και ας παίξουμε λίγο με το δωρεάν API το οποίο μας παρέχει το Django. Για να μεταβούμε στο Python shell, πληκτρολογήστε την εντολή (βεβαιωθείτε ότι βρίσκεστε στο root φάκελο του project σας, εκεί που βρίσκεται το αρχείο manage.py):

$ python manage.py shell
...\> py manage.py shell

Εκτελούμε δηλαδή με την Python το script manage.py το οποίο εκτελεί την εντολή shell. Δεν χρησιμοποιούμε σκέτο τη λέξη «python», επειδή το αρχείο manage.py θέτει την μεταβλητή περιβάλλοντος (environment variable) DJANGO_SETTINGS_MODULE, η οποία δίνει στο Django το Python import μονοπάτι για το αρχείο mysite/settings.py.

Όταν είστε μέσα στο shell, μπορείτε να εξερευνήσετε το database API:

>>> from polls.models import Choice, Question  # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

Wait a minute. <Question: Question object (1)> isn’t a helpful representation of this object. Let’s fix that by editing the Question model (in the polls/models.py file) and adding a __str__() method to both Question and Choice:

polls/models.py
from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

Είναι σημαντικό να προσθέσετε την μέθοδο __str__() στα μοντέλα σας, όχι μόνο για δική σας διευκόλυνση (προβολή μέσα από την κονσόλα) αλλά και γιατί το διαχειριστικό κομμάτι του Django (admin) χρησιμοποιεί ευρέως την μέθοδο αυτή (όπως θα δείτε αργότερα) για να σας παρουσιάσει τα ονόματα των entries της βάσης σας.

Let’s also add a custom method to this model:

polls/models.py
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Σημειώστε την προσθήκη του import datetime και from django.utils import timezone, ούτως ώστε να αναφερθούμε στο module της Python datetime και στο module του Django django.utils.timezone, αντίστοιχα. Αν δεν είστε εξοικειωμένοι με τον χειρισμό των ζωνών ώρας (time zone) στην Python, μπορείτε να μάθετε περισσότερα στο άρθρο time zone support docs.

Αποθηκεύστε τις αλλαγές στα μοντέλα σας (δεν χρειάζεται να τρέξετε τις εντολές makemigrations ή migrate γιατί δεν άλλαξε κάτι στα πεδία των μοντέλων σας) και ξεκινήστε εκ νέου ένα Python interactive shell τρέχοντας πάλι την εντολή python manage.py shell:

>>> from polls.models import Choice, Question

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

Για περισσότερες πληροφορίες σχετικά με τις συσχετίσεις των μοντέλων, δείτε στο άρθρο Πρόσβαση συσχετισμένων objects. Για περισσότερες πληροφορίες σχετικά με το πώς να χρησιμοποιείτε τη διπλή κάτω παύλα για queries στην db μέσω του API, δείτε στο άρθρο Αναζητήσεις στα fields. Για περισσότερες λεπτομέρειες σχετικά με το database API, δείτε το άρθρο Αναφορά στο Database API.

Εισαγωγή στο Django Admin

Φιλοσοφία

Η δημιουργία των διαχειριστικών ιστοσελίδων (admin sites) για το προσωπικό σας ή τους πελάτες σας (ή ακόμη και για σας τον ίδιο) προκειμένου να προσθέσετε, αλλάξετε ή να διαγράψετε περιεχόμενο είναι μια ανιαρή διαδικασία η οποία δεν χρειάζεται και πολύ δημιουργικότητα. Για το λόγο αυτό το Django αυτοματοποιεί πλήρως την δημιουργία του διαχειριστικού interface για τα μοντέλα σας.

Το Django έχει γραφτεί σε ένα ειδησεογραφικό περιβάλλον, με πλήρη διαχωρισμό των εννοιών «εκδότες περιεχομένου» και «δημόσιο» site. Οι site managers χρησιμοποιούν το σύστημα για να εισάγουν νέα γεγονότα, αποτελέσματα αγώνων κλπ και αυτό το περιεχόμενο προβάλλεται στο «δημόσιο» site. Το Django λύνει το πρόβλημα της δημιουργίας ενός ενοποιημένου interface για τους site administrators με σκοπό την επεξεργασία του περιεχομένου.

Το admin site δεν είναι σχεδιασμένο για να χρησιμοποιηθεί από τους επισκέπτες της ιστοσελίδας σας. Είναι μόνο για αυτούς που θα διαχειρίζονται το site (site managers).

Δημιουργώντας έναν χρήστη admin

Πρώτα απ’όλα θα χρειαστεί να δημιουργήσουμε έναν χρήστη ο οποίος θα έχει πρόσβαση στο διαχειριστικό περιβάλλον (admin site). Τρέξτε την εντολή:

$ python manage.py createsuperuser
...\> py manage.py createsuperuser

Γράψτε το επιθυμητό όνομα χρήστη (username) και πιέστε enter.

Username: admin

Μετά θα πρέπει να γράψετε μια διεύθυνση email:

Email address: admin@example.com

Το τελευταίο βήμα είναι η επιλογή ενός συνθηματικού (password). Θα κληθείτε να γράψετε το συνθηματικό σας δύο φορές, (η δεύτερη φορά αποτελεί επιβεβαίωση της πρώτης).

Password: **********
Password (again): *********
Superuser created successfully.

Εκκίνηση του development server

Το Django admin site είναι ενεργό από προεπιλογή. Ας τρέξουμε τον development server και ας το εξερευνήσουμε.

Αν ο server δεν τρέχει, ξεκινήστε τον με την εντολή:

$ python manage.py runserver
...\> py manage.py runserver

Τώρα, ανοίξτε έναν Web browser και μεταβείτε στη σελίδα «/admin/» στο local domain σας – π.χ, http://127.0.0.1:8000/admin/. Θα πρέπει να δείτε την login οθόνη της Django admin σελίδας:

Django admin login screen

Since translation is turned on by default, if you set LANGUAGE_CODE, the login screen will be displayed in the given language (if Django has appropriate translations).

Επίσκεψη στο admin site

Προσπαθήστε τώρα να κάνετε login με τα credentials που δώσατε πριν. Θα πρέπει να δείτε την αρχική σελίδα του Django admin:

Django admin index page

Θα πρέπει να δείτε μερικούς τύπους περιεχομένου οι οποίοι μπορούν να επεξεργαστούν: ομάδες (groups) και χρήστες (users). Αυτοί παρέχονται από το authentication framework django.contrib.auth, το οποίο έρχεται προεγκατεστημένο με το Django.

Κάντε την εφαρμογή σας (poll) τροποποιήσιμη στο admin

Φαίνεται όμως να λείπει η εφαρμογή μας. Δεν εμφανίζεται καθόλου στο διαχειριστικό site.

Only one more thing to do: we need to tell the admin that Question objects have an admin interface. To do this, open the polls/admin.py file, and edit it to look like this:

polls/admin.py
from django.contrib import admin

from .models import Question

admin.site.register(Question)

Εξερευνήστε την δωρεάν διαχειριστική λειτουργία

Τώρα που έχουμε κάνει register το μοντέλο Question στο admin, το Django ξέρει πως πρέπει να εμφανίσει στην αρχική σελίδα του admin, την εφαρμογή σας:

Django admin index page, now with polls displayed

Κλικάρετε στο «Questions». Τώρα είστε στη λεγόμενη «change list» σελίδα για τις ερωτήσεις. Αυτή η σελίδα εμφανίζει όλες τις ερωτήσεις (που είναι αποθηκευμένες στην βάση δεδομένων) και σας επιτρέπει να κλικάρετε πάνω τους και να τις επεξεργαστείτε. Εδώ φαίνεται και η ερώτηση που δημιουργήσαμε πριν («What’s up?»):

Polls change list page

Κλικάρετε Click the «What’s up?» question to edit it:

Editing form for question object

Μερικά πράγματα που αξίζει να σημειώσετε:

  • Η φόρμα δημιουργείται αυτόματα από το Question μοντέλο.
  • Τα διαφορετικού τύπου πεδία του μοντέλου Question (DateTimeField, CharField) αντιστοιχούν στα ανάλογα HTML input πεδία (widgets). Κάθε τύπος πεδίου γνωρίζει ποιο HTML input element να χρησιμοποιήσει στο Django admin (π.χ τα πεδία χαρακτήρων - CharField``s αντιστοιχούν στο ``<input type=”text” /> ενώ τα αριθμητικά ημερομηνία - IntegerField``s αντιστοιχούν στο ``<input type=”number” />).
  • Κάθε DateTimeField λαμβάνει ένα δωρεάν JavaScript plugin. Οι ημερομηνίες (dates) λαμβάνουν μια συντόμευση με το όνομα «Σήμερα» (όταν το κλικάρετε επιλέγεται η τωρινή ημερομηνία) καθώς και ένα ημερολόγιο (που εμφανίζεται σαν popup). Οι ώρες λαμβάνουν μια συντόμευση με το όνομα «Τώρα» (όταν το κλικάρετε επιλέγεται η τρέχουσα ώρα) και ένα βολικό popup το οποίο προβάλλει κοινότυπες ώρες προκειμένου να διαλέξετε αυτή που σας ταιριάζει.

Το κάτω μέρος της σελίδας (το οποίο με την ρύθμιση py, μπορεί να εμφανιστεί και στο πάνω μέρος) σας δίνει ορισμένες επιλογές:

  • Αποθήκευση – Αποθηκεύει τυχόν αλλαγές και σας επιστρέφει στην σελίδα change list για αυτό το object.
  • Αποθήκευση και συνέχεια επεξεργασίας – Αποθηκεύει τυχόν αλλαγές και επαναφορτώνει την ίδια σελίδα για αυτό το object.
  • Αποθήκευση και προσθήκη καινούργιου – Αποθηκεύει τυχόν αλλαγές και επαναφορτώνει την ίδια σελίδα, άδεια χωρίς τις τιμές του object που αποθηκεύτηκε προκειμένου να γίνει καταχώρηση νέου.
  • Διαγραφή – Σας ανακατευθύνει σε μια ενδιάμεση σελίδα επιβεβαίωσης της διαγραφής του object.

Αν η τιμή του «Date published» δεν ταιριάζει με την ώρα που αποθηκεύσατε την ερώτηση πριν (το Question object), αυτό σημαίνει ότι πιθανόν παραλείψατε να θέσετε τη σωστή τιμή στη ρύθμιση TIME_ZONE του αρχείου mysite/settings.py. Αλλάχτε το, επαναφορτώστε τη σελίδα και ελέγξτε αν εμφανίστηκε η σωστή τιμή.

Αλλάξτε τώρα την τιμή του «Date published» κλικάροντας στα κουμπιά «Σήμερα» και «Τώρα». Μετά κλικάρετε στο κουμπί » Αποθήκευση και συνέχεια επεξεργασίας». Μετά κλικάρετε στο κουμπί «Ιστορικό» (πάνω δεξιά της σελίδας). Θα δείτε μια σελίδα στην οποία εμφανίζονται όλες οι αλλαγές που έχουν γίνει μέχρι τώρα στο συγκεκριμένο object μέσω του Django admin, μαζί με ημερομηνία και ώρα που έγινε η αλλαγή καθώς και τον χρήστη που την έκανε:

History page for question object

Όταν νιώσετε άνετα με το API των μοντέλων (πειραματιστείτε με τις αναζητήσεις στην database, με τις συσχετίσεις των μοντέλων μεταξύ τους κλπ) και έχετε εξοικειωθεί με το διαχειριστικό περιβάλλον, συνεχίστε στο τρίτο μέρος αυτού του οδηγού για να μάθετε περισσότερα σχετικά με την προσθήκη views στην εφαρμογή μας (polls).

Back to Top