# Τεκμηρίωση του Django - 6.0.7

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

This tutorial begins where Tutorial 1 left off. We’ll set up the database, create your first model, and get a quick introduction to Django’s automatically-generated admin site.

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

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. Ανοίξτε το αρχείο αυτό.

By default, the `DATABASES` configuration uses SQLite. If you’re new to databases, or you’re just interested in trying Django, this is the easiest choice. SQLite is included in Python, so you won’t need to install anything else to support your database. When starting your first real project, however, you may want to use a more scalable database like PostgreSQL, to avoid database-switching headaches down the road.

If you wish to use another database, see details to customize and get your database running.

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

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

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

- `django.contrib.admin` – Το admin site. Θα φτάσετε εκεί σε λίγο.

- `django.contrib.auth` – Το σύστημα πιστοποίησης (authentication)

- `django.contrib.contenttypes` – Ένα framework για content types.

- `django.contrib.sessions` – Το session framework.

- `django.contrib.messages` – Το messaging framework.

- `django.contrib.staticfiles` – Ένα framework για να διαχειρίζεστε τα static files (css, js, φωτογραφίες, εικονίδια κλπ).

Αυτά τα 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), `.tables` (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.

Φιλοσοφία

A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Django follows the DRY Principle. The goal is to define your data model in one place and automatically derive things from it.

This includes the migrations, which are derived from your models file. They form a history that Django uses 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" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
        "question_text" varchar(200) NOT NULL,
        "pub_date" timestamp with time zone NOT NULL
    );
    --
    -- Create model Choice
    --
    CREATE TABLE "polls_choice" (
        "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
        "choice_text" varchar(200) NOT NULL,
        "votes" integer NOT NULL,
        "question_id" bigint 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.

- It’s tailored to the database you’re using, so database-specific field types such as `auto_increment` (MySQL), `bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY` (PostgreSQL), or `integer primary key autoincrement` (SQLite) are handled for you automatically. Same goes for the quoting of field names – e.g., using double quotes or single 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:
      Applying polls.0001_initial... OK

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

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

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

- Αλλάξτε τα μοντέλα σας (στο αρχείο `models.py`).

- Run `python manage.py makemigrations` to create migrations for those changes.

- Τρέξτε την εντολή `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

We’re using this instead of simply typing «python», because `manage.py` sets the `DJANGO_SETTINGS_MODULE` environment variable, which gives Django the Python import path to your `mysite/settings.py` file. By default, the `shell` command automatically imports the models from your `INSTALLED_APPS`.

Once you’re in the shell, explore the database API:

    # 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=datetime.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.

Save these changes and start a new Python interactive shell. (If a three-chevron prompt (>>>) indicates you are still in the shell, you need to exit first using `exit()`). Run `python manage.py shell` again to reload the models.

    # 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 (defined as "choice_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

Now, open a web browser and go to «/admin/» on your local domain – e.g., http://127.0.0.1:8000/admin/. You should see the admin’s 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:

Θα πρέπει να δείτε μερικούς τύπους περιεχομένου οι οποίοι μπορούν να επεξεργαστούν: ομάδες (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, την εφαρμογή σας:

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

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

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

- Η φόρμα δημιουργείται αυτόματα από το `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, μαζί με ημερομηνία και ώρα που έγινε η αλλαγή καθώς και τον χρήστη που την έκανε:

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