django-cfg 1.5.8__py3-none-any.whl → 1.5.14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of django-cfg might be problematic. Click here for more details.

Files changed (119) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/commands/serializers.py +152 -0
  3. django_cfg/apps/api/commands/views.py +32 -0
  4. django_cfg/apps/business/accounts/management/commands/otp_test.py +5 -2
  5. django_cfg/apps/business/agents/management/commands/create_agent.py +5 -194
  6. django_cfg/apps/business/agents/management/commands/load_agent_templates.py +205 -0
  7. django_cfg/apps/business/agents/management/commands/orchestrator_status.py +4 -2
  8. django_cfg/apps/business/knowbase/management/commands/knowbase_stats.py +4 -2
  9. django_cfg/apps/business/knowbase/management/commands/setup_knowbase.py +4 -2
  10. django_cfg/apps/business/newsletter/management/commands/test_newsletter.py +5 -2
  11. django_cfg/apps/business/payments/management/commands/check_payment_status.py +4 -2
  12. django_cfg/apps/business/payments/management/commands/create_payment.py +4 -2
  13. django_cfg/apps/business/payments/management/commands/sync_currencies.py +4 -2
  14. django_cfg/apps/integrations/centrifugo/management/commands/generate_centrifugo_clients.py +5 -5
  15. django_cfg/apps/integrations/centrifugo/serializers/__init__.py +2 -1
  16. django_cfg/apps/integrations/centrifugo/serializers/publishes.py +22 -2
  17. django_cfg/apps/integrations/centrifugo/views/monitoring.py +25 -40
  18. django_cfg/apps/integrations/grpc/admin/__init__.py +7 -1
  19. django_cfg/apps/integrations/grpc/admin/config.py +113 -9
  20. django_cfg/apps/integrations/grpc/admin/grpc_api_key.py +129 -0
  21. django_cfg/apps/integrations/grpc/admin/grpc_request_log.py +72 -63
  22. django_cfg/apps/integrations/grpc/admin/grpc_server_status.py +236 -0
  23. django_cfg/apps/integrations/grpc/auth/__init__.py +11 -3
  24. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +320 -0
  25. django_cfg/apps/integrations/grpc/interceptors/logging.py +17 -20
  26. django_cfg/apps/integrations/grpc/interceptors/metrics.py +15 -14
  27. django_cfg/apps/integrations/grpc/interceptors/request_logger.py +79 -59
  28. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +130 -0
  29. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +171 -96
  30. django_cfg/apps/integrations/grpc/management/commands/test_grpc_integration.py +75 -0
  31. django_cfg/apps/integrations/grpc/managers/__init__.py +2 -0
  32. django_cfg/apps/integrations/grpc/managers/grpc_api_key.py +192 -0
  33. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +19 -11
  34. django_cfg/apps/integrations/grpc/migrations/0005_grpcapikey.py +143 -0
  35. django_cfg/apps/integrations/grpc/migrations/0006_grpcrequestlog_api_key_and_more.py +34 -0
  36. django_cfg/apps/integrations/grpc/models/__init__.py +2 -0
  37. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +198 -0
  38. django_cfg/apps/integrations/grpc/models/grpc_request_log.py +11 -0
  39. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +39 -4
  40. django_cfg/apps/integrations/grpc/serializers/__init__.py +22 -6
  41. django_cfg/apps/integrations/grpc/serializers/api_keys.py +63 -0
  42. django_cfg/apps/integrations/grpc/serializers/charts.py +118 -120
  43. django_cfg/apps/integrations/grpc/serializers/config.py +65 -51
  44. django_cfg/apps/integrations/grpc/serializers/health.py +7 -7
  45. django_cfg/apps/integrations/grpc/serializers/proto_files.py +74 -0
  46. django_cfg/apps/integrations/grpc/serializers/requests.py +13 -7
  47. django_cfg/apps/integrations/grpc/serializers/service_registry.py +181 -112
  48. django_cfg/apps/integrations/grpc/serializers/services.py +14 -32
  49. django_cfg/apps/integrations/grpc/serializers/stats.py +50 -12
  50. django_cfg/apps/integrations/grpc/serializers/testing.py +66 -58
  51. django_cfg/apps/integrations/grpc/services/__init__.py +2 -0
  52. django_cfg/apps/integrations/grpc/services/monitoring_service.py +149 -43
  53. django_cfg/apps/integrations/grpc/services/proto_files_manager.py +268 -0
  54. django_cfg/apps/integrations/grpc/services/service_registry.py +48 -46
  55. django_cfg/apps/integrations/grpc/services/testing_service.py +10 -15
  56. django_cfg/apps/integrations/grpc/urls.py +8 -0
  57. django_cfg/apps/integrations/grpc/utils/__init__.py +4 -13
  58. django_cfg/apps/integrations/grpc/utils/integration_test.py +334 -0
  59. django_cfg/apps/integrations/grpc/utils/proto_gen.py +48 -8
  60. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +177 -0
  61. django_cfg/apps/integrations/grpc/views/__init__.py +4 -0
  62. django_cfg/apps/integrations/grpc/views/api_keys.py +255 -0
  63. django_cfg/apps/integrations/grpc/views/charts.py +21 -14
  64. django_cfg/apps/integrations/grpc/views/config.py +8 -6
  65. django_cfg/apps/integrations/grpc/views/monitoring.py +51 -79
  66. django_cfg/apps/integrations/grpc/views/proto_files.py +214 -0
  67. django_cfg/apps/integrations/grpc/views/services.py +30 -21
  68. django_cfg/apps/integrations/grpc/views/testing.py +45 -43
  69. django_cfg/apps/integrations/rq/views/jobs.py +19 -9
  70. django_cfg/apps/integrations/rq/views/schedule.py +7 -3
  71. django_cfg/apps/system/dashboard/serializers/commands.py +25 -1
  72. django_cfg/apps/system/dashboard/services/commands_service.py +12 -1
  73. django_cfg/apps/system/maintenance/management/commands/maintenance.py +5 -2
  74. django_cfg/apps/system/maintenance/management/commands/process_scheduled_maintenance.py +4 -2
  75. django_cfg/apps/system/maintenance/management/commands/sync_cloudflare.py +5 -2
  76. django_cfg/config.py +33 -0
  77. django_cfg/core/generation/integration_generators/grpc_generator.py +30 -32
  78. django_cfg/management/commands/check_endpoints.py +2 -2
  79. django_cfg/management/commands/check_settings.py +3 -10
  80. django_cfg/management/commands/clear_constance.py +3 -10
  81. django_cfg/management/commands/create_token.py +4 -11
  82. django_cfg/management/commands/list_urls.py +4 -10
  83. django_cfg/management/commands/migrate_all.py +18 -12
  84. django_cfg/management/commands/migrator.py +4 -11
  85. django_cfg/management/commands/script.py +4 -10
  86. django_cfg/management/commands/show_config.py +8 -16
  87. django_cfg/management/commands/show_urls.py +5 -11
  88. django_cfg/management/commands/superuser.py +4 -11
  89. django_cfg/management/commands/tree.py +5 -10
  90. django_cfg/management/utils/README.md +402 -0
  91. django_cfg/management/utils/__init__.py +29 -0
  92. django_cfg/management/utils/mixins.py +176 -0
  93. django_cfg/middleware/pagination.py +53 -54
  94. django_cfg/models/api/grpc/__init__.py +15 -21
  95. django_cfg/models/api/grpc/config.py +155 -73
  96. django_cfg/models/ngrok/config.py +7 -6
  97. django_cfg/modules/django_client/core/generator/python/files_generator.py +5 -13
  98. django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +16 -4
  99. django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +2 -3
  100. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +6 -5
  101. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +12 -8
  102. django_cfg/modules/django_client/core/parser/base.py +114 -30
  103. django_cfg/modules/django_client/management/commands/generate_client.py +5 -2
  104. django_cfg/modules/django_client/management/commands/validate_openapi.py +5 -2
  105. django_cfg/modules/django_email/management/commands/test_email.py +4 -10
  106. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +16 -13
  107. django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -11
  108. django_cfg/modules/django_twilio/management/commands/test_twilio.py +4 -11
  109. django_cfg/modules/django_unfold/navigation.py +6 -18
  110. django_cfg/pyproject.toml +1 -1
  111. django_cfg/registry/modules.py +1 -4
  112. django_cfg/requirements.txt +52 -0
  113. django_cfg/static/frontend/admin.zip +0 -0
  114. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/METADATA +1 -1
  115. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/RECORD +118 -97
  116. django_cfg/apps/integrations/grpc/auth/jwt_auth.py +0 -295
  117. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/WHEEL +0 -0
  118. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/entry_points.txt +0 -0
  119. {django_cfg-1.5.8.dist-info → django_cfg-1.5.14.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,402 @@
1
+ # Django Management Command Base Classes
2
+
3
+ Simplified base classes for Django management commands with automatic logger initialization and web execution safety metadata.
4
+
5
+ ## Features
6
+
7
+ - **Automatic Logger**: No need to manually create loggers - use `self.logger`
8
+ - **Security Metadata**: Integrated with django_cfg's web execution security system
9
+ - **DRY Principle**: Eliminate boilerplate code in every command
10
+ - **Type Safety**: Clear command categorization with semantic base classes
11
+
12
+ ## Available Base Classes
13
+
14
+ ### 1. SafeCommand
15
+ For read-only commands safe for web execution.
16
+
17
+ ```python
18
+ from django_cfg.management.utils import SafeCommand
19
+
20
+ class Command(SafeCommand):
21
+ help = 'Display current configuration'
22
+
23
+ def handle(self, *args, **options):
24
+ self.logger.info("Showing configuration")
25
+ # Read-only operations
26
+ ```
27
+
28
+ **Metadata:**
29
+ - `web_executable = True`
30
+ - `requires_input = False`
31
+ - `is_destructive = False`
32
+
33
+ **Use for:** show_config, list_urls, check_settings
34
+
35
+ ---
36
+
37
+ ### 2. InteractiveCommand
38
+ For commands requiring user input (blocked from web).
39
+
40
+ ```python
41
+ from django_cfg.management.utils import InteractiveCommand
42
+
43
+ class Command(InteractiveCommand):
44
+ help = 'Create superuser with prompts'
45
+
46
+ def handle(self, *args, **options):
47
+ self.logger.info("Creating superuser")
48
+ username = input("Username: ")
49
+ # Interactive operations
50
+ ```
51
+
52
+ **Metadata:**
53
+ - `web_executable = False`
54
+ - `requires_input = True`
55
+ - `is_destructive = False`
56
+
57
+ **Use for:** superuser, createsuperuser, any command with `input()` or `questionary`
58
+
59
+ ---
60
+
61
+ ### 3. DestructiveCommand
62
+ For commands that modify or delete data (blocked from web).
63
+
64
+ ```python
65
+ from django_cfg.management.utils import DestructiveCommand
66
+
67
+ class Command(DestructiveCommand):
68
+ help = 'Clear all cache data'
69
+
70
+ def handle(self, *args, **options):
71
+ self.logger.warning("Clearing cache")
72
+ # Destructive operations
73
+ ```
74
+
75
+ **Metadata:**
76
+ - `web_executable = False`
77
+ - `requires_input = True`
78
+ - `is_destructive = True`
79
+
80
+ **Use for:** clear_constance, flush, clear cache commands
81
+
82
+ ---
83
+
84
+ ### 4. AdminCommand
85
+ For administrative commands safe for web execution.
86
+
87
+ ```python
88
+ from django_cfg.management.utils import AdminCommand
89
+
90
+ class Command(AdminCommand):
91
+ help = 'Run database migrations'
92
+
93
+ def handle(self, *args, **options):
94
+ self.logger.info("Running migrations")
95
+ # Admin operations
96
+ ```
97
+
98
+ **Metadata:**
99
+ - `web_executable = True`
100
+ - `requires_input = False`
101
+ - `is_destructive = False`
102
+
103
+ **Use for:** migrate, collectstatic, createcachetable
104
+
105
+ ---
106
+
107
+ ## Refactoring Examples
108
+
109
+ ### Before: Manual Logger & Metadata (15 lines)
110
+
111
+ ```python
112
+ from django.core.management.base import BaseCommand
113
+ from django_cfg.modules.django_logging import get_logger
114
+
115
+ logger = get_logger('show_config')
116
+
117
+ class Command(BaseCommand):
118
+ logger = get_logger('show_config') # Duplicate!
119
+
120
+ # Web execution metadata
121
+ web_executable = True
122
+ requires_input = False
123
+ is_destructive = False
124
+
125
+ help = 'Show Django Config configuration'
126
+
127
+ def handle(self, *args, **options):
128
+ logger.info("Starting command")
129
+ # Command logic
130
+ ```
131
+
132
+ ### After: Using SafeCommand (5 lines)
133
+
134
+ ```python
135
+ from django_cfg.management.utils import SafeCommand
136
+
137
+ class Command(SafeCommand):
138
+ help = 'Show Django Config configuration'
139
+
140
+ def handle(self, *args, **options):
141
+ self.logger.info("Starting command")
142
+ # Command logic
143
+ ```
144
+
145
+ **Result: 67% less boilerplate code!**
146
+
147
+ ---
148
+
149
+ ## More Examples
150
+
151
+ ### Example 1: clear_constance.py
152
+
153
+ **Before:**
154
+ ```python
155
+ from django.core.management.base import BaseCommand
156
+ from django_cfg.modules.django_logging import get_logger
157
+
158
+ class Command(BaseCommand):
159
+ logger = get_logger('clear_constance')
160
+
161
+ web_executable = False
162
+ requires_input = True
163
+ is_destructive = True
164
+
165
+ help = 'Clear Constance configuration cache'
166
+
167
+ def handle(self, *args, **options):
168
+ self.logger.info("Clearing cache")
169
+ ```
170
+
171
+ **After:**
172
+ ```python
173
+ from django_cfg.management.utils import DestructiveCommand
174
+
175
+ class Command(DestructiveCommand):
176
+ command_name = 'clear_constance' # Optional: for custom logger name
177
+ help = 'Clear Constance configuration cache'
178
+
179
+ def handle(self, *args, **options):
180
+ self.logger.info("Clearing cache")
181
+ ```
182
+
183
+ ---
184
+
185
+ ### Example 2: superuser.py
186
+
187
+ **Before:**
188
+ ```python
189
+ from django.core.management.base import BaseCommand
190
+ from django_cfg.modules.django_logging import get_logger
191
+ import questionary
192
+
193
+ logger = get_logger('superuser')
194
+
195
+ class Command(BaseCommand):
196
+ web_executable = False
197
+ requires_input = True
198
+ is_destructive = False
199
+
200
+ help = 'Create superuser'
201
+
202
+ def handle(self, *args, **options):
203
+ logger.info("Starting")
204
+ username = questionary.text("Username:").ask()
205
+ ```
206
+
207
+ **After:**
208
+ ```python
209
+ from django_cfg.management.utils import InteractiveCommand
210
+ import questionary
211
+
212
+ class Command(InteractiveCommand):
213
+ help = 'Create superuser'
214
+
215
+ def handle(self, *args, **options):
216
+ self.logger.info("Starting")
217
+ username = questionary.text("Username:").ask()
218
+ ```
219
+
220
+ ---
221
+
222
+ ### Example 3: migrate_all.py
223
+
224
+ **Before:**
225
+ ```python
226
+ from django.core.management.base import BaseCommand
227
+ from django_cfg.modules.django_logging import get_logger
228
+
229
+ class Command(BaseCommand):
230
+ logger = get_logger('migrate_all')
231
+
232
+ web_executable = True
233
+ requires_input = False
234
+ is_destructive = False
235
+
236
+ help = 'Run migrations'
237
+
238
+ def handle(self, *args, **options):
239
+ self.logger.info("Running migrations")
240
+ ```
241
+
242
+ **After:**
243
+ ```python
244
+ from django_cfg.management.utils import AdminCommand
245
+
246
+ class Command(AdminCommand):
247
+ help = 'Run migrations'
248
+
249
+ def handle(self, *args, **options):
250
+ self.logger.info("Running migrations")
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Custom Logger Name
256
+
257
+ By default, the logger name is auto-detected from the module name. To override:
258
+
259
+ ```python
260
+ class Command(SafeCommand):
261
+ command_name = 'my_custom_logger_name'
262
+ help = 'My command'
263
+ ```
264
+
265
+ ---
266
+
267
+ ## Quick Selection Guide
268
+
269
+ ```
270
+ ┌─────────────────────────────────────┬─────────────────────┐
271
+ │ Command Type │ Use This │
272
+ ├─────────────────────────────────────┼─────────────────────┤
273
+ │ Read-only (no modifications) │ SafeCommand │
274
+ │ Requires input() or questionary │ InteractiveCommand │
275
+ │ Deletes or modifies data │ DestructiveCommand │
276
+ │ Admin tasks (migrations, etc) │ AdminCommand │
277
+ └─────────────────────────────────────┴─────────────────────┘
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Security Integration
283
+
284
+ These base classes integrate with django_cfg's security system:
285
+
286
+ 1. **commands_security.py** - Analyzes `web_executable`, `requires_input`, `is_destructive` attributes
287
+ 2. **commands_service.py** - Filters commands based on safety metadata
288
+ 3. **API views** - Blocks unsafe commands from web execution
289
+
290
+ When you use these base classes, your commands are automatically categorized and protected.
291
+
292
+ ---
293
+
294
+ ## Refactoring Checklist
295
+
296
+ When refactoring existing commands:
297
+
298
+ - [ ] Remove `from django_cfg.modules.django_logging import get_logger`
299
+ - [ ] Remove `logger = get_logger('...')` (both global and in class)
300
+ - [ ] Choose appropriate base class (SafeCommand, InteractiveCommand, etc)
301
+ - [ ] Import base class: `from django_cfg.management.utils import SafeCommand`
302
+ - [ ] Change inheritance: `class Command(SafeCommand):`
303
+ - [ ] Remove metadata attributes (if they match base class defaults)
304
+ - [ ] Replace `logger.info()` with `self.logger.info()`
305
+ - [ ] Add `command_name = '...'` if custom logger name needed
306
+ - [ ] Test the command
307
+
308
+ ---
309
+
310
+ ## Migration Strategy
311
+
312
+ ### Find All Commands to Refactor
313
+
314
+ ```bash
315
+ # Find all commands with manual metadata
316
+ find . -name "*.py" -path "*/management/commands/*" -exec grep -l "web_executable" {} \;
317
+ ```
318
+
319
+ ### Refactor by Priority
320
+
321
+ 1. **Start with SafeCommand** - Easiest wins, most common
322
+ 2. **Then InteractiveCommand** - Clear pattern with input()
323
+ 3. **Then DestructiveCommand** - Important for security
324
+ 4. **Finally AdminCommand** - Review case-by-case
325
+
326
+ ### Testing
327
+
328
+ ```bash
329
+ # Test command help
330
+ python manage.py <command> --help
331
+
332
+ # Test command execution
333
+ python manage.py <command>
334
+
335
+ # Test logger
336
+ # Should see: "Command initialized: <name> (web_executable=..., ...)"
337
+ ```
338
+
339
+ ---
340
+
341
+ ## Advanced: Override Metadata
342
+
343
+ If you need custom metadata different from base class defaults:
344
+
345
+ ```python
346
+ from django_cfg.management.utils import SafeCommand
347
+
348
+ class Command(SafeCommand):
349
+ # Override defaults if needed
350
+ web_executable = False # Make it non-web-executable
351
+ is_destructive = True # Mark as destructive
352
+
353
+ help = 'Special command'
354
+ ```
355
+
356
+ Though generally, if you need different metadata, choose a different base class.
357
+
358
+ ---
359
+
360
+ ## Benefits Summary
361
+
362
+ | Feature | Before | After |
363
+ |---------|--------|-------|
364
+ | Lines of boilerplate | ~15 lines | ~3 lines |
365
+ | Logger setup | Manual | Automatic |
366
+ | Metadata | Manual | Automatic |
367
+ | Type safety | None | Built-in |
368
+ | Code clarity | Low | High |
369
+ | Maintenance | Hard | Easy |
370
+
371
+ ---
372
+
373
+ ## FAQ
374
+
375
+ **Q: Can I still use `BaseCommand` directly?**
376
+ A: Yes, but you'll need to manually add logger and metadata.
377
+
378
+ **Q: What if I need different metadata than the base classes?**
379
+ A: Choose the closest base class or override the attributes you need.
380
+
381
+ **Q: Does this work with existing Django commands?**
382
+ A: Yes, these are just base classes that extend `BaseCommand`.
383
+
384
+ **Q: Can I use multiple inheritance?**
385
+ A: Not needed - each base class already has everything you need.
386
+
387
+ **Q: What about existing code using the old approach?**
388
+ A: Both approaches work. Refactor gradually as you touch files.
389
+
390
+ ---
391
+
392
+ ## Support
393
+
394
+ For issues or questions:
395
+ - Check `commands_security.py` for security system details
396
+ - Review `commands_service.py` for filtering logic
397
+ - See `mixins.py` source code for implementation
398
+
399
+ ---
400
+
401
+ **Last Updated:** 2025-01-04
402
+ **Version:** 1.0.0
@@ -0,0 +1,29 @@
1
+ """
2
+ Django Management Command Utilities
3
+
4
+ Ready-to-use base classes for Django management commands.
5
+
6
+ Quick Start:
7
+ from django_cfg.management.utils import SafeCommand
8
+
9
+ class Command(SafeCommand):
10
+ help = 'My safe command'
11
+
12
+ def handle(self, *args, **options):
13
+ self.logger.info("Running command")
14
+ # Your code here
15
+ """
16
+
17
+ from .mixins import (
18
+ AdminCommand,
19
+ DestructiveCommand,
20
+ InteractiveCommand,
21
+ SafeCommand,
22
+ )
23
+
24
+ __all__ = [
25
+ 'SafeCommand',
26
+ 'InteractiveCommand',
27
+ 'DestructiveCommand',
28
+ 'AdminCommand',
29
+ ]
@@ -0,0 +1,176 @@
1
+ """
2
+ Django Management Command Base Classes
3
+
4
+ Ready-to-use base classes for Django management commands with automatic
5
+ logger initialization and web execution safety metadata.
6
+
7
+ Security Integration:
8
+ These classes integrate with django_cfg's security system via:
9
+ - commands_security.py: Analyzes web_executable, requires_input, is_destructive
10
+ - commands_service.py: Filters commands based on safety metadata
11
+ - API views: Blocks unsafe commands from web execution
12
+
13
+ Available Classes:
14
+ - SafeCommand: Read-only, web-executable commands
15
+ - InteractiveCommand: Commands requiring user input (blocked from web)
16
+ - DestructiveCommand: Commands that modify/delete data (blocked from web)
17
+ - AdminCommand: Administrative commands (safe for web execution)
18
+ """
19
+
20
+ from django.core.management.base import BaseCommand
21
+
22
+ from django_cfg.modules.django_logging import get_logger
23
+
24
+
25
+ class _BaseCommandWithMetadata(BaseCommand):
26
+ """
27
+ Internal base class that adds logger and metadata to commands.
28
+
29
+ Do not use directly - use SafeCommand, InteractiveCommand, etc.
30
+ """
31
+
32
+ # Default safety metadata (override in subclasses)
33
+ web_executable = False
34
+ requires_input = False
35
+ is_destructive = False
36
+
37
+ def __init__(self, *args, **kwargs):
38
+ """Initialize command with automatic logger."""
39
+ super().__init__(*args, **kwargs)
40
+
41
+ # Auto-detect command name from module if not set
42
+ if not hasattr(self, 'command_name'):
43
+ self.command_name = self.__module__.split('.')[-1]
44
+
45
+ # Initialize logger
46
+ command_name = f"command.{self.command_name}"
47
+ self.logger = get_logger(command_name)
48
+
49
+ # Log initialization in debug mode
50
+ self.logger.debug(
51
+ f"Command initialized: {self.command_name} "
52
+ f"(web_executable={self.web_executable}, "
53
+ f"requires_input={self.requires_input}, "
54
+ f"is_destructive={self.is_destructive})"
55
+ )
56
+
57
+
58
+ class SafeCommand(_BaseCommandWithMetadata):
59
+ """
60
+ Base class for safe, read-only commands that can be executed via web.
61
+
62
+ Use this for commands that:
63
+ - Only read data (no modifications)
64
+ - Don't require user input
65
+ - Are safe to run from web interface
66
+
67
+ Examples: show_config, list_urls, check_settings
68
+
69
+ Usage:
70
+ class Command(SafeCommand):
71
+ help = 'Display current configuration'
72
+
73
+ def handle(self, *args, **options):
74
+ self.logger.info("Showing configuration")
75
+ # Read-only operations here
76
+
77
+ Metadata:
78
+ web_executable = True
79
+ requires_input = False
80
+ is_destructive = False
81
+ """
82
+
83
+ web_executable = True
84
+ requires_input = False
85
+ is_destructive = False
86
+
87
+
88
+ class InteractiveCommand(_BaseCommandWithMetadata):
89
+ """
90
+ Base class for interactive commands requiring user input.
91
+
92
+ Use this for commands that:
93
+ - Require input() or questionary prompts
94
+ - Need user interaction
95
+ - Cannot run via web interface
96
+
97
+ Examples: superuser, createsuperuser
98
+
99
+ Usage:
100
+ class Command(InteractiveCommand):
101
+ help = 'Create superuser with prompts'
102
+
103
+ def handle(self, *args, **options):
104
+ self.logger.info("Creating superuser")
105
+ username = input("Username: ")
106
+ # Interactive operations here
107
+
108
+ Metadata:
109
+ web_executable = False
110
+ requires_input = True
111
+ is_destructive = False
112
+ """
113
+
114
+ web_executable = False
115
+ requires_input = True
116
+ is_destructive = False
117
+
118
+
119
+ class DestructiveCommand(_BaseCommandWithMetadata):
120
+ """
121
+ Base class for destructive commands that modify or delete data.
122
+
123
+ Use this for commands that:
124
+ - Delete or modify data
125
+ - Clear caches
126
+ - Perform irreversible operations
127
+
128
+ Examples: clear_constance, flush, sqlflush
129
+
130
+ Usage:
131
+ class Command(DestructiveCommand):
132
+ help = 'Clear all cache data'
133
+
134
+ def handle(self, *args, **options):
135
+ self.logger.warning("Clearing cache - destructive operation")
136
+ # Destructive operations here
137
+
138
+ Metadata:
139
+ web_executable = False
140
+ requires_input = True
141
+ is_destructive = True
142
+ """
143
+
144
+ web_executable = False
145
+ requires_input = True
146
+ is_destructive = True
147
+
148
+
149
+ class AdminCommand(_BaseCommandWithMetadata):
150
+ """
151
+ Base class for administrative commands safe for web execution.
152
+
153
+ Use this for commands that:
154
+ - Perform administrative tasks
155
+ - Are safe despite needing privileges
156
+ - Can be run via web interface
157
+
158
+ Examples: migrate, collectstatic, createcachetable
159
+
160
+ Usage:
161
+ class Command(AdminCommand):
162
+ help = 'Run database migrations'
163
+
164
+ def handle(self, *args, **options):
165
+ self.logger.info("Running migrations")
166
+ # Admin operations here
167
+
168
+ Metadata:
169
+ web_executable = True
170
+ requires_input = False
171
+ is_destructive = False
172
+ """
173
+
174
+ web_executable = True
175
+ requires_input = False
176
+ is_destructive = False