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

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

Παραμετροποιώντας την 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»):

Fields have been reordered

Αυτό δεν είναι και τόσο εντυπωσιακό με μόλις δύο πεδία, αλλά για φόρμες 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. Δείτε πως θα εμφανίζεται τώρα η φόρμα:

Form has fieldsets now

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

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

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

Polls change list page

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

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

Για λόγους πληρότητας ας συμπεριλάβουμε την μέθοδο του μοντέλου Question was_published_recently() από τον Οδηγό 2:

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

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

Polls change list page, updated

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

Μπορούμε να βελτιώσουμε την όλη αυτή εμφάνιση παρέχοντας μερικά attributes στην μέθοδο αυτή (μέσα στο αρχείο polls/models.py) ως ακολούθως:

polls/models.py
class Question(models.Model):
    # ...
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

Για περισσότερες πληροφορίες σχετικά με τα properties των μεθόδων, δείτε στο list_display.

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

list_filter = ['pub_date']

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

Polls change list page, updated

Ο τύπος του φίλτρου που εμφανίζεται εξαρτάται από τον τύπο του πεδίου που προσπαθείτε να φιλτράρετε. Επειδή το πεδίο 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.

Αυτό αλλάζει πανεύκολα ούτως ώστε να γράφει κάτι που να ταιριάζει με το δικό σας διαχειριστικό site. Θα χρησιμοποιήσουμε το σύστημα των templates του Django. Το Django admin δεν είναι τίποτε άλλο παρά άλλο ένα application και δεν ακολουθά καμία άλλη template λογική παρά αυτή που θα δούμε παρακάτω (template inheritance κλπ).

Παραμετροποιώντας τα 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': [os.path.join(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__)"

Επόμενο βήμα είναι να ανοίξετε το αρχείο που μόλις αντιγράψατε και να αντικαταστήσετε το {{ site_header|default:_('Django administration') }} (μαζί με τα διπλά άγκιστρα) με το όνομα του site σας ή οτιδήποτε άλλο εσείς θέλετε. Θα καταλήξετε με κάτι σαν αυτό:

{% 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.

Σημειώστε ότι κάθε template του Django μπορεί να γίνει overridden. Το μόνο που έχετε να κάνετε είναι να ακολουθήσετε την ίδια διαδικασία που κάναμε παραπάνω για το αρχείο base_site.html – το αντιγράφετε από την αρχική του θέση (πηγαίο κώδικα του Django) στο φάκελο που κρατάει τα templates της εφαρμογής σας. Αφού αντιγραφεί, μετά είστε ελεύθεροι να κάνετε τυχόν αλλαγές της αρέσκειας σας.

Παραμετροποιώντας τα 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.

Back to Top