# Τεκμηρίωση του Django - 3.2.11.dev

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

Καλώς ορίσατε στο τελευταίο μέρος του οδηγού (tutorial) του Django! Ο οδηγός αυτός ξεκινά εκεί που τελειώνει ο οδηγός 6. Συνεχίζουμε με την εφαρμογή μας (Web-poll) και αυτή τη φορά θα επικεντρωθούμε στην παραμετροποίηση του διαχειριστικού site του Django το οποίο δημιουργείται αυτόματα για εσάς. Το Django admin το συναντήσαμε πρώτα στον Οδηγό 2.

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

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

## Παραμετροποιώντας την admin form

Κάνοντας register το `Question` model με το Django admin (`admin.site.register(Question)`), το Django ήταν σε θέση να κατασκευάσει μια προεπιλεγμένη εμφάνιση της φόρμας του μοντέλου για επεξεργασία. Με άλλα λόγια σας δίνει τη δυνατότητα να δημιουργείτε, επεξεργάζεστε, ανανεώνετε και διαγράφετε entries στη βάση δεδομένων σας (υπενθυμίζουμε ότι κάθε instance του μοντέλου σας αναπαριστά και μια γραμμή -entry, row- στον αντίστοιχο πίνακα της database) χωρίς τη χρήση της κονσόλας (γραμμής εντολών). Πολύ συχνά θα θέλετε να επεξεργαστείτε την εμφάνιση της φόρμας αυτής καθώς και τον τρόπο που λειτουργεί. Για να το πετύχετε αυτό δεν έχετε παρά να πείτε στο Django τις επιλογές-ρυθμίσεις που θέλετε, για αυτό το μοντέλο, την ώρα που κάνετε register το μοντέλο σας με το Django admin.

Ας δούμε πως δουλεύει αναδιοργανόνοντας τα πεδία (fields) στην φόρμα επεξεργασίας (edit form). Μέσα στο αρχείο `polls/admin.py`, αντικαταστήστε την γραμμή `admin.site.register(Question)` με αυτό το κομμάτι κώδικα:

polls/admin.py

    from django.contrib import admin

    from .models import Question

    class QuestionAdmin(admin.ModelAdmin):
        fields = ['pub_date', 'question_text']

    admin.site.register(Question, QuestionAdmin)

Θα ακολουθείτε αυτή τη διαδικασία (αρχικά θα δημιουργείτε μια model admin class και έπειτα θα περνάτε αυτή τη κλάση ως δεύτερο όρισμα στη μέθοδο `admin.site.register()`) κάθε φορά που θέλετε να αλλάξετε τυχόν επιλογές στο admin (admin options) για ένα μοντέλο.

Αν θυμάστε, πριν την αλλαγή αυτή, στη φόρμα επεξεργασίας εμφανιζόταν πρώτα το πεδίο της ερώτησης και μετά το πεδίο της ημερομηνίας επειδή τα είχαμε δηλώσει με αυτή τη σειρά στο μοντέλο `Question`. Τώρα, παρακάμπτουμε αυτή τη σειρά και πλέον εμφανίζεται πρώτα το πεδίο της ημερομηνίας («Publication date») και κατόπιν το πεδίο της ερώτησης («Question»):

Αυτό δεν είναι και τόσο εντυπωσιακό με μόλις δύο πεδία, αλλά για φόρμες admin (admin forms) με δεκάδες πεδία, η επιλογή της σειράς εμφάνισης αποτελεί σημαντική λεπτομέρεια.

Και μιλώντας για φόρμες με δεκάδες πεδία, ίσως να θέλετε να διαχωρίσετε τη φόρμα σε πεδία φορμών (fieldsets):

polls/admin.py

    from django.contrib import admin

    from .models import Question

    class QuestionAdmin(admin.ModelAdmin):
        fieldsets = [
            (None,               {'fields': ['question_text']}),
            ('Date information', {'fields': ['pub_date']}),
        ]

    admin.site.register(Question, QuestionAdmin)

Το πρώτο element από κάθε tuple μέσα στη λίστα `fieldsets` είναι ο τίτλος του fieldset. Δείτε πως θα εμφανίζεται τώρα η φόρμα:

## Προσθήκη συσχετισμένων objects

Ωραία, έχουμε την σελίδα διαχείρισης του Question model, αλλά ένα `Question` έχει πολλαπλά `Choice`s και η φόρμα δεν εμφανίζει αυτές τις επιλογές.

Ακόμα.

There are two ways to solve this problem. The first is to register `Choice` with the admin just as we did with `Question`:

