django-cfg 1.4.10__py3-none-any.whl → 1.4.11__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.
Files changed (181) hide show
  1. django_cfg/apps/agents/management/commands/create_agent.py +1 -1
  2. django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
  3. django_cfg/apps/newsletter/serializers.py +40 -3
  4. django_cfg/apps/newsletter/views/campaigns.py +12 -3
  5. django_cfg/apps/newsletter/views/emails.py +14 -3
  6. django_cfg/apps/newsletter/views/subscriptions.py +12 -2
  7. django_cfg/apps/payments/views/api/currencies.py +49 -6
  8. django_cfg/apps/payments/views/api/webhooks.py +72 -7
  9. django_cfg/apps/payments/views/overview/serializers.py +34 -1
  10. django_cfg/apps/payments/views/overview/views.py +2 -1
  11. django_cfg/apps/payments/views/serializers/payments.py +6 -6
  12. django_cfg/apps/urls.py +106 -45
  13. django_cfg/core/base/config_model.py +2 -2
  14. django_cfg/core/constants.py +1 -1
  15. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  16. django_cfg/core/generation/integration_generators/api.py +72 -49
  17. django_cfg/core/integration/display/startup.py +30 -22
  18. django_cfg/core/integration/url_integration.py +15 -16
  19. django_cfg/dashboard/sections/documentation.py +391 -0
  20. django_cfg/management/commands/check_endpoints.py +11 -160
  21. django_cfg/management/commands/check_settings.py +13 -348
  22. django_cfg/management/commands/clear_constance.py +13 -201
  23. django_cfg/management/commands/create_token.py +13 -321
  24. django_cfg/management/commands/generate_clients.py +23 -0
  25. django_cfg/management/commands/list_urls.py +13 -306
  26. django_cfg/management/commands/migrate_all.py +13 -126
  27. django_cfg/management/commands/migrator.py +13 -396
  28. django_cfg/management/commands/rundramatiq.py +15 -247
  29. django_cfg/management/commands/rundramatiq_simulator.py +12 -429
  30. django_cfg/management/commands/runserver_ngrok.py +15 -160
  31. django_cfg/management/commands/script.py +12 -488
  32. django_cfg/management/commands/show_config.py +12 -215
  33. django_cfg/management/commands/show_urls.py +12 -342
  34. django_cfg/management/commands/superuser.py +15 -295
  35. django_cfg/management/commands/task_clear.py +14 -217
  36. django_cfg/management/commands/task_status.py +13 -248
  37. django_cfg/management/commands/test_email.py +15 -86
  38. django_cfg/management/commands/test_telegram.py +14 -61
  39. django_cfg/management/commands/test_twilio.py +15 -105
  40. django_cfg/management/commands/tree.py +13 -383
  41. django_cfg/management/commands/validate_openapi.py +10 -0
  42. django_cfg/middleware/README.md +1 -1
  43. django_cfg/middleware/user_activity.py +3 -3
  44. django_cfg/models/__init__.py +2 -2
  45. django_cfg/models/api/drf/spectacular.py +6 -6
  46. django_cfg/models/django/__init__.py +2 -2
  47. django_cfg/models/django/openapi.py +238 -0
  48. django_cfg/modules/django_admin/management/__init__.py +0 -0
  49. django_cfg/modules/django_admin/management/commands/__init__.py +0 -0
  50. django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
  51. django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
  52. django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
  53. django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
  54. django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
  55. django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
  56. django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
  57. django_cfg/modules/django_admin/management/commands/script.py +496 -0
  58. django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
  59. django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
  60. django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
  61. django_cfg/modules/django_admin/management/commands/tree.py +390 -0
  62. django_cfg/modules/django_client/__init__.py +20 -0
  63. django_cfg/modules/django_client/apps.py +35 -0
  64. django_cfg/modules/django_client/core/__init__.py +56 -0
  65. django_cfg/modules/django_client/core/archive/__init__.py +11 -0
  66. django_cfg/modules/django_client/core/archive/manager.py +134 -0
  67. django_cfg/modules/django_client/core/cli/__init__.py +12 -0
  68. django_cfg/modules/django_client/core/cli/main.py +235 -0
  69. django_cfg/modules/django_client/core/config/__init__.py +18 -0
  70. django_cfg/modules/django_client/core/config/config.py +188 -0
  71. django_cfg/modules/django_client/core/config/group.py +101 -0
  72. django_cfg/modules/django_client/core/config/service.py +209 -0
  73. django_cfg/modules/django_client/core/generator/__init__.py +115 -0
  74. django_cfg/modules/django_client/core/generator/base.py +767 -0
  75. django_cfg/modules/django_client/core/generator/python.py +751 -0
  76. django_cfg/modules/django_client/core/generator/templates/python/__init__.py.jinja +9 -0
  77. django_cfg/modules/django_client/core/generator/templates/python/api_wrapper.py.jinja +130 -0
  78. django_cfg/modules/django_client/core/generator/templates/python/app_init.py.jinja +6 -0
  79. django_cfg/modules/django_client/core/generator/templates/python/client/app_client.py.jinja +18 -0
  80. django_cfg/modules/django_client/core/generator/templates/python/client/flat_client.py.jinja +38 -0
  81. django_cfg/modules/django_client/core/generator/templates/python/client/main_client.py.jinja +50 -0
  82. django_cfg/modules/django_client/core/generator/templates/python/client/main_client_file.py.jinja +13 -0
  83. django_cfg/modules/django_client/core/generator/templates/python/client/operation_method.py.jinja +7 -0
  84. django_cfg/modules/django_client/core/generator/templates/python/client/sub_client.py.jinja +11 -0
  85. django_cfg/modules/django_client/core/generator/templates/python/client_file.py.jinja +13 -0
  86. django_cfg/modules/django_client/core/generator/templates/python/main_init.py.jinja +50 -0
  87. django_cfg/modules/django_client/core/generator/templates/python/models/app_models.py.jinja +17 -0
  88. django_cfg/modules/django_client/core/generator/templates/python/models/enum_class.py.jinja +15 -0
  89. django_cfg/modules/django_client/core/generator/templates/python/models/enums.py.jinja +8 -0
  90. django_cfg/modules/django_client/core/generator/templates/python/models/models.py.jinja +17 -0
  91. django_cfg/modules/django_client/core/generator/templates/python/models/schema_class.py.jinja +19 -0
  92. django_cfg/modules/django_client/core/generator/templates/python/utils/logger.py.jinja +255 -0
  93. django_cfg/modules/django_client/core/generator/templates/python/utils/schema.py.jinja +12 -0
  94. django_cfg/modules/django_client/core/generator/templates/typescript/app_index.ts.jinja +2 -0
  95. django_cfg/modules/django_client/core/generator/templates/typescript/client/app_client.ts.jinja +18 -0
  96. django_cfg/modules/django_client/core/generator/templates/typescript/client/client.ts.jinja +327 -0
  97. django_cfg/modules/django_client/core/generator/templates/typescript/client/flat_client.ts.jinja +109 -0
  98. django_cfg/modules/django_client/core/generator/templates/typescript/client/main_client_file.ts.jinja +9 -0
  99. django_cfg/modules/django_client/core/generator/templates/typescript/client/operation.ts.jinja +61 -0
  100. django_cfg/modules/django_client/core/generator/templates/typescript/client/sub_client.ts.jinja +15 -0
  101. django_cfg/modules/django_client/core/generator/templates/typescript/client_file.ts.jinja +9 -0
  102. django_cfg/modules/django_client/core/generator/templates/typescript/index.ts.jinja +5 -0
  103. django_cfg/modules/django_client/core/generator/templates/typescript/main_index.ts.jinja +206 -0
  104. django_cfg/modules/django_client/core/generator/templates/typescript/models/app_models.ts.jinja +8 -0
  105. django_cfg/modules/django_client/core/generator/templates/typescript/models/enums.ts.jinja +4 -0
  106. django_cfg/modules/django_client/core/generator/templates/typescript/models/models.ts.jinja +8 -0
  107. django_cfg/modules/django_client/core/generator/templates/typescript/utils/errors.ts.jinja +114 -0
  108. django_cfg/modules/django_client/core/generator/templates/typescript/utils/http.ts.jinja +98 -0
  109. django_cfg/modules/django_client/core/generator/templates/typescript/utils/logger.ts.jinja +251 -0
  110. django_cfg/modules/django_client/core/generator/templates/typescript/utils/schema.ts.jinja +7 -0
  111. django_cfg/modules/django_client/core/generator/templates/typescript/utils/storage.ts.jinja +114 -0
  112. django_cfg/modules/django_client/core/generator/typescript.py +872 -0
  113. django_cfg/modules/django_client/core/groups/__init__.py +13 -0
  114. django_cfg/modules/django_client/core/groups/detector.py +178 -0
  115. django_cfg/modules/django_client/core/groups/manager.py +314 -0
  116. django_cfg/modules/django_client/core/ir/__init__.py +57 -0
  117. django_cfg/modules/django_client/core/ir/context.py +387 -0
  118. django_cfg/modules/django_client/core/ir/operation.py +518 -0
  119. django_cfg/modules/django_client/core/ir/schema.py +353 -0
  120. django_cfg/modules/django_client/core/parser/__init__.py +74 -0
  121. django_cfg/modules/django_client/core/parser/base.py +648 -0
  122. django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
  123. django_cfg/modules/django_client/core/parser/models/base.py +212 -0
  124. django_cfg/modules/django_client/core/parser/models/components.py +160 -0
  125. django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
  126. django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
  127. django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
  128. django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
  129. django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
  130. django_cfg/modules/django_client/core/validation/__init__.py +22 -0
  131. django_cfg/modules/django_client/core/validation/checker.py +134 -0
  132. django_cfg/modules/django_client/core/validation/fixer.py +216 -0
  133. django_cfg/modules/django_client/core/validation/reporter.py +480 -0
  134. django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
  135. django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
  136. django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
  137. django_cfg/modules/django_client/core/validation/safety.py +266 -0
  138. django_cfg/modules/django_client/management/__init__.py +3 -0
  139. django_cfg/modules/django_client/management/commands/__init__.py +3 -0
  140. django_cfg/modules/django_client/management/commands/generate_client.py +422 -0
  141. django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
  142. django_cfg/modules/django_client/spectacular/__init__.py +9 -0
  143. django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
  144. django_cfg/modules/django_client/urls.py +72 -0
  145. django_cfg/modules/django_email/management/__init__.py +0 -0
  146. django_cfg/modules/django_email/management/commands/__init__.py +0 -0
  147. django_cfg/modules/django_email/management/commands/test_email.py +93 -0
  148. django_cfg/modules/django_logging/django_logger.py +6 -6
  149. django_cfg/modules/django_ngrok/management/__init__.py +0 -0
  150. django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
  151. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
  152. django_cfg/modules/django_tasks/management/__init__.py +0 -0
  153. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  154. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
  155. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
  156. django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
  157. django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
  158. django_cfg/modules/django_telegram/management/__init__.py +0 -0
  159. django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
  160. django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
  161. django_cfg/modules/django_twilio/management/__init__.py +0 -0
  162. django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
  163. django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
  164. django_cfg/modules/django_unfold/callbacks/main.py +16 -5
  165. django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
  166. django_cfg/pyproject.toml +2 -6
  167. django_cfg/registry/third_party.py +5 -7
  168. django_cfg/routing/callbacks.py +1 -1
  169. django_cfg/static/admin/css/prose-unfold.css +666 -0
  170. django_cfg/templates/admin/index.html +8 -0
  171. django_cfg/templates/admin/index_new.html +13 -0
  172. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
  173. django_cfg/templates/admin/sections/documentation_section.html +172 -0
  174. django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
  175. {django_cfg-1.4.10.dist-info → django_cfg-1.4.11.dist-info}/METADATA +2 -2
  176. {django_cfg-1.4.10.dist-info → django_cfg-1.4.11.dist-info}/RECORD +180 -59
  177. django_cfg/management/commands/generate.py +0 -107
  178. /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
  179. {django_cfg-1.4.10.dist-info → django_cfg-1.4.11.dist-info}/WHEEL +0 -0
  180. {django_cfg-1.4.10.dist-info → django_cfg-1.4.11.dist-info}/entry_points.txt +0 -0
  181. {django_cfg-1.4.10.dist-info → django_cfg-1.4.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,225 +1,22 @@
1
1
  """
2
- Django management command to show current configuration.
2
+ Django-CFG wrapper for show_config command.
3
+
4
+ This is a simple alias for django_admin.management.commands.show_config.
5
+ All logic is in django_admin module.
3
6
 
4
7
  Usage:
5
8
  python manage.py show_config
6
9
  python manage.py show_config --format json
10
+ python manage.py show_config --include-secrets
7
11
  """
8
12
 
9
- import json
10
- import os
11
- from django.core.management.base import BaseCommand
12
- from django.conf import settings
13
- from django_cfg.modules.django_logging import get_logger
14
-
15
- logger = get_logger('show_config')
16
-
17
-
18
- class Command(BaseCommand):
19
- # Web execution metadata
20
- web_executable = True
21
- requires_input = False
22
- is_destructive = False
23
-
24
- help = 'Show Django Config configuration'
25
-
26
- def add_arguments(self, parser):
27
- parser.add_argument(
28
- '--format',
29
- choices=['table', 'json'],
30
- default='table',
31
- help='Output format (default: table)',
32
- )
33
- parser.add_argument(
34
- '--include-secrets',
35
- action='store_true',
36
- help='Include sensitive information (use carefully)',
37
- )
38
-
39
- def handle(self, *args, **options):
40
- """Show configuration in requested format."""
41
- logger.info("Starting show_config command")
42
- try:
43
- # Get the config instance from Django settings
44
- config = self._get_config_instance()
45
- logger.info("Successfully retrieved configuration instance")
46
-
47
- if options['format'] == 'json':
48
- logger.info("Displaying configuration in JSON format")
49
- self._show_json_format(config, options['include_secrets'])
50
- else:
51
- logger.info("Displaying configuration in table format")
52
- self._show_table_format(config, options['include_secrets'])
53
-
54
- logger.info("show_config command completed successfully")
55
- except Exception as e:
56
- error_msg = f'Failed to show configuration: {e}'
57
- logger.error(error_msg, exc_info=True)
58
- self.stdout.write(
59
- self.style.ERROR(f'āŒ {error_msg}')
60
- )
13
+ from django_cfg.modules.django_admin.management.commands.show_config import Command as ShowConfigCommand
61
14
 
62
- def _get_config_instance(self):
63
- """Get the DjangoConfig instance from Django settings."""
64
- # Try to get config from settings module
65
- settings_module = os.environ.get('DJANGO_SETTINGS_MODULE')
66
- if not settings_module:
67
- raise ValueError("DJANGO_SETTINGS_MODULE environment variable not set")
68
-
69
- # Import the settings module and get the config
70
- import importlib
71
- settings_mod = importlib.import_module(settings_module)
72
-
73
- if hasattr(settings_mod, 'config'):
74
- return settings_mod.config
75
- else:
76
- # Fallback: create a minimal config from Django settings
77
- from django_cfg import DjangoConfig
78
- return DjangoConfig(
79
- project_name=getattr(settings, 'PROJECT_NAME', 'Django Project'),
80
- secret_key=settings.SECRET_KEY,
81
- debug=settings.DEBUG,
82
- allowed_hosts=settings.ALLOWED_HOSTS,
83
- )
84
15
 
85
- def _show_table_format(self, config, include_secrets=False):
86
- """Show configuration in table format."""
87
- self.stdout.write(
88
- self.style.HTTP_INFO('šŸš€ Django Config - Current Configuration')
89
- )
90
- self.stdout.write('=' * 80)
91
-
92
- # Project section
93
- self.stdout.write(self.style.SUCCESS('\nšŸ“‹ Project'))
94
- self.stdout.write('-' * 40)
95
- project_data = [
96
- ('Name', config.project_name),
97
- ('Version', getattr(config, 'project_version', 'N/A')),
98
- ('Description', getattr(config, 'project_description', 'N/A')),
99
- ]
100
-
101
- for key, value in project_data:
102
- self.stdout.write(f' {key:<20}: {value}')
103
-
104
- # Environment section
105
- self.stdout.write(self.style.SUCCESS('\nšŸŒ Environment'))
106
- self.stdout.write('-' * 40)
107
- env_data = [
108
- ('Environment', getattr(config, 'env_mode', 'auto-detected')),
109
- ('Debug Mode', config.debug),
110
- ('Security Domains', ', '.join(config.security_domains) if config.security_domains else 'None'),
111
- ]
112
-
113
- if include_secrets:
114
- env_data.append(('Secret Key', config.secret_key[:20] + '...'))
115
- else:
116
- env_data.append(('Secret Key', '[HIDDEN]'))
117
-
118
- for key, value in env_data:
119
- self.stdout.write(f' {key:<20}: {value}')
120
-
121
- # Database section
122
- self.stdout.write(self.style.SUCCESS('\nšŸ—„ļø Databases'))
123
- self.stdout.write('-' * 40)
124
-
125
- for db_name, db_config in config.databases.items():
126
- self.stdout.write(f' {db_name}:')
127
- self.stdout.write(f' Engine: {db_config.engine}')
128
- if include_secrets:
129
- self.stdout.write(f' Name: {db_config.name}')
130
- self.stdout.write(f' Host: {db_config.host}')
131
- self.stdout.write(f' Port: {db_config.port}')
132
- else:
133
- self.stdout.write(f' Name: [HIDDEN]')
134
- self.stdout.write(f' Host: [HIDDEN]')
135
- self.stdout.write(f' Port: [HIDDEN]')
136
-
137
- # Cache section
138
- cache_configured = False
139
- if hasattr(config, 'cache_default') and config.cache_default:
140
- cache_configured = True
141
-
142
- if cache_configured:
143
- self.stdout.write(self.style.SUCCESS('\n⚔ Cache'))
144
- self.stdout.write('-' * 40)
145
- cache_data = [
146
- ('Default Cache', 'Configured'),
147
- ('Sessions Cache', 'Configured' if hasattr(config, 'cache_sessions') and config.cache_sessions else 'Not configured'),
148
- ]
149
-
150
- for key, value in cache_data:
151
- self.stdout.write(f' {key:<20}: {value}')
152
-
153
- # Services section
154
- services_configured = []
155
- if hasattr(config, 'email') and config.email:
156
- services_configured.append(('Email', 'Configured'))
157
- if hasattr(config, 'telegram') and config.telegram:
158
- services_configured.append(('Telegram', 'Configured'))
159
-
160
- if services_configured:
161
- self.stdout.write(self.style.SUCCESS('\nšŸ”§ Services'))
162
- self.stdout.write('-' * 40)
163
-
164
- for key, value in services_configured:
165
- self.stdout.write(f' {key:<20}: {value}')
166
-
167
- # Apps section
168
- if hasattr(config, 'project_apps') and config.project_apps:
169
- self.stdout.write(self.style.SUCCESS('\nšŸ“¦ Project Apps'))
170
- self.stdout.write('-' * 40)
171
-
172
- for app in config.project_apps:
173
- self.stdout.write(f' • {app}')
174
-
175
- # Custom Middleware section
176
- if hasattr(config, 'custom_middleware') and config.custom_middleware:
177
- self.stdout.write(self.style.SUCCESS('\nšŸ›”ļø Custom Middleware'))
178
- self.stdout.write('-' * 40)
179
-
180
- for middleware in config.custom_middleware:
181
- self.stdout.write(f' • {middleware}')
182
-
183
- self.stdout.write('\n' + '=' * 80)
16
+ class Command(ShowConfigCommand):
17
+ """
18
+ Alias for show_config command.
184
19
 
185
- def _show_json_format(self, config, include_secrets=False):
186
- """Show configuration in JSON format."""
187
- config_data = {
188
- 'project': {
189
- 'name': config.project_name,
190
- 'version': getattr(config, 'project_version', None),
191
- 'description': getattr(config, 'project_description', None),
192
- },
193
- 'environment': {
194
- 'environment': getattr(config, 'env_mode', 'auto-detected'),
195
- 'debug': config.debug,
196
- 'allowed_hosts': config.allowed_hosts,
197
- },
198
- 'databases': {},
199
- 'cache': {
200
- 'default_configured': hasattr(config, 'cache_default') and config.cache_default is not None,
201
- 'sessions_configured': hasattr(config, 'cache_sessions') and config.cache_sessions is not None,
202
- },
203
- 'services': {
204
- 'email_configured': hasattr(config, 'email') and config.email is not None,
205
- 'telegram_configured': hasattr(config, 'telegram') and config.telegram is not None,
206
- },
207
- 'apps': {
208
- 'project_apps': getattr(config, 'project_apps', []),
209
- 'custom_middleware': getattr(config, 'custom_middleware', []),
210
- }
211
- }
212
-
213
- # Add database info
214
- for db_name, db_config in config.databases.items():
215
- config_data['databases'][db_name] = {
216
- 'engine': db_config.engine,
217
- 'name': db_config.name if include_secrets else '[HIDDEN]',
218
- 'host': db_config.host if include_secrets else '[HIDDEN]',
219
- 'port': db_config.port if include_secrets else '[HIDDEN]',
220
- }
221
-
222
- if include_secrets:
223
- config_data['environment']['secret_key'] = config.secret_key
224
-
225
- self.stdout.write(json.dumps(config_data, indent=2, default=str))
20
+ Simply inherits from ShowConfigCommand without any changes.
21
+ """
22
+ pass
@@ -1,350 +1,20 @@
1
1
  """
2
- Django management command to display all URL patterns in the project.
3
- """
2
+ Django-CFG wrapper for show_urls command.
4
3
 
5
- import re
6
- from typing import List, Tuple, Optional
7
- from django.core.management.base import BaseCommand, CommandParser
8
- from django.urls import get_resolver
9
- from django.conf import settings
10
- from django.utils.termcolors import make_style
11
- from django_cfg.modules.django_logging import get_logger
4
+ This is a simple alias for django_admin.management.commands.show_urls.
5
+ All logic is in django_admin module.
12
6
 
13
- logger = get_logger('show_urls')
7
+ Usage:
8
+ python manage.py show_urls
9
+ """
14
10
 
11
+ from django_cfg.modules.django_admin.management.commands.show_urls import Command as ShowUrlsCommand
15
12
 
16
- class Command(BaseCommand):
17
- """
18
- Display all URL patterns in the Django project.
19
13
 
20
- This command recursively walks through all URL patterns and displays them
21
- in a hierarchical format with colors and filtering options.
14
+ class Command(ShowUrlsCommand):
22
15
  """
16
+ Alias for show_urls command.
23
17
 
24
- # Web execution metadata
25
- web_executable = True
26
- requires_input = False
27
- is_destructive = False
28
-
29
- help = 'Display all URL patterns in the project'
30
-
31
- def __init__(self, *args, **kwargs):
32
- super().__init__(*args, **kwargs)
33
-
34
- # Define color styles
35
- self.styles = {
36
- 'SUCCESS': make_style(opts=('bold',), fg='green'),
37
- 'WARNING': make_style(opts=('bold',), fg='yellow'),
38
- 'ERROR': make_style(opts=('bold',), fg='red'),
39
- 'HTTP_200': make_style(fg='green'),
40
- 'HTTP_400': make_style(fg='yellow'),
41
- 'HTTP_500': make_style(fg='red'),
42
- 'URL': make_style(fg='cyan'),
43
- 'NAME': make_style(fg='blue'),
44
- 'INCLUDE': make_style(opts=('bold',), fg='magenta'),
45
- 'NAMESPACE': make_style(opts=('bold',), fg='yellow'),
46
- }
47
-
48
- def add_arguments(self, parser: CommandParser) -> None:
49
- """Add command arguments."""
50
- parser.add_argument(
51
- '--format',
52
- choices=['list', 'tree', 'table'],
53
- default='tree',
54
- help='Output format (default: tree)'
55
- )
56
- parser.add_argument(
57
- '--filter',
58
- type=str,
59
- help='Filter URLs by pattern (regex supported)'
60
- )
61
- parser.add_argument(
62
- '--namespace',
63
- type=str,
64
- help='Show URLs only from specific namespace'
65
- )
66
- parser.add_argument(
67
- '--plain',
68
- action='store_true',
69
- help='Plain output without colors'
70
- )
71
- parser.add_argument(
72
- '--include-unnamed',
73
- action='store_true',
74
- help='Include URLs without names'
75
- )
76
- parser.add_argument(
77
- '--show-methods',
78
- action='store_true',
79
- help='Show HTTP methods for each URL'
80
- )
81
- parser.add_argument(
82
- '--show-views',
83
- action='store_true',
84
- help='Show view functions/classes'
85
- )
86
-
87
- def handle(self, *args, **options) -> None:
88
- """Main command handler."""
89
- logger.info("Starting show_urls command")
90
- self.options = options
91
-
92
- # Disable colors if requested
93
- if options['plain'] or options.get('no_color', False):
94
- for key in self.styles:
95
- self.styles[key] = lambda x: x
96
-
97
- self.stdout.write(
98
- self.styles['SUCCESS']('🌐 Django URL Patterns')
99
- )
100
- self.stdout.write('=' * 50)
101
-
102
- # Show Django Revolution info if available
103
- if hasattr(settings, 'DJANGO_REVOLUTION'):
104
- self._show_revolution_info()
105
-
106
- # Get and display URL patterns
107
- resolver = get_resolver()
108
- patterns = self._collect_patterns(resolver.url_patterns)
109
-
110
- # Filter patterns if requested
111
- if options['filter']:
112
- patterns = self._filter_patterns(patterns, options['filter'])
113
-
114
- if options['namespace']:
115
- patterns = self._filter_by_namespace(patterns, options['namespace'])
116
-
117
- # Display patterns in requested format
118
- if options['format'] == 'list':
119
- self._display_list(patterns)
120
- elif options['format'] == 'table':
121
- self._display_table(patterns)
122
- else:
123
- self._display_tree(patterns)
124
-
125
- self.stdout.write(f"\nšŸ“Š Total URLs: {len(patterns)}")
126
-
127
- def _show_revolution_info(self) -> None:
128
- """Display Django Revolution configuration info."""
129
- revolution = settings.DJANGO_REVOLUTION
130
-
131
- self.stdout.write(
132
- self.styles['NAMESPACE']('\nšŸ“‹ Django Revolution Configuration:')
133
- )
134
- self.stdout.write(f" API Prefix: {revolution.get('api_prefix', 'N/A')}")
135
- self.stdout.write(f" Debug: {revolution.get('debug', 'N/A')}")
136
-
137
- zones = revolution.get('zones', {})
138
- if zones:
139
- self.stdout.write(f" Zones: {', '.join(zones.keys())}")
140
- self.stdout.write('')
141
-
142
- def _collect_patterns(
143
- self,
144
- urlpatterns,
145
- prefix: str = '',
146
- namespace: str = ''
147
- ) -> List[Tuple[str, str, str, str, Optional[str]]]:
148
- """
149
- Recursively collect all URL patterns.
150
-
151
- Returns list of tuples: (pattern, name, namespace, view, methods)
152
- """
153
- patterns = []
154
-
155
- for pattern in urlpatterns:
156
- if hasattr(pattern, 'url_patterns'):
157
- # This is an include() pattern
158
- new_prefix = prefix + str(pattern.pattern)
159
- new_namespace = namespace
160
-
161
- if hasattr(pattern, 'namespace') and pattern.namespace:
162
- new_namespace = (
163
- f"{namespace}:{pattern.namespace}"
164
- if namespace
165
- else pattern.namespace
166
- )
167
-
168
- # Add the include pattern itself
169
- patterns.append((
170
- new_prefix,
171
- f"[INCLUDE: {getattr(pattern, 'app_name', 'unknown')}]",
172
- new_namespace,
173
- 'include',
174
- None
175
- ))
176
-
177
- # Recursively collect nested patterns
178
- patterns.extend(
179
- self._collect_patterns(
180
- pattern.url_patterns,
181
- new_prefix,
182
- new_namespace
183
- )
184
- )
185
- else:
186
- # Regular URL pattern
187
- full_pattern = prefix + str(pattern.pattern)
188
- name = getattr(pattern, 'name', None)
189
- view_name = self._get_view_name(pattern)
190
- methods = self._get_http_methods(pattern)
191
-
192
- patterns.append((
193
- full_pattern,
194
- name or '[unnamed]',
195
- namespace,
196
- view_name,
197
- methods
198
- ))
199
-
200
- return patterns
201
-
202
- def _get_view_name(self, pattern) -> str:
203
- """Get the view function/class name from a URL pattern."""
204
- try:
205
- if hasattr(pattern, 'callback'):
206
- callback = pattern.callback
207
- if hasattr(callback, '__name__'):
208
- return callback.__name__
209
- elif hasattr(callback, '__class__'):
210
- return callback.__class__.__name__
211
- else:
212
- return str(callback)
213
- return 'unknown'
214
- except Exception:
215
- return 'unknown'
216
-
217
- def _get_http_methods(self, pattern) -> Optional[str]:
218
- """Get HTTP methods supported by a URL pattern."""
219
- if not self.options['show_methods']:
220
- return None
221
-
222
- try:
223
- # Try to get methods from the view
224
- if hasattr(pattern, 'callback'):
225
- callback = pattern.callback
226
- if hasattr(callback, 'cls'):
227
- # DRF ViewSet or APIView
228
- view_class = callback.cls
229
- if hasattr(view_class, 'http_method_names'):
230
- return ', '.join(view_class.http_method_names).upper()
231
- elif hasattr(callback, 'view_class'):
232
- # Class-based view
233
- view_class = callback.view_class
234
- if hasattr(view_class, 'http_method_names'):
235
- return ', '.join(view_class.http_method_names).upper()
236
- return 'GET, POST, PUT, PATCH, DELETE' # Default assumption
237
- except Exception:
238
- return None
239
-
240
- def _filter_patterns(
241
- self,
242
- patterns: List[Tuple],
243
- filter_pattern: str
244
- ) -> List[Tuple]:
245
- """Filter patterns by regex."""
246
- try:
247
- regex = re.compile(filter_pattern, re.IGNORECASE)
248
- return [
249
- pattern for pattern in patterns
250
- if regex.search(pattern[0]) or regex.search(pattern[1])
251
- ]
252
- except re.error:
253
- self.stdout.write(
254
- self.styles['ERROR'](f"Invalid regex pattern: {filter_pattern}")
255
- )
256
- return patterns
257
-
258
- def _filter_by_namespace(
259
- self,
260
- patterns: List[Tuple],
261
- namespace: str
262
- ) -> List[Tuple]:
263
- """Filter patterns by namespace."""
264
- return [
265
- pattern for pattern in patterns
266
- if pattern[2] and namespace in pattern[2]
267
- ]
268
-
269
- def _display_tree(self, patterns: List[Tuple]) -> None:
270
- """Display patterns in tree format."""
271
- self.stdout.write(self.styles['SUCCESS']('\n🌳 URL Tree:'))
272
- self.stdout.write('-' * 30)
273
-
274
- for pattern, name, namespace, view, methods in patterns:
275
- # Format the output
276
- if '[INCLUDE:' in name:
277
- # Include pattern
278
- icon = 'šŸ“'
279
- pattern_display = self.styles['INCLUDE'](pattern)
280
- name_display = self.styles['NAMESPACE'](name)
281
- elif name == '[unnamed]' and not self.options['include_unnamed']:
282
- continue
283
- else:
284
- # Regular pattern
285
- icon = 'šŸ”—'
286
- pattern_display = self.styles['URL'](pattern)
287
- name_display = self.styles['NAME'](name)
288
-
289
- # Build the line
290
- line = f"{icon} {pattern_display}"
291
- if name and name != '[unnamed]':
292
- line += f" -> {name_display}"
293
-
294
- if namespace:
295
- line += f" [{self.styles['NAMESPACE'](namespace)}]"
296
-
297
- if self.options['show_views'] and view and view != 'include':
298
- line += f" ({view})"
299
-
300
- if methods:
301
- line += f" [{methods}]"
302
-
303
- self.stdout.write(line)
304
-
305
- def _display_list(self, patterns: List[Tuple]) -> None:
306
- """Display patterns in simple list format."""
307
- self.stdout.write(self.styles['SUCCESS']('\nšŸ“‹ URL List:'))
308
- self.stdout.write('-' * 20)
309
-
310
- for i, (pattern, name, namespace, view, methods) in enumerate(patterns, 1):
311
- if name == '[unnamed]' and not self.options['include_unnamed']:
312
- continue
313
-
314
- line = f"{i:3d}. {self.styles['URL'](pattern)}"
315
- if name and name != '[unnamed]':
316
- line += f" ({self.styles['NAME'](name)})"
317
-
318
- self.stdout.write(line)
319
-
320
- def _display_table(self, patterns: List[Tuple]) -> None:
321
- """Display patterns in table format."""
322
- self.stdout.write(self.styles['SUCCESS']('\nšŸ“Š URL Table:'))
323
- self.stdout.write('-' * 80)
324
-
325
- # Header
326
- headers = ['Pattern', 'Name', 'Namespace', 'View']
327
- if self.options['show_methods']:
328
- headers.append('Methods')
329
-
330
- header_line = ' | '.join(f"{h:<20}" for h in headers)
331
- self.stdout.write(self.styles['SUCCESS'](header_line))
332
- self.stdout.write('-' * len(header_line))
333
-
334
- # Rows
335
- for pattern, name, namespace, view, methods in patterns:
336
- if name == '[unnamed]' and not self.options['include_unnamed']:
337
- continue
338
-
339
- row = [
340
- pattern[:20],
341
- (name or '')[:20],
342
- (namespace or '')[:20],
343
- (view or '')[:20]
344
- ]
345
-
346
- if self.options['show_methods']:
347
- row.append((methods or '')[:20])
348
-
349
- row_line = ' | '.join(f"{cell:<20}" for cell in row)
350
- self.stdout.write(row_line)
18
+ Simply inherits from ShowUrlsCommand without any changes.
19
+ """
20
+ pass