Skip to content

Commit 5b09512

Browse files
committed
Django Custom Commands
1 parent bf37491 commit 5b09512

File tree

1 file changed

+226
-0
lines changed

1 file changed

+226
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
---
2+
title : Django Custom Commands
3+
sidebar_label : Custom Commands
4+
---
5+
6+
# Django Custom Commands
7+
8+
<SubHeading>Learn how to add our own commands in Django Framework</SubHeading>
9+
10+
This article explains how to **write our own Django custom commands** that might help us to test, upload data or extract valuable information in a production environment from a Django project.
11+
12+
For newcomers, [Django](https://www.djangoproject.com/) is a popular web framework designed and written in Python by experienced developers.
13+
14+
The main advantage of a custom command is that all Django machinery is loaded and ready to be used.
15+
That means you can import models, execute queries to the database using Django’s ORM and interact with all your project’s resources.
16+
17+
![Django Releases - Tutorial provided by AppSeed.](https://user-images.githubusercontent.com/51070104/268675023-54ea4ace-a8ad-442b-9b43-2ba12a6403ba.jpg)
18+
19+
> Topics
20+
21+
- Create a new Django App and Update Django to use it
22+
- Visualize the required directory structure inside the app
23+
- Code end execute a few custom commands:
24+
- `cmd_time.py` - show current timestamp
25+
- `cmd_apps` - list all registered apps
26+
- `cmd_models` - list all apps and associated models
27+
- `cmd_showcfg` - list all CFG keys and values
28+
- The [source code](https://github.com/app-generator/django-learn-by-coding) can be found on Github (MIT License)
29+
30+
## ✅ Create a new Django App
31+
32+
This tutorial assumes that we have a working Django project and we will move forward and create a new app via startapp subcommand:
33+
34+
```bash
35+
$ python manage.py startapp app_customcmd
36+
```
37+
38+
Inside the new app directory, we need to create a directory structure as shown below:
39+
40+
```bash
41+
< PROJECT ROOT > <-- project directory
42+
|
43+
|-- app_customcmd/ <-- app directory
44+
| |-- management/
45+
| | +-- __init__.py
46+
| | +-- commands/
47+
| | +-- __init__.py
48+
| | +-- cmd_....py <-- module where all commands are saved
49+
```
50+
51+
Once we have built and configure Django to use the new app, all commands defined in commands directory are automatically discovered even without an application restart.
52+
53+
## ✅ Configure Django
54+
55+
To execute our custom commands we need to activate app_customcmd in the project configuration:
56+
57+
```python
58+
INSTALLED_APPS = [
59+
'django.contrib.admin',
60+
'django.contrib.auth',
61+
'django.contrib.contenttypes',
62+
'django.contrib.sessions',
63+
'django.contrib.messages',
64+
'django.contrib.staticfiles',
65+
'app_customcmd', # <-- NEW
66+
]
67+
```
68+
69+
## ✅ Custom Commands
70+
71+
This section presents for custom commands that will access and report a few things related to a Django project internals - Let's go!
72+
73+
### Show Current Time
74+
75+
This simple custom command help us to accommodate with the concept. Here is the code, saved in the `app_customcmd/management/commands` directory:
76+
77+
```python
78+
from django.core.management.base import BaseCommand
79+
from django.utils import timezone
80+
81+
class Command(BaseCommand):
82+
help = 'Displays current time'
83+
84+
def handle(self, *args, **kwargs):
85+
time = timezone.now().strftime('%X')
86+
self.stdout.write("It's %s" % time)
87+
```
88+
89+
The actual executed code resides in the handle method and the execution should display something similar to this:
90+
91+
```bash
92+
$ python manage.py cmd_time
93+
It 09:18:08 <-- The output from our custom CMD
94+
```
95+
96+
The most important aspect regarding the code is the usage of BaseCommand as a super-class for our definition.
97+
98+
### Show Registered Apps
99+
100+
This sample will iterate over all registered and active apps and print their names.
101+
102+
```python
103+
from django.core.management.base import BaseCommand
104+
from django.apps import apps
105+
106+
class Command(BaseCommand):
107+
help = 'Displays registered apps'
108+
109+
def handle(self, *args, **kwargs):
110+
for app in apps.get_app_configs():
111+
self.stdout.write(" APP -> %s" % app.verbose_name)
112+
```
113+
114+
> **Script execution and output**
115+
116+
```bash
117+
$ python manage.py cmd_apps
118+
APP -> Administration # Default Django App
119+
APP -> Authentication and Authorization # Default Django App
120+
APP -> Content Types # Default Django App
121+
APP -> Sessions # Default Django App
122+
APP -> Messages # Default Django App
123+
APP -> Static Files # Default Django App
124+
APP -> App_Customcmd # <-- Our NEW App
125+
```
126+
127+
### Show models for each app
128+
129+
This command is quite similar with the previous one, but provide also the registered models for each app.
130+
131+
```python
132+
from django.core.management.base import BaseCommand
133+
134+
from django.apps import apps
135+
136+
class Command(BaseCommand):
137+
help = 'Displays registered apps and models'
138+
139+
def handle(self, *args, **kwargs):
140+
141+
# Iterate over apps
142+
for app in apps.get_app_configs():
143+
self.stdout.write(" APP -> %s" % app.verbose_name)
144+
145+
# Iterate over models # <-- New Code
146+
for model in app.get_models(): # <-- New Code
147+
self.stdout.write("\t |- (model) -> %s" % model) # <-- New Code
148+
```
149+
150+
> **The execution and output**
151+
152+
```bash
153+
$ python manage.py cmd_models
154+
APP -> Administration
155+
|- (model) -> <class 'django.contrib.admin.models.LogEntry'>
156+
APP -> Authentication and Authorization
157+
|- (model) -> <class 'django.contrib.auth.models.Permission'>
158+
|- (model) -> <class 'django.contrib.auth.models.Group'>
159+
|- (model) -> <class 'django.contrib.auth.models.User'>
160+
APP -> Content Types
161+
|- (model) -> <class 'django.contrib.contenttypes.models.ContentType'>
162+
APP -> Sessions
163+
|- (model) -> <class 'django.contrib.sessions.models.Session'>
164+
APP -> Messages
165+
APP -> Static Files
166+
APP -> App_Forms
167+
APP -> App_Pdf
168+
APP -> App_Customcmd
169+
APP -> App
170+
|- (model) -> <class 'app.models.Book'>
171+
```
172+
173+
### Print Config Variables
174+
175+
This custom command scan the settings object for proprieties and print all values.
176+
177+
```python
178+
from django.core.management.base import BaseCommand
179+
from django.utils import timezone
180+
181+
from django.conf import settings
182+
183+
class Command(BaseCommand):
184+
help = 'Displays project config'
185+
186+
def handle(self, *args, **kwargs):
187+
188+
# type( settings ) => <class 'django.conf.LazySettings'>
189+
# settings.__dict__
190+
191+
# Iterate over apps
192+
for key in settings.__dict__.keys():
193+
194+
self.stdout.write(" Cfg Key: " + key + " -> %s" % settings.__dict__[ key ] )
195+
```
196+
197+
> **The output and execution**
198+
199+
```bash
200+
(env) PS D:\work\repo-samples\django-learn-by-coding> python manage.py cmd_showcfg
201+
Cfg Key: _wrapped -> <Settings "config.settings">
202+
Cfg Key: INSTALLED_APPS -> ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app_forms', 'app_pdf', 'app_customcmd', 'app']
203+
Cfg Key: DEBUG -> True
204+
Cfg Key: LOGGING_CONFIG -> logging.config.dictConfig
205+
Cfg Key: LOGGING -> {}
206+
Cfg Key: DEFAULT_EXCEPTION_REPORTER -> django.views.debug.ExceptionReporter
207+
Cfg Key: FORCE_SCRIPT_NAME -> None
208+
Cfg Key: DEFAULT_TABLESPACE ->
209+
Cfg Key: DEFAULT_AUTO_FIELD -> django.db.models.BigAutoField
210+
Cfg Key: ABSOLUTE_URL_OVERRIDES -> {}
211+
Cfg Key: AUTH_USER_MODEL -> auth.User
212+
Cfg Key: DATABASES -> {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': WindowsPath('D:/work/repo-samples/django-learn-by-coding/db.sqlite3'), 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None, 'USER': '', 'PASSWORD': '', 'HOST': '', 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'MIGRATE': True, 'MIRROR': None, 'NAME': None}}}
213+
...
214+
(truncated output)
215+
```
216+
217+
## ✅ In Summary
218+
219+
Writing custom commands in our Django projects might help us to extract stats, execute cron jobs, and check the health of a project that runs in production.
220+
221+
## ✅ Resources
222+
223+
- 👉 Access [AppSeed](https://appseed.us/) and start your next project
224+
- 👉 [Deploy Projects on Aws, Azure and Digital Ocean](https://www.docs.deploypro.dev/) via **DeployPRO**
225+
- 👉 Create an amazing landing page with [Simpllo, an open-source site builder](https://www.simpllo.com/)
226+
- 👉 [Django App Generator](https://app-generator.dev/django/) - A 2nd generation App Builder

0 commit comments

Comments
 (0)