polls/admin.py

    from django.contrib import admin

    from .models import Choice, Question
    # ...
    admin.site.register(Choice)

Μετά από αυτό, το μοντέλο `Choice` απέκτησε τη δική του διαχειριστική φόρμα (admin form). Επομένως, τα πεδία της φόρμας θα εμφανιστούν με τη σειρά που δηλώθηκαν στο ίδιο το μοντέλο (εφόσον δεν κάναμε καμία αλλαγή μέσα στο `admin.py` όπως κάναμε για το `Question`). Η φόρμα θα δείχνει κάπως έτσι:

Σε αυτή τη φόρμα, το πεδίο «Question» αναπαριστάται από ένα HTML select box το οποίο περιέχει κάθε ερώτηση μέσα στη βάση δεδομένων. Το Django γνωρίζει ότι η κλάση `ForeignKey` θα πρέπει να αναπαρασταθεί ως ένα `<select>` box μέσα στην admin form. Στη δικιά μας περίπτωση, μόνο μια ερώτηση θα εμφανιστεί σε αυτό το σημείο (εκτός κι αν έχετε δημιουργήσει και άλλες).

Επίσης προσέξτε το link «Προσθήκη Καινούγιου <όνομα_μοντέλου>» (με το σύμβολο της πρόσθεσης) δίπλα από το πεδίο «Question.» Κάθε object με ένα πεδίο `ForeignKey` λαμβάνει αυτή την ευκολία από προεπιλογή. Όταν κλικάρετε πάνω σε αυτό το link, θα δείτε ένα popup παράθυρο με τη φόρμα επεξεργασίας του `Question` μοντέλου (αυτή που είδαμε πριν). Αν προσθέσετε μια ερώτηση σε αυτό το πράθυρο και κλικάρετε «Αποθήκευση», το Django θα αποθηκεύσει την ερώτηση στη βάση δεδομένων και έπειτα θα εμφανίσει αυτή την ερώτηση ως επιλεγμένη (selected) στο `<select>` box.

Όμως αυτός ο τρόπος προσθήκης επιλογών (`Choice` objects) δεν είναι και ο πιο αποτελεσματικός που υπάρχει. Δε θα ήταν πιο βολικό αν δημιουργούσατε τα ``Choice``s κατά τη διάρκεια δημιουργίας των ερωτήσεων; Ας το υλοποιήσουμε.

Αφαιρέστε την κλήση της `register()` με το μοντέλο `Choice`. Έπειτα, επεξεργαστείτε τον registration κώδικα του `Question` για να γίνει έτσι:

polls/admin.py

    from django.contrib import admin

    from .models import Choice, Question

    class ChoiceInline(admin.StackedInline):
        model = Choice
        extra = 3

    class QuestionAdmin(admin.ModelAdmin):
        fieldsets = [
            (None,               {'fields': ['question_text']}),
            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
        ]
        inlines = [ChoiceInline]

    admin.site.register(Question, QuestionAdmin)

Αυτό λέει στο Django: «Όλα τα `Choice` objects θα επεξεργάζονται στην διαχειριστική σελίδα του μοντέλου `Question`. Από προεπιλογή, να παρέχεις 3 choices».

Επισκεφτείτε, πάλι, τη σελίδα «Add question» για να δείτε πως φαίνεται:

Δουλεύει κάπως έτσι: Υπάρχουν τρία slots για τα συσχετισμένα Choices – όπως δηλώθηκε μέσω του attribute `extra` – και κάθε φορά που επισκέπτεστε τη σελίδα ενός ήδη υπάρχοντος object, παίρνετε άλλα τρία επιπλέον slots. Όταν όμως επισκέπτεστε για πρώτη φορά τη σελίδα (δημιουργία νέου object) θα λαμβάνετε τα πρώτα τρία slots.

At the end of the three current slots you will find an «Add another Choice» link. If you click on it, a new slot will be added. If you want to remove the added slot, you can click on the X to the top right of the added slot. This image shows an added slot:

One small problem, though. It takes a lot of screen space to display all the fields for entering related `Choice` objects. For that reason, Django offers a tabular way of displaying inline related objects. To use it, change the `ChoiceInline` declaration to read:

polls/admin.py

    class ChoiceInline(admin.TabularInline):
        #...

Με αυτό, `TabularInline` (αντί του `StackedInline`), τα συσχετισμένα objects εμφανίζονται πιο συμπυκνωμένα, σαν να βρίσκονται μέσα σε ένα πίνακα:

Σε αυτή τη μορφή υπάρχει και μια επιπλέον στήλη («Θέλετε να πραγματοποιηθεί διαγραφή?») η οποία σας επιτρέπει να διαγράψετε γραμμές που προστέθηκαν με την επιλογή «Προσθήκη καινούργιου Choice». Σημειώστε ότι πάντα θα έχετε το ελάχιστο τρεις επιλογές (ρύθμιση `extra` μέσα στο `ChoiceInline`).

## Παραμετροποιώντας την admin change list

Τώρα που η διαχειριστική σελίδα του μοντέλου Question δείχνει όμορφη, ας κάνουμε μερικές αλλαγές στην σελίδα «change list» – αυτή που εμφανίζει όλες τις ερωτήσεις μέσα στο σύστημα (σαν μια λίστα).

Δείτε πως φαίνεται σε αυτό το σημείο:

Από προεπιλογή, το Django εμφανίζει τη μέθοδο `str()` για κάθε object. Αλλά μερικές φορές θα ήταν πιο βολικό να εμφανίζουμε μεμονομένα πεδία. Για να το κάνουμε αυτό θα χρησιμοποιήσουμε την επιλογή-ρύθμιση `list_display`, η οποία είναι ένα tuple από ονόματα πεδίων (του μοντέλου σας), τα οποία θα εμφανιστούν ως στήλες σε αυτή τη σελίδα:

polls/admin.py

    class QuestionAdmin(admin.ModelAdmin):
        # ...
        list_display = ('question_text', 'pub_date')

For good measure, let’s also include the `was_published_recently()` method from Tutorial 2:

polls/admin.py

    class QuestionAdmin(admin.ModelAdmin):
        # ...
        list_display = ('question_text', 'pub_date', 'was_published_recently')

Τώρα η σελίδα change list του Question δείχνει κάπως έτσι:

Μπορείτε να κλικάρετε στους headers κάθε στήλης για να ταξινομήσετε την αντίστοιχη στήλη κατά τις τιμές της. Μοναδική εξαίρεση στη δυνατότητα της ταξινόμηση μιας στήλης αποτελεί η περίπτωση του header `was_published_recently`, επειδή η ταξινόμηση με βάση την έξοδο μιας μεθόδου (ενός μοντέλου) δεν υποστηρίζεται. Επίσης, σημειώστε ότι ο header της στήλης `was_published_recently` είναι, από προεπιλογή, το όνομα της μεθόδου (με τα κενά να αντικαθιστούν τις κάτω παύλες) και κάθε κελί της στήλης αυτής περιέχει την έξοδο της συγκεκριμένης μεθόδου (True ή False).

You can improve that by using the `display()` decorator on that method (in `polls/models.py`), as follows:

polls/models.py

    from django.contrib import admin

    class Question(models.Model):
        # ...
        @admin.display(
            boolean=True,
            ordering='pub_date',
            description='Published recently?',
        )
        def was_published_recently(self):
            now = timezone.now()
            return now - datetime.timedelta(days=1) <= self.pub_date <= now

For more information on the properties configurable via the decorator, see `list_display`.

Επεξεργαστείτε το αρχείο `polls/admin.py` για ακόμη μια φορά και προσθέστε ένα φίλτρο στη σελίδα change list του μοντέλου `Question` χρησιμοποιώντας το `list_filter`. Προσθέστε την ακόλουθη γραμμή κώδικα στην κλάση `QuestionAdmin`:

    list_filter = ['pub_date']

Αυτό προσθέτει μια πλευρική στήλη (sidebar) «Filter» η οποία επιτρέπει το φιλτράρισμα των αποτελεσμάτων στην σελίδα change list κατά το πεδίο `pub_date`:

Ο τύπος του φίλτρου που εμφανίζεται εξαρτάται από τον τύπο του πεδίου που προσπαθείτε να φιλτράρετε. Επειδή το πεδίο `pub_date` είναι τύπου `DateTimeField`, το Django ξέρει ότι πρέπει να του δώσει τις ανάλογες επιλογές για φιλτράρισμα, όπως: «Οποιαδήποτε ημερομηνία», «Σήμερα», «Τελευταίες 7 μέρες», «Αυτόν το μήνα», «Αυτόν το χρόνο».

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

    search_fields = ['question_text']

Αυτό προσθέτει ένα search box κοντά στην κορυφή της σελίδας change list. Όταν κάποιος πληκτρολογήσει κάποια λέξη κλειδί για εύρεση, το Django θα ψάξει μέσα στο πεδίο `question_text`. Μπορείτε να χρησιμοποιήσετε όσα πεδία θέλετε – όμως επειδή η μέθοδος αυτή κάνει χρήση του `LIKE` query στο παρασκήνιο, αν περιορίσετε τον αριθμό των search fields μέσα στο πεδίο `search_fields`, τότε θα κάνει τη δουλειά της database σας πιο εύκολη στην εύρεση της λέξης κλειδί που δώσατε.

Τώρα είναι μια καλή στιγμή να σημειώσουμε ότι η σελίδες change lists σας δίνουν δωρεάν τη δυνατότητα του pagination. Από προεπιλογή, το Djoango εμφανίζει 100 γραμμές ανά σελίδα. Τα attributes `Change list pagination`, `search boxes`, `filters`, `date-hierarchies` και `column-header-ordering` συνεργάζονται μεταξύ τους όπως ακριβώς νομίζετε.

## Παραμετροποιώντας την εμφάνιση του admin site

Βασικά, η λέξη «Διαχείριση Django» στην κορυφή κάθε σελίδας του admin είναι γελοία. Στην πραγματικότητα είναι ένα κείμενο placeholder.

You can change it, though, using Django’s template system. The Django admin is powered by Django itself, and its interfaces use Django’s own template system.

### Παραμετροποιώντας τα templates του project σας

Δημιουργήστε έναν φάκελο `templates` μέσα στο root φάκελο του project σας (αυτόν που περιέχει το αρχείο `manage.py`). Τα templates μπορούν να υπάρχουν οπουδήποτε μέσα στο filesystem σας αρκεί το Django να έχει πρόσβαση σε αυτά. (Το Django τρέχει υπό τον χρήστη που τρέχει και τον server σας.) Ωστόσο, το να κρατάτε τα templates σας μέσα στο project σας είναι μια, γενικά, καλή πρακτική.

Ανοίξτε το αρχείο ρυθμίσεων-επιλογών του project σας (settings file, `mysite/settings.py`) και προσθέστε την επιλογή `DIRS` μέσα στην επιλογή `TEMPLATES`:

mysite/settings.py

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [BASE_DIR / 'templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]

Η επιλογή `DIRS` είναι μια λίστα με strings. Κάθε string είναι η διαδρομή (path) η οποία καταλήγει σε κάποιο φάκελο που περιέχει τα templates σας. Όταν το Django φορτώνει τα templates θα ψάξει και σε αυτά τα paths για να βρει τα templates σας. Με άλλα λόγια αποτελεί ένα μονοπάτι ευρέσεως των templates.

Οργανώνοντας τα templates

Just like the static files, we could have all our templates together, in one big templates directory, and it would work perfectly well. However, templates that belong to a particular application should be placed in that application’s template directory (e.g. `polls/templates`) rather than the project’s (`templates`). We’ll discuss in more detail in the reusable apps tutorial why we do this.

Δημιουργήστε, τώρα, ένα φάκελο με όνομα `admin` μέσα στο φάκελο `templates` και κάντε αντιγραφή-επικόλληση το αρχείο template `admin/base_site.html` το οποίο θα βρείτε μέσα στον πηγαίο κώδικα του Django (`django/contrib/admin/templates`).

Που είναι ο πηγαίος κώδικας του Django?

Αν δυσκολεύεστε να βρείτε τον πηγαίο κώδικα του Django μέσα στο σύστημα σας, τρέξτε την ακόλουθη εντολή:

/ 

    $ python -c "import django; print(django.__path__)"

    ...\> py -c "import django; print(django.__path__)"

Then, edit the file and replace `{{ site_header|default:_('Django administration') }}` (including the curly braces) with your own site’s name as you see fit. You should end up with a section of code like:

    {% block branding %}
    <h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
    {% endblock %}

Χρησιμοποιούμε αυτή τη διαδικασία για να σας δείξουμε πως μπορείτε να κάνετε override τα templates. Σε ένα πραγματικό project, το πιο πιθανόν είναι να χρησιμοποιήσετε το attibute `django.contrib.admin.AdminSite.site_header` κάνοντας την παραπάνω διαδικασία ακόμα πιο εύκολη.

Αυτό το αρχείο template περιέχει αρκετό κείμενο όπως `{% block branding %}` και `{{ title }}`. Τα tags `{%` και `{{` είναι μέρος της γλώσσας template του Django. Όταν το Django κάνει render το αρχείο `admin/base_site.html`, αυτή η γλώσσα θα τρέξει και θα γεμίσει αυτά τα tags με διάφορες τιμές για να παραχθεί στο τέλος η HTML σελίδα που θα επιστρέψει πίσω στον χρήστη (ως response), όπως είδαμε στον Οδηγό 3.

Note that any of Django’s default admin templates can be overridden. To override a template, do the same thing you did with `base_site.html` – copy it from the default directory into your custom directory, and make changes.

### Παραμετροποιώντας τα templates της εφαρμογής σας

Οι προσεκτικοί αναγνώστες θα αναρρωτηθούν: Αφού η ρύθμιση (λίστα) `DIRS` είναι κενή αρχικά, πως ξέρει το Django που να βρει τα προεπιλεγμένα admin templates; Η απάντηση έχει ως εξής: εφόσον η ρύθμιση (boolean) `APP_DIRS` έχει την τιμή `True`, το Django αυτόματα κοιτάζει στο φάκελο `templates/` κάθε εφαρμογής (που συμπεριλαμβάνεται στη ρύθμιση-λίστα `INSTALLED_APPS`), για τη χρήση τους ως fallback (μην ξεχνάτε ότι το `django.contrib.admin` είναι και αυτό μια εφαρμογή).

Η εφαρμογή ψηφοφορίας μας δεν είναι πολύ περίπλοκη και δεν χρειάζεται κάποια μεγάλη παραμετροποίηση των admin templates. Αλλά αν αναπτυχθεί και μεγαλώσει σε τέτοιο βαθμό που να χρειάζεται απαραιτήτως διάφορες λειτουργικές επεμβάσεις στα default templates του Django, τότε θα ήταν πιο λογικό να γίνει σε επίπεδο application (μέσα στο φάκελο templates της εφαρμογής σας) παρά σε επίπεδο project (μέσα στο φάκελο templates του project σας). Με αυτό τον τρόπο, θα μπορέσετε να συμπεριλάβετε την εφαρμογή ψηφοφορίας σας σε κάποιο μελλοντικό project και θα είστε σίγουροι ότι τα templates αυτής της εφαρμογής θα εφαρμοστούν αμέσως στο νέο project.

Δείτε στο εγχειρίδιο (documentation) φόρτωσης των templates για περισσότερες πληροφορίες σχετικά με το πως το Django βρίσκει-αναζητά τα templates.

## Παραμετροποιώντας την αρχική σελίδα του Django admin

Ομοίως, ίσως να θέλετε να παραμετροποιήσετε (να φέρετε στα μέτρα σας) την εμφάνιση της αρχικής σελίδας του Django admin.

Από προεπιλογή, εμφανίζονται όλες οι εφαρμογές (κατά αλφαβητική σειρά) που συμπεριλαμβάνονται στη ρύθμιση (λίστα) `INSTALLED_APPS` και έχουν γίνει register με το admin. Αν θέλετε να κάνετε σημαντικές αλλαγές στην εμφάνιση της αρχικής σελίδας δεν έχετε παρά να βάλετε τη φαντασία σας να δουλέψει. Είναι γνωστό ότι η εμφάνιση της αρχικής σελίδας του admin είναι η πιο σημαντική και θα πρέπει να είναι εύκολο να την παραμετροποιήσετε.

To template προς παραμετροποίηση είναι το `admin/index.html` (κάντε το ίδιο όπως κάνατε για το αρχείο `admin/base_site.html` πριν – αντιγράψτε το από τον πηγαίο κώδικα του Django στον τοπικό φάκελο templates της εφαρμογής σας). Κατά τη διάρκεια επεξεργασίας του αρχείου θα δείτε ότι χρησιμοποιείται μια template variable με το όνομα `app_list`. Αυτή η μεταβλητή περιέχει κάθε εγκατεστημένη εφαρμογή στο Django (είναι μέσα στο `INSTALLED_APPS` και register στο admin). Αντί αυτού, μπορείτε να γράψετε hard-code συνδέσμους σε object-specific admin σελίδες με όποιον τρόπο πιστεύετε ότι είναι καλύτερος.

## Επόμενα βήματα

Ο οδηγός για αρχάριους τελειώνει κάπου εδώ. Στο μεταξύ μπορείτε να δείτε προτεινόμενες κατευθύνσεις για το τι να κάνετε έπειτα, στο άρθρο τι να κάνω μετά από εδώ.

Αν είστε εξοικειωμένοι με το Python packaging και ενδιαφέρεστε να μάθετε πως να μετατρέψετε την εφαρμογή ψηφοφορίας σε «επαναχρησιμοποιήσιμη εφαρμογή», δείτε το άρθρο Οδηγός για προχωρημένους: Πως να γράψετε επαναχρησιμοποιήσιμα apps.