Γράφοντας δικές σας django-admin εντολέςLink to this heading
Οι εφαρμογές μπορούν να κάνουν register τις δικές τους ενέργειες με το manage.py. Για παράδειγμα, ίσως να θέλετε να προσθέσετε μια manage.py ενέργεια για ένα Django app το οποίο προωθείτε για διανομή. Σε αυτό το άρθρο θα χτίσουμε μια δικιά μας εντολή, με το όνομα closepoll, για την εφαρμογή polls που φτιάξαμε στον οδηγό.
Για να το κάνουμε αυτό, απλά δημιουργήστε μια δομή φακέλων μέσα στην εφαρμογή ως εξής: management/commands. Το Django θα κάνει register μια manage.py εντολή για κάθε Python module μέσα σε αυτό το φάκελο του οποίου το όνομα δεν ξεκινά με τον χαρακτήρα της κάτω παύλας. Για παράδειγμα:
polls/
__init__.py
models.py
management/
commands/
_private.py
closepoll.py
tests.py
views.py
Σε αυτό το παράδειγμα, η εντολή closepoll θα είναι διαθέσιμη σε κάθε project που έχει εγκατεστημένη αυτή την εφαρμογή, ήτοι, η εφαρμογή polls βρίσκεται μέσα στη ρύθμιση INSTALLED_APPS.
Το module _private.py δεν θα είναι διαθέσιμο ως μια εντολή διαχείρισης (management command), αφού το όνομα του ξεκινά με την κάτω παύλα.
Το module closepoll.py έχει μόνο μια απαίτηση – πρέπει να ορίσει μια κλάση Command η οποία κάνει extend την κλάση BaseCommand ή μια από τις subclasses της.
Για να υλοποιήσετε την εντολή επεξεργαστείτε το αρχείο polls/management/commands/closepoll.py για να δείχνει κάπως έτσι:
from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll
class Command(BaseCommand):
help = 'Closes the specified poll for voting'
def add_arguments(self, parser):
parser.add_argument('poll_ids', nargs='+', type=int)
def handle(self, *args, **options):
for poll_id in options['poll_ids']:
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise CommandError('Poll "%s" does not exist' % poll_id)
poll.opened = False
poll.save()
self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))
The new custom command can be called using python manage.py closepoll
<poll_ids>.
The handle() method takes one or more poll_ids and sets poll.opened
to False for each one. If the user referenced any nonexistent polls, a
CommandError is raised. The poll.opened attribute does not exist in
the tutorial and was added to
polls.models.Question for this example.
Προαιρετικά argumentsLink to this heading
Αλλάζοντας εύκολα την εντολή closepoll ώστε να δέχεται επιπρόσθετες επιλογές όταν την καλείτε, θα μπορούσε να διαγράφει ένα poll αντί να το θέτει ως κλειστό (poll.opened = False). Αυτές οι επιλογές μπορούν να προστεθούν στη μέθοδο add_arguments() ως εξής:
class Command(BaseCommand):
def add_arguments(self, parser):
# Positional arguments
parser.add_argument('poll_ids', nargs='+', type=int)
# Named (optional) arguments
parser.add_argument(
'--delete',
action='store_true',
help='Delete poll instead of closing it',
)
def handle(self, *args, **options):
# ...
if options['delete']:
poll.delete()
# ...
Η επιλογή (η delete στο παράδειγμα μας) είναι διαθέσιμη μέσα στη μέθοδο handle μέσα από το options dictionary με το key delete. Δείτε περισσότερα στο εγχειρίδιο της Python σχετικά με τη χρήση της argparse και τη μέθοδο add_argument .
Πέρα από τη δυνατότητα της πρόσθεσης δικών σας επιλογών στην εντολή, όλες οι εντολές διαχείρισης μπορούν να δεχτούν μερικές δικές τους, προεγκατεστημένες, επιλογές όπως η --verbosity και η --traceback.
Εντολές διαχείρισης και localesLink to this heading
By default, management commands are executed with the current active locale.
If, for some reason, your custom management command must run without an active
locale (for example, to prevent translated content from being inserted into
the database), deactivate translations using the @no_translations
decorator on your handle() method:
from django.core.management.base import BaseCommand, no_translations
class Command(BaseCommand):
...
@no_translations
def handle(self, *args, **options):
...
Since translation deactivation requires access to configured settings, the decorator can’t be used for commands that work without configured settings.
ΤεστLink to this heading
Πληροφορίες στο πως να τεστάρετε τις δικές σας εντολές διαχείρισης, μπορείτε να βρείτε στα εργαλεία για τεστ.
Overriding commandsLink to this heading
Django registers the built-in commands and then searches for commands in
INSTALLED_APPS in reverse. During the search, if a command name
duplicates an already registered command, the newly discovered command
overrides the first.
In other words, to override a command, the new command must have the same name
and its app must be before the overridden command’s app in
INSTALLED_APPS.
Management commands from third-party apps that have been unintentionally
overridden can be made available under a new name by creating a new command in
one of your project’s apps (ordered before the third-party app in
INSTALLED_APPS) which imports the Command of the overridden
command.
Objects εντολώνLink to this heading
- class BaseCommandLink to this definition
Η κύρια κλάση από την οποία πηγάζουν όλες οι εντολές διαχείρισης.
Χρησιμοποιήστε αυτή την κλάση αν θέλετε να έχετε πρόσβαση σε όλους τους μηχανισμούς οι οποίοι μεταφράζουν τις επιλογές στη γραμμή εντολών (όπως την --delete που χρησιμοποιήσαμε νωρίτερα) και αποφασίζουν, ανάλογα την επιλογή, ποιον κώδικα να καλέσουν περαιτέρω. Αν δεν θέλετε να αλλάξετε κάποια από αυτές τις συμπεριφορές, ίσως σας φανεί χρήσιμη μια από τις subclasses της BaseCommand.
Πραγματοποιώντας subclassing στην κλάση BaseCommand απαιτεί να υλοποιήσετε τη μέθοδο handle().
AttributesLink to this heading
Όλα τα attributes μπορούν να οριστούν στη δική σας κλάση και να χρησιμοποιηθούν στις subclasses της BaseCommand.
- BaseCommand.helpLink to this definition
Μια μικρή περιγραφή της εντολής η οποία θα εκτυπωθεί στην κονσόλα όταν ο χρήστης τρέξει την εντολή
python manage.py help <command>.
- BaseCommand.missing_args_messageLink to this definition
Αν η εντολή σας ορίζει κάποια υποχρεωτικά positional arguments, μπορείτε να παραμετροποιήσετε το μήνυμα σφάλματος που επιστρέφεται, σε περίπτωση που αυτά τα arguments λείπουν. Προεπιλεγμένη τιμή είναι η έξοδος της
argparse(«too few arguments»).
- BaseCommand.output_transactionLink to this definition
Τύπου boolean που υποδεικνύει αν η εντολή θα εκτυπώσει (στην κονσόλα) εντολές SQL. Αν είναι
True, τότε η έξοδος θα συμπεριληφθεί μέσα σε έναBEGIN;καιCOMMIT;. Προεπιλεγμένη τιμή είναι τοFalse.
- BaseCommand.requires_migrations_checksLink to this definition
Τύπου boolean. Αν είναι
True, η εντολή θα εκτυπώσει ένα warning αν το σετ των migrations στο δίσκο δεν ταιριάζει με τα migrations στη βάση δεδομένων. Υπόψιν ότι, ένα warning δεν εμποδίζει την εντολή από το να εκτελεστεί. Προεπιλεγμένη τιμή είναι τοFalse.
- BaseCommand.requires_system_checksLink to this definition
Τύπου boolean. Αν είναι
True, τότε ολόκληρο το Django project σας θα ελεγχθεί για τυχόν σφάλματα πριν εκτελεστεί η εντολή. Προεπιλεγμένη τιμή είναι τοTrue.
- BaseCommand.styleLink to this definition
Ένα attribute που βοηθά στο να χρωματίσει την έξοδο (δηλαδή το κείμενο) όταν γράφετε στο
self.stdoutή στοself.stderr. Για παράδειγμα:self.stdout.write(self.style.SUCCESS('...'))Δείτε στο χρωματίζοντας την έξοδο για να μάθετε πως να τροποποιείτε την παλέτα των χρωμάτων και να δείτε τα διαθέσιμα στυλ (χρήση της έκδοσης των κεφαλαίων γραμμάτων των «ρόλων» όπως περιγράφονται σε αυτή την ενότητα).
Αν δηλώσετε την επιλογή
--no-colorόταν τρέχετε την εντολή σας, όλες οι κλήσεις τηςself.style()θα επιστρέψουν το αρχικό string χωρίς κάποιο χρώμα.
ΜέθοδοιLink to this heading
Η κλάση BaseCommand έχει μερικές μεθόδους οι οποίες μπορούν να παρακαμφθούν (overridden) αλλά μόνο η μέθοδος handle() πρέπει να υλοποιηθεί υποχρεωτικά.
- BaseCommand.create_parser(prog_name, subcommand, **kwargs)Link to this definition
Returns a
CommandParserinstance, which is anArgumentParsersubclass with a few customizations for Django.You can customize the instance by overriding this method and calling
super()withkwargsofArgumentParserparameters.
- BaseCommand.add_arguments(parser)Link to this definition
Σημείο εισόδου για να προσθέσετε arguments στο μεταφραστή (parser) για τον χειρισμό των arguments που εισάγονται στη γραμμή εντολών (όπως το argument
--deleteπου αναφέραμε παραπάνω). Τυχόν δικές σας διαχειριστικές εντολές θα πρέπει να παρακάμπτουν αυτή τη μέθοδο για να προσθέσουν positional και optional arguments που θα δέχεται η εντολή. Η κλήση τηςsuper()δεν είναι απαραίτητη όταν κάνετε απ’ ευθείας subclass την κλάσηBaseCommand.
- BaseCommand.get_version()Link to this definition
Επιστρέφει την έκδοση του Django, η οποία θα πρέπει να είναι η σωστή για όλες τις προεγκατεστημένες εντολές του Django. Τυχόν δικές σας διαχειριστικές εντολές μπορούν να παρακάμψουν αυτή τη μέθοδο για να επιστρέφουν τη δική τους έκδοση.
- BaseCommand.execute(*args, **options)Link to this definition
Προσπαθεί να εκτελέσει την εντολή που γράψατε, πραγματοποιεί τυχόν τεστ που αφορά το σύστημα (ανάλογα την τιμή του attribute
requires_system_checks). Αν η εντολή κάνει raise το exceptionCommandError, τότε θα εμφανιστεί ανάλογο σφάλμα στοstderr.
- BaseCommand.handle(*args, **options)Link to this definition
Η πραγματική λογική της εντολής. Όλες οι subclasses πρέπει να υλοποιήσουν αυτή τη μέθοδο.
It may return a string which will be printed to
stdout(wrapped byBEGIN;andCOMMIT;ifoutput_transactionisTrue).
- BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)Link to this definition
Χρησιμοποιεί το σύστημα ελέγχου του framework για να επιθεωρήσει ολόκληρο το Django project για τυχόν προβλήματα. Τα σοβαρά προβλήματα γίνονται raised ως
CommandError. Τα warnings εκτυπώνονται στοstderr. Τυχόν δευτερεύουσες ειδοποιήσεις εκτυπώνονται στοstdout.Αν τα ορίσματα
app_configsκαιtagsείναι και τα δύο τύπουNone, τότε θα γίνουν όλα τα συστήματα ελέγχου. Το όρισμαtagsμπορεί να είναι μια λίστα από check tags, όπωςcompatibilityήmodels.
BaseCommand subclassesLink to this heading
- class AppCommandLink to this definition
Μια εντολή διαχείρισης η οποία δέχεται ως arguments (όπως το <poll_id> στην εντολή που γράψαμε παραπάνω python manage.py closepoll <poll_id>) ένα ή περισσότερα labels εφαρμογών και κάνει κάτι με καθένα από αυτά.
Αντί της υλοποίησης της μεθόδου handle(), οι subclasses πρέπει να υλοποιούν τη μέθοδο handle_app_config() η οποία θα καλείται μια φορά για κάθε εφαρμογή.
- AppCommand.handle_app_config(app_config, **options)Link to this definition
Εκτελεί τις ενέργειες της εντολής για το
app_configτο οποίο θα είναι ένα instance της κλάσηςAppConfigπου αντιστοιχεί στο label της εφαρμογής που δόθηκε στη γραμμή εντολών.
- class LabelCommandLink to this definition
Μια εντολή διαχείρισης η οποία δέχεται ένα η περισσότερα arguments (labels) μέσω της γραμμής εντολών και κάνει κάτι με καθένα από αυτά.
Αντί της υλοποίησης της μεθόδου handle(), οι subclasses πρέπει να υλοποιούν τη μέθοδο handle_label(), η οποία θα καλείται μια φορά για κάθε label.
- LabelCommand.labelLink to this definition
Ένα αλφαριθμητικό (string) που περιγράφει τις παραμέτρους που δόθηκαν στην εντολή. Το αλφαριθμητικό χρησιμοποιείται στα μηνύματα σφαλμάτων καθώς και στο κείμενο περιγραφής της εντολής. Προεπιλογή είναι το
'label'.
- LabelCommand.handle_label(label, **options)Link to this definition
Εκτελεί τις ενέργειες της εντολής για το
label, το οποίο θα είναι ένα string όπως δόθηκε στη γραμμή εντολών.
Exceptions εντολήςLink to this heading
- exception CommandErrorLink to this definition
Μια κλάση Exception που υποδεικνύει ότι προέκυψε κάποιο πρόβλημα κατά τη διάρκεια εκτέλεσης της εντολής διαχείρισης.
Αν αυτό το exception γίνει raised κατά τη διάρκεια της εκτέλεσης, μέσω της κονσόλας, μιας διαχειριστικής εντολής, θα “πιαστεί” (caught) και θα μετατραπεί σε ένα όμορφα εκτυπώσιμο μήνυμα σφάλματος το οποίο θα προωθηθεί στην ανάλογη έξοδο προβολής (πχ stderr, stdout κλπ). Επομένως, ο καλύτερος τρόπος για να υποδείξετε ότι κάτι πήγε στραβά κατά τη διάρκεια της εκτέλεσης της εντολής σας, είναι κάνοντας raise αυτό το exception (με μια λογική περιγραφή του σφάλματος που προέκυψε, φυσικά).
Αν η εντολή διαχείρισης καλείται μέσα από τον κώδικα σας μέσω της συνάρτησης call_command(), τότε είναι δικό σας θέμα να κάνετε catch, όποτε το κρίνετε απαραίτητο, αυτό το exception.