django-cfg 1.4.10__py3-none-any.whl → 1.4.13__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.
- django_cfg/apps/agents/management/commands/create_agent.py +1 -1
- django_cfg/apps/agents/management/commands/orchestrator_status.py +3 -3
- django_cfg/apps/newsletter/serializers.py +40 -3
- django_cfg/apps/newsletter/views/campaigns.py +12 -3
- django_cfg/apps/newsletter/views/emails.py +14 -3
- django_cfg/apps/newsletter/views/subscriptions.py +12 -2
- django_cfg/apps/payments/views/api/currencies.py +49 -6
- django_cfg/apps/payments/views/api/webhooks.py +72 -7
- django_cfg/apps/payments/views/overview/serializers.py +34 -1
- django_cfg/apps/payments/views/overview/views.py +2 -1
- django_cfg/apps/payments/views/serializers/payments.py +6 -6
- django_cfg/apps/urls.py +106 -45
- django_cfg/core/base/config_model.py +2 -2
- django_cfg/core/constants.py +1 -1
- django_cfg/core/generation/integration_generators/__init__.py +1 -1
- django_cfg/core/generation/integration_generators/api.py +73 -49
- django_cfg/core/integration/display/startup.py +30 -22
- django_cfg/core/integration/url_integration.py +15 -16
- django_cfg/management/commands/check_endpoints.py +11 -160
- django_cfg/management/commands/check_settings.py +13 -348
- django_cfg/management/commands/clear_constance.py +13 -201
- django_cfg/management/commands/create_token.py +13 -321
- django_cfg/management/commands/generate_clients.py +23 -0
- django_cfg/management/commands/list_urls.py +13 -306
- django_cfg/management/commands/migrate_all.py +13 -126
- django_cfg/management/commands/migrator.py +13 -396
- django_cfg/management/commands/rundramatiq.py +15 -247
- django_cfg/management/commands/rundramatiq_simulator.py +12 -429
- django_cfg/management/commands/runserver_ngrok.py +15 -160
- django_cfg/management/commands/script.py +12 -488
- django_cfg/management/commands/show_config.py +12 -215
- django_cfg/management/commands/show_urls.py +12 -342
- django_cfg/management/commands/superuser.py +15 -295
- django_cfg/management/commands/task_clear.py +14 -217
- django_cfg/management/commands/task_status.py +13 -248
- django_cfg/management/commands/test_email.py +15 -86
- django_cfg/management/commands/test_telegram.py +14 -61
- django_cfg/management/commands/test_twilio.py +15 -105
- django_cfg/management/commands/tree.py +13 -383
- django_cfg/management/commands/validate_openapi.py +10 -0
- django_cfg/middleware/README.md +1 -1
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/__init__.py +2 -2
- django_cfg/models/api/drf/spectacular.py +6 -6
- django_cfg/models/django/__init__.py +2 -2
- django_cfg/models/django/openapi.py +162 -0
- django_cfg/modules/django_admin/management/commands/check_endpoints.py +169 -0
- django_cfg/modules/django_admin/management/commands/check_settings.py +355 -0
- django_cfg/modules/django_admin/management/commands/clear_constance.py +208 -0
- django_cfg/modules/django_admin/management/commands/create_token.py +328 -0
- django_cfg/modules/django_admin/management/commands/list_urls.py +313 -0
- django_cfg/modules/django_admin/management/commands/migrate_all.py +133 -0
- django_cfg/modules/django_admin/management/commands/migrator.py +403 -0
- django_cfg/modules/django_admin/management/commands/script.py +496 -0
- django_cfg/modules/django_admin/management/commands/show_config.py +225 -0
- django_cfg/modules/django_admin/management/commands/show_urls.py +361 -0
- django_cfg/modules/django_admin/management/commands/superuser.py +302 -0
- django_cfg/modules/django_admin/management/commands/tree.py +390 -0
- django_cfg/modules/django_client/__init__.py +20 -0
- django_cfg/modules/django_client/apps.py +35 -0
- django_cfg/modules/django_client/core/__init__.py +56 -0
- django_cfg/modules/django_client/core/archive/__init__.py +11 -0
- django_cfg/modules/django_client/core/archive/manager.py +134 -0
- django_cfg/modules/django_client/core/cli/__init__.py +12 -0
- django_cfg/modules/django_client/core/cli/main.py +235 -0
- django_cfg/modules/django_client/core/config/__init__.py +18 -0
- django_cfg/modules/django_client/core/config/config.py +208 -0
- django_cfg/modules/django_client/core/config/group.py +101 -0
- django_cfg/modules/django_client/core/config/service.py +209 -0
- django_cfg/modules/django_client/core/generator/__init__.py +115 -0
- django_cfg/modules/django_client/core/generator/base.py +838 -0
- django_cfg/modules/django_client/core/generator/python/__init__.py +16 -0
- django_cfg/modules/django_client/core/generator/python/async_client_gen.py +174 -0
- django_cfg/modules/django_client/core/generator/python/files_generator.py +180 -0
- django_cfg/modules/django_client/core/generator/python/generator.py +182 -0
- django_cfg/modules/django_client/core/generator/python/models_generator.py +318 -0
- django_cfg/modules/django_client/core/generator/python/operations_generator.py +278 -0
- django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +102 -0
- django_cfg/modules/django_client/core/generator/python/templates/__init__.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/api_wrapper.py.jinja +153 -0
- django_cfg/modules/django_client/core/generator/python/templates/app_init.py.jinja +6 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/app_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/flat_client.py.jinja +38 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client.py.jinja +68 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/main_client_file.py.jinja +14 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_main_client.py.jinja +50 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_operation_method.py.jinja +9 -0
- django_cfg/modules/django_client/core/generator/python/templates/client/sync_sub_client.py.jinja +18 -0
- django_cfg/modules/django_client/core/generator/python/templates/client_file.py.jinja +13 -0
- django_cfg/modules/django_client/core/generator/python/templates/main_init.py.jinja +52 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/app_models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enum_class.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/enums.py.jinja +8 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/models.py.jinja +17 -0
- django_cfg/modules/django_client/core/generator/python/templates/models/schema_class.py.jinja +21 -0
- django_cfg/modules/django_client/core/generator/python/templates/pyproject.toml.jinja +55 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/logger.py.jinja +255 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/retry.py.jinja +271 -0
- django_cfg/modules/django_client/core/generator/python/templates/utils/schema.py.jinja +12 -0
- django_cfg/modules/django_client/core/generator/typescript/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/typescript/client_generator.py +165 -0
- django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +428 -0
- django_cfg/modules/django_client/core/generator/typescript/files_generator.py +207 -0
- django_cfg/modules/django_client/core/generator/typescript/generator.py +432 -0
- django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +536 -0
- django_cfg/modules/django_client/core/generator/typescript/models_generator.py +245 -0
- django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +298 -0
- django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +329 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/api_instance.ts.jinja +131 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/app_index.ts.jinja +2 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/app_client.ts.jinja +18 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +403 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/flat_client.ts.jinja +109 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/main_client_file.ts.jinja +10 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/operation.ts.jinja +61 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client/sub_client.ts.jinja +15 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/client_file.ts.jinja +9 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/fetchers.ts.jinja +45 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/fetchers/index.ts.jinja +30 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/index.ts.jinja +5 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +268 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/app_models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/enums.ts.jinja +4 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/models/models.ts.jinja +8 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/package.json.jinja +52 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/index.ts.jinja +21 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/schemas/schema.ts.jinja +24 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/tsconfig.json.jinja +20 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/errors.ts.jinja +116 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/http.ts.jinja +98 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/logger.ts.jinja +259 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/retry.ts.jinja +175 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/schema.ts.jinja +7 -0
- django_cfg/modules/django_client/core/generator/typescript/templates/utils/storage.ts.jinja +158 -0
- django_cfg/modules/django_client/core/groups/__init__.py +13 -0
- django_cfg/modules/django_client/core/groups/detector.py +178 -0
- django_cfg/modules/django_client/core/groups/manager.py +314 -0
- django_cfg/modules/django_client/core/ir/__init__.py +57 -0
- django_cfg/modules/django_client/core/ir/context.py +387 -0
- django_cfg/modules/django_client/core/ir/operation.py +518 -0
- django_cfg/modules/django_client/core/ir/schema.py +353 -0
- django_cfg/modules/django_client/core/parser/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/base.py +648 -0
- django_cfg/modules/django_client/core/parser/models/__init__.py +74 -0
- django_cfg/modules/django_client/core/parser/models/base.py +212 -0
- django_cfg/modules/django_client/core/parser/models/components.py +160 -0
- django_cfg/modules/django_client/core/parser/models/openapi.py +203 -0
- django_cfg/modules/django_client/core/parser/models/operation.py +207 -0
- django_cfg/modules/django_client/core/parser/models/schema.py +266 -0
- django_cfg/modules/django_client/core/parser/openapi30.py +56 -0
- django_cfg/modules/django_client/core/parser/openapi31.py +64 -0
- django_cfg/modules/django_client/core/validation/__init__.py +22 -0
- django_cfg/modules/django_client/core/validation/checker.py +134 -0
- django_cfg/modules/django_client/core/validation/fixer.py +216 -0
- django_cfg/modules/django_client/core/validation/reporter.py +480 -0
- django_cfg/modules/django_client/core/validation/rules/__init__.py +11 -0
- django_cfg/modules/django_client/core/validation/rules/base.py +96 -0
- django_cfg/modules/django_client/core/validation/rules/type_hints.py +288 -0
- django_cfg/modules/django_client/core/validation/safety.py +266 -0
- django_cfg/modules/django_client/management/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/__init__.py +3 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +427 -0
- django_cfg/modules/django_client/management/commands/validate_openapi.py +343 -0
- django_cfg/modules/django_client/pytest.ini +30 -0
- django_cfg/modules/django_client/spectacular/__init__.py +10 -0
- django_cfg/modules/django_client/spectacular/async_detection.py +187 -0
- django_cfg/modules/django_client/spectacular/enum_naming.py +192 -0
- django_cfg/modules/django_client/urls.py +72 -0
- django_cfg/{dashboard → modules/django_dashboard}/DEBUG_README.md +2 -2
- django_cfg/{dashboard → modules/django_dashboard}/REFACTORING_SUMMARY.md +1 -1
- django_cfg/modules/django_dashboard/management/__init__.py +0 -0
- django_cfg/modules/django_dashboard/management/commands/__init__.py +0 -0
- django_cfg/{dashboard → modules/django_dashboard}/management/commands/debug_dashboard.py +5 -5
- django_cfg/modules/django_dashboard/sections/documentation.py +391 -0
- django_cfg/modules/django_email/management/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/__init__.py +0 -0
- django_cfg/modules/django_email/management/commands/test_email.py +93 -0
- django_cfg/modules/django_logging/LOGGING_GUIDE.md +1 -1
- django_cfg/modules/django_logging/django_logger.py +6 -6
- django_cfg/modules/django_ngrok/management/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/__init__.py +0 -0
- django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +167 -0
- django_cfg/modules/django_tasks/management/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +254 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +437 -0
- django_cfg/modules/django_tasks/management/commands/task_clear.py +226 -0
- django_cfg/modules/django_tasks/management/commands/task_status.py +257 -0
- django_cfg/modules/django_telegram/management/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/__init__.py +0 -0
- django_cfg/modules/django_telegram/management/commands/test_telegram.py +68 -0
- django_cfg/modules/django_twilio/management/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/__init__.py +0 -0
- django_cfg/modules/django_twilio/management/commands/test_twilio.py +112 -0
- django_cfg/modules/django_unfold/callbacks/main.py +21 -10
- django_cfg/modules/django_unfold/callbacks/revolution.py +41 -36
- django_cfg/pyproject.toml +2 -6
- django_cfg/registry/third_party.py +5 -7
- django_cfg/routing/callbacks.py +1 -1
- django_cfg/static/admin/css/prose-unfold.css +666 -0
- django_cfg/templates/admin/index.html +8 -0
- django_cfg/templates/admin/index_new.html +13 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +15 -3
- django_cfg/templates/admin/sections/documentation_section.html +172 -0
- django_cfg/templates/admin/snippets/tabs/documentation_tab.html +231 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/METADATA +2 -2
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/RECORD +224 -74
- django_cfg/management/commands/generate.py +0 -107
- /django_cfg/models/django/{revolution.py → revolution_legacy.py} +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_admin}/management/commands/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/components.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/debug.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/__init__.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/base.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/commands.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/overview.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/stats.py +0 -0
- /django_cfg/{dashboard → modules/django_dashboard}/sections/system.py +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.10.dist-info → django_cfg-1.4.13.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
"""
|
2
|
+
Auto-fix enum naming collisions in OpenAPI schema.
|
3
|
+
|
4
|
+
This postprocessing hook automatically generates unique, descriptive enum names
|
5
|
+
based on model names to avoid collisions like "Status50eEnum", "StatusA98Enum".
|
6
|
+
|
7
|
+
Instead generates: "ProductStatusEnum", "OrderStatusEnum", "PostStatusEnum", etc.
|
8
|
+
"""
|
9
|
+
|
10
|
+
import logging
|
11
|
+
from typing import Dict, Any, Optional
|
12
|
+
import re
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
def auto_fix_enum_names(result: Dict[str, Any], generator, request, public) -> Dict[str, Any]:
|
18
|
+
"""
|
19
|
+
DRF Spectacular postprocessing hook to auto-fix enum naming collisions.
|
20
|
+
|
21
|
+
Automatically detects and fixes enum naming collisions by using model names.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
result: OpenAPI schema dict
|
25
|
+
generator: Schema generator instance
|
26
|
+
request: HTTP request
|
27
|
+
public: Whether schema is public
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
Modified OpenAPI schema with fixed enum names
|
31
|
+
|
32
|
+
Example:
|
33
|
+
Before: Status50eEnum, StatusA98Enum (collision hashes)
|
34
|
+
After: ProductStatusEnum, OrderStatusEnum (descriptive names)
|
35
|
+
"""
|
36
|
+
|
37
|
+
if 'components' not in result or 'schemas' not in result['components']:
|
38
|
+
return result
|
39
|
+
|
40
|
+
schemas = result['components']['schemas']
|
41
|
+
|
42
|
+
# Track enum references and their sources (model + field)
|
43
|
+
enum_sources: Dict[str, list] = {} # enum_name -> [(model_name, field_name, choices)]
|
44
|
+
enum_renames: Dict[str, str] = {} # old_name -> new_name
|
45
|
+
|
46
|
+
# Step 1: Find all enums and their sources
|
47
|
+
for schema_name, schema in schemas.items():
|
48
|
+
if schema.get('type') == 'object' and 'properties' in schema:
|
49
|
+
# This is a model schema
|
50
|
+
model_name = _extract_model_name(schema_name)
|
51
|
+
|
52
|
+
for field_name, field_schema in schema['properties'].items():
|
53
|
+
# Check if field references an enum
|
54
|
+
if '$ref' in field_schema:
|
55
|
+
enum_ref = field_schema['$ref']
|
56
|
+
if '#/components/schemas/' in enum_ref:
|
57
|
+
enum_name = enum_ref.split('/')[-1]
|
58
|
+
|
59
|
+
# Track enum source
|
60
|
+
if enum_name not in enum_sources:
|
61
|
+
enum_sources[enum_name] = []
|
62
|
+
|
63
|
+
enum_sources[enum_name].append((model_name, field_name))
|
64
|
+
|
65
|
+
# Step 2: Detect collisions and generate better names
|
66
|
+
for enum_name, sources in enum_sources.items():
|
67
|
+
# Check if enum looks like a collision (contains hash or generic name)
|
68
|
+
if _is_collision_enum(enum_name):
|
69
|
+
# Multiple models use this enum - need unique names
|
70
|
+
if len(sources) == 1:
|
71
|
+
# Single source - generate descriptive name
|
72
|
+
model_name, field_name = sources[0]
|
73
|
+
new_name = _generate_enum_name(model_name, field_name)
|
74
|
+
enum_renames[enum_name] = new_name
|
75
|
+
|
76
|
+
logger.debug(f" Renaming {enum_name} -> {new_name} (from {model_name}.{field_name})")
|
77
|
+
|
78
|
+
# Step 3: Apply renames to schema
|
79
|
+
if enum_renames:
|
80
|
+
logger.info(f"🔧 Auto-fixed {len(enum_renames)} enum naming collision(s)")
|
81
|
+
_apply_enum_renames(result, enum_renames)
|
82
|
+
|
83
|
+
return result
|
84
|
+
|
85
|
+
|
86
|
+
def _extract_model_name(schema_name: str) -> str:
|
87
|
+
"""
|
88
|
+
Extract model name from schema name.
|
89
|
+
|
90
|
+
Examples:
|
91
|
+
"Product" -> "Product"
|
92
|
+
"ProductDetail" -> "Product"
|
93
|
+
"PaginatedProductList" -> "Product"
|
94
|
+
"""
|
95
|
+
# Remove common prefixes/suffixes
|
96
|
+
name = schema_name
|
97
|
+
|
98
|
+
# Remove pagination wrapper
|
99
|
+
if name.startswith('Paginated') and name.endswith('List'):
|
100
|
+
name = name[9:-4] # Remove "Paginated" and "List"
|
101
|
+
|
102
|
+
# Remove common suffixes
|
103
|
+
for suffix in ['Serializer', 'Detail', 'List', 'Create', 'Update']:
|
104
|
+
if name.endswith(suffix):
|
105
|
+
name = name[:-len(suffix)]
|
106
|
+
break
|
107
|
+
|
108
|
+
return name
|
109
|
+
|
110
|
+
|
111
|
+
def _is_collision_enum(enum_name: str) -> bool:
|
112
|
+
"""
|
113
|
+
Check if enum name looks like a collision (contains hash).
|
114
|
+
|
115
|
+
Examples:
|
116
|
+
"Status50eEnum" -> True (has hash)
|
117
|
+
"StatusA98Enum" -> True (has hash)
|
118
|
+
"ProductStatusEnum" -> False (descriptive)
|
119
|
+
"""
|
120
|
+
# Check if enum contains hash-like patterns (3+ hex chars)
|
121
|
+
if re.search(r'[0-9A-Fa-f]{3,}Enum$', enum_name):
|
122
|
+
return True
|
123
|
+
|
124
|
+
# Check for generic single-word enums that are likely collisions
|
125
|
+
# (e.g., "StatusEnum" without model prefix)
|
126
|
+
if re.match(r'^[A-Z][a-z]+Enum$', enum_name):
|
127
|
+
# Single word + Enum - likely collision
|
128
|
+
return True
|
129
|
+
|
130
|
+
return False
|
131
|
+
|
132
|
+
|
133
|
+
def _generate_enum_name(model_name: str, field_name: str) -> str:
|
134
|
+
"""
|
135
|
+
Generate descriptive enum name from model and field.
|
136
|
+
|
137
|
+
Examples:
|
138
|
+
("Product", "status") -> "ProductStatusEnum"
|
139
|
+
("Order", "status") -> "OrderStatusEnum"
|
140
|
+
("Post", "status") -> "PostStatusEnum"
|
141
|
+
"""
|
142
|
+
# Capitalize field name
|
143
|
+
field_capitalized = field_name.capitalize()
|
144
|
+
|
145
|
+
# Combine: ModelName + FieldName + Enum
|
146
|
+
return f"{model_name}{field_capitalized}Enum"
|
147
|
+
|
148
|
+
|
149
|
+
def _apply_enum_renames(schema: Dict[str, Any], renames: Dict[str, str]) -> None:
|
150
|
+
"""
|
151
|
+
Apply enum renames throughout the schema.
|
152
|
+
|
153
|
+
Renames both:
|
154
|
+
1. Schema component definitions (components/schemas/OldName -> NewName)
|
155
|
+
2. All references to renamed enums ($ref: #/components/schemas/OldName)
|
156
|
+
"""
|
157
|
+
if 'components' not in schema or 'schemas' not in schema['components']:
|
158
|
+
return
|
159
|
+
|
160
|
+
schemas = schema['components']['schemas']
|
161
|
+
|
162
|
+
# Step 1: Rename schema definitions
|
163
|
+
for old_name, new_name in renames.items():
|
164
|
+
if old_name in schemas:
|
165
|
+
schemas[new_name] = schemas.pop(old_name)
|
166
|
+
logger.debug(f" Renamed schema: {old_name} -> {new_name}")
|
167
|
+
|
168
|
+
# Step 2: Update all $ref references
|
169
|
+
_update_refs_recursive(schema, renames)
|
170
|
+
|
171
|
+
|
172
|
+
def _update_refs_recursive(obj: Any, renames: Dict[str, str]) -> None:
|
173
|
+
"""
|
174
|
+
Recursively update all $ref references in schema.
|
175
|
+
"""
|
176
|
+
if isinstance(obj, dict):
|
177
|
+
# Check if this dict contains a $ref
|
178
|
+
if '$ref' in obj:
|
179
|
+
ref = obj['$ref']
|
180
|
+
if '#/components/schemas/' in ref:
|
181
|
+
enum_name = ref.split('/')[-1]
|
182
|
+
if enum_name in renames:
|
183
|
+
obj['$ref'] = f"#/components/schemas/{renames[enum_name]}"
|
184
|
+
|
185
|
+
# Recurse into dict values
|
186
|
+
for value in obj.values():
|
187
|
+
_update_refs_recursive(value, renames)
|
188
|
+
|
189
|
+
elif isinstance(obj, list):
|
190
|
+
# Recurse into list items
|
191
|
+
for item in obj:
|
192
|
+
_update_refs_recursive(item, renames)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
"""
|
2
|
+
Django URL integration.
|
3
|
+
|
4
|
+
Provides URL patterns for OpenAPI schema generation.
|
5
|
+
Each configured group gets its own schema endpoint.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import List, Any
|
9
|
+
|
10
|
+
|
11
|
+
def _is_django_configured() -> bool:
|
12
|
+
"""Check if Django settings are configured."""
|
13
|
+
try:
|
14
|
+
from django.conf import settings
|
15
|
+
return settings.configured
|
16
|
+
except ImportError:
|
17
|
+
return False
|
18
|
+
|
19
|
+
|
20
|
+
def get_openapi_urls() -> List[Any]:
|
21
|
+
"""
|
22
|
+
Get URL patterns for OpenAPI schema generation.
|
23
|
+
|
24
|
+
Creates URLs for each configured group:
|
25
|
+
- /openapi/{group_name}/schema/ - JSON schema
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
List of Django URL patterns
|
29
|
+
"""
|
30
|
+
try:
|
31
|
+
from django.urls import path
|
32
|
+
from drf_spectacular.views import SpectacularAPIView
|
33
|
+
from django_cfg.modules.django_client.core import get_openapi_service
|
34
|
+
except ImportError:
|
35
|
+
return []
|
36
|
+
|
37
|
+
service = get_openapi_service()
|
38
|
+
|
39
|
+
if not service.config or not service.is_enabled():
|
40
|
+
return []
|
41
|
+
|
42
|
+
patterns = []
|
43
|
+
|
44
|
+
for group_name in service.get_group_names():
|
45
|
+
group_config = service.get_group(group_name)
|
46
|
+
if not group_config:
|
47
|
+
continue
|
48
|
+
|
49
|
+
# Schema endpoint for each group
|
50
|
+
patterns.append(
|
51
|
+
path(
|
52
|
+
f'{group_name}/schema/',
|
53
|
+
SpectacularAPIView.as_view(
|
54
|
+
urlconf=f'openapi_group_{group_name}',
|
55
|
+
api_version=group_config.version,
|
56
|
+
),
|
57
|
+
name=f'openapi-schema-{group_name}',
|
58
|
+
)
|
59
|
+
)
|
60
|
+
|
61
|
+
return patterns
|
62
|
+
|
63
|
+
|
64
|
+
# Export urlpatterns for django.urls.include()
|
65
|
+
# Only create urlpatterns if Django is configured
|
66
|
+
if _is_django_configured():
|
67
|
+
urlpatterns = get_openapi_urls()
|
68
|
+
else:
|
69
|
+
urlpatterns = []
|
70
|
+
|
71
|
+
|
72
|
+
__all__ = ["get_openapi_urls", "urlpatterns"]
|
@@ -37,7 +37,7 @@ libs/django_cfg/src/django_cfg/debug/dashboard/
|
|
37
37
|
### 3. Программное использование
|
38
38
|
|
39
39
|
```python
|
40
|
-
from django_cfg.
|
40
|
+
from django_cfg.modules.django_dashboard.debug import save_section_render
|
41
41
|
|
42
42
|
# В коде секции
|
43
43
|
html = section.render()
|
@@ -62,7 +62,7 @@ dashboard/
|
|
62
62
|
## Сравнение с архивом
|
63
63
|
|
64
64
|
```python
|
65
|
-
from django_cfg.
|
65
|
+
from django_cfg.modules.django_dashboard.debug import get_debugger
|
66
66
|
from pathlib import Path
|
67
67
|
|
68
68
|
debugger = get_debugger()
|
@@ -65,7 +65,7 @@ python manage.py debug_dashboard
|
|
65
65
|
### 2. Автоматическое сохранение рендеров ✅
|
66
66
|
При каждом рендере секции автоматически сохраняются через:
|
67
67
|
```python
|
68
|
-
from django_cfg.
|
68
|
+
from django_cfg.modules.django_dashboard.debug import save_section_render
|
69
69
|
|
70
70
|
save_section_render('overview', html)
|
71
71
|
```
|
File without changes
|
File without changes
|
@@ -8,11 +8,11 @@ from django.core.management.base import BaseCommand
|
|
8
8
|
from django.test import RequestFactory
|
9
9
|
from django.contrib.auth import get_user_model
|
10
10
|
|
11
|
-
from django_cfg.
|
12
|
-
from django_cfg.
|
13
|
-
from django_cfg.
|
14
|
-
from django_cfg.
|
15
|
-
from django_cfg.
|
11
|
+
from django_cfg.modules.django_dashboard.sections.overview import OverviewSection
|
12
|
+
from django_cfg.modules.django_dashboard.sections.stats import StatsSection
|
13
|
+
from django_cfg.modules.django_dashboard.sections.system import SystemSection
|
14
|
+
from django_cfg.modules.django_dashboard.sections.commands import CommandsSection
|
15
|
+
from django_cfg.modules.django_dashboard.debug import get_debugger
|
16
16
|
|
17
17
|
|
18
18
|
class Command(BaseCommand):
|