django-cfg 1.3.13__py3-none-any.whl → 1.4.0__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 (438) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/user_admin.py +39 -16
  3. django_cfg/apps/accounts/serializers/profile.py +1 -1
  4. django_cfg/apps/accounts/services/otp_service.py +18 -11
  5. django_cfg/apps/accounts/signals.py +15 -24
  6. django_cfg/apps/accounts/utils/notifications.py +217 -358
  7. django_cfg/apps/accounts/views/otp.py +2 -2
  8. django_cfg/apps/accounts/views/webhook.py +1 -1
  9. django_cfg/apps/agents/core/django_agent.py +1 -1
  10. django_cfg/apps/api/commands/views.py +66 -83
  11. django_cfg/apps/api/health/drf_views.py +269 -0
  12. django_cfg/apps/api/health/serializers.py +45 -0
  13. django_cfg/apps/api/health/urls.py +6 -1
  14. django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
  15. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
  16. django_cfg/apps/knowbase/admin/document_admin.py +136 -270
  17. django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
  18. django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
  19. django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
  20. django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
  21. django_cfg/apps/knowbase/config/constance_fields.py +1 -1
  22. django_cfg/apps/knowbase/config/settings.py +2 -2
  23. django_cfg/apps/knowbase/mixins/__init__.py +19 -2
  24. django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
  25. django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
  26. django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
  27. django_cfg/apps/knowbase/mixins/creator.py +10 -10
  28. django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
  29. django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
  30. django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
  31. django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
  32. django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
  33. django_cfg/apps/knowbase/mixins/service.py +2 -2
  34. django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
  35. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
  36. django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
  37. django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
  38. django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
  39. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
  40. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
  41. django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
  42. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
  43. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
  44. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
  45. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
  46. django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
  47. django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
  48. django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
  49. django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
  50. django_cfg/apps/knowbase/services/embedding/models.py +18 -14
  51. django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
  52. django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
  53. django_cfg/apps/leads/tests.py +1 -1
  54. django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
  55. django_cfg/apps/payments/admin/balance_admin.py +1 -1
  56. django_cfg/apps/payments/admin/currencies_admin.py +1 -1
  57. django_cfg/apps/payments/admin/payments_admin.py +1 -1
  58. django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
  59. django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
  60. django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
  61. django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
  62. django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
  63. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
  64. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
  65. django_cfg/apps/payments/admin_interface/views/base.py +29 -2
  66. django_cfg/apps/payments/apps.py +1 -1
  67. django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
  68. django_cfg/apps/payments/config/helpers.py +3 -2
  69. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
  70. django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
  71. django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
  72. django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
  73. django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
  74. django_cfg/apps/payments/management/commands/test_providers.py +1 -1
  75. django_cfg/apps/payments/middleware/api_access.py +1 -1
  76. django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
  77. django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
  78. django_cfg/apps/payments/models/balance.py +2 -2
  79. django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
  80. django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
  81. django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
  82. django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
  83. django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
  84. django_cfg/apps/payments/models/payments.py +2 -2
  85. django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
  86. django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
  87. django_cfg/apps/payments/services/core/base.py +1 -1
  88. django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
  89. django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
  90. django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
  91. django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
  92. django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
  93. django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
  94. django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
  95. django_cfg/apps/payments/services/core/payment_service.py +124 -612
  96. django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
  97. django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
  98. django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
  99. django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
  100. django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
  101. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
  102. django_cfg/apps/payments/services/providers/base.py +1 -1
  103. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
  104. django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
  105. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
  106. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
  107. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
  108. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
  109. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
  110. django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
  111. django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
  112. django_cfg/apps/payments/services/providers/registry.py +1 -1
  113. django_cfg/apps/payments/services/providers/sync_service.py +1 -1
  114. django_cfg/apps/payments/signals/__init__.py +1 -1
  115. django_cfg/apps/payments/signals/api_key_signals.py +1 -1
  116. django_cfg/apps/payments/signals/balance_signals.py +1 -1
  117. django_cfg/apps/payments/signals/payment_signals.py +1 -1
  118. django_cfg/apps/payments/signals/subscription_signals.py +1 -1
  119. django_cfg/apps/payments/views/api/api_keys.py +1 -1
  120. django_cfg/apps/payments/views/api/balances.py +1 -1
  121. django_cfg/apps/payments/views/api/base.py +1 -1
  122. django_cfg/apps/payments/views/api/currencies.py +1 -1
  123. django_cfg/apps/payments/views/api/payments.py +1 -1
  124. django_cfg/apps/payments/views/api/subscriptions.py +1 -1
  125. django_cfg/apps/payments/views/api/webhooks.py +1 -1
  126. django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
  127. django_cfg/apps/payments/views/serializers/balances.py +1 -1
  128. django_cfg/apps/payments/views/serializers/currencies.py +1 -1
  129. django_cfg/apps/payments/views/serializers/payments.py +1 -1
  130. django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
  131. django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
  132. django_cfg/apps/support/admin/support_admin.py +21 -13
  133. django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
  134. django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
  135. django_cfg/apps/support/utils/support_email_service.py +1 -1
  136. django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
  137. django_cfg/apps/tasks/utils/simulator.py +1 -1
  138. django_cfg/apps/tasks/views/dashboard.py +33 -3
  139. django_cfg/apps/urls.py +5 -1
  140. django_cfg/cli/README.md +57 -471
  141. django_cfg/cli/commands/create_project.py +140 -529
  142. django_cfg/cli/main.py +13 -10
  143. django_cfg/core/__init__.py +63 -6
  144. django_cfg/core/base/__init__.py +5 -0
  145. django_cfg/core/base/config_model.py +652 -0
  146. django_cfg/core/builders/__init__.py +11 -0
  147. django_cfg/core/builders/apps_builder.py +258 -0
  148. django_cfg/core/builders/middleware_builder.py +115 -0
  149. django_cfg/core/builders/security_builder.py +96 -0
  150. django_cfg/core/config.py +20 -892
  151. django_cfg/core/constants.py +69 -0
  152. django_cfg/core/environment/__init__.py +9 -0
  153. django_cfg/core/exceptions.py +45 -298
  154. django_cfg/core/generation/__init__.py +51 -0
  155. django_cfg/core/generation/core_generators/__init__.py +0 -0
  156. django_cfg/core/generation/core_generators/settings.py +90 -0
  157. django_cfg/core/generation/core_generators/static.py +82 -0
  158. django_cfg/core/generation/core_generators/templates.py +141 -0
  159. django_cfg/core/generation/data_generators/__init__.py +15 -0
  160. django_cfg/core/generation/data_generators/cache.py +132 -0
  161. django_cfg/core/generation/data_generators/database.py +117 -0
  162. django_cfg/core/generation/generation.py +92 -0
  163. django_cfg/core/generation/integration_generators/__init__.py +21 -0
  164. django_cfg/core/generation/integration_generators/api.py +237 -0
  165. django_cfg/core/generation/integration_generators/sessions.py +65 -0
  166. django_cfg/core/generation/integration_generators/tailwind.py +54 -0
  167. django_cfg/core/generation/integration_generators/tasks.py +92 -0
  168. django_cfg/core/generation/integration_generators/third_party.py +144 -0
  169. django_cfg/core/generation/orchestrator.py +285 -0
  170. django_cfg/core/generation/protocols.py +30 -0
  171. django_cfg/core/generation/security_generators/__init__.py +0 -0
  172. django_cfg/core/generation/utility_generators/__init__.py +24 -0
  173. django_cfg/core/generation/utility_generators/email.py +58 -0
  174. django_cfg/core/generation/utility_generators/i18n.py +66 -0
  175. django_cfg/core/generation/utility_generators/limits.py +58 -0
  176. django_cfg/core/generation/utility_generators/logging.py +66 -0
  177. django_cfg/core/generation/utility_generators/security.py +101 -0
  178. django_cfg/core/generation/utils/__init__.py +0 -0
  179. django_cfg/core/generation/utils/helpers.py +32 -0
  180. django_cfg/core/integration/__init__.py +18 -25
  181. django_cfg/core/integration/display/startup.py +146 -133
  182. django_cfg/core/integration/url_integration.py +13 -2
  183. django_cfg/core/services/__init__.py +5 -0
  184. django_cfg/core/services/config_service.py +121 -0
  185. django_cfg/core/state/__init__.py +9 -0
  186. django_cfg/core/state/registry.py +84 -0
  187. django_cfg/core/types/__init__.py +15 -0
  188. django_cfg/core/types/aliases.py +15 -0
  189. django_cfg/core/types/enums.py +49 -0
  190. django_cfg/dashboard/DEBUG_README.md +105 -0
  191. django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
  192. django_cfg/dashboard/__init__.py +24 -0
  193. django_cfg/dashboard/components.py +308 -0
  194. django_cfg/dashboard/debug.py +176 -0
  195. django_cfg/dashboard/management/__init__.py +0 -0
  196. django_cfg/dashboard/management/commands/__init__.py +0 -0
  197. django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
  198. django_cfg/dashboard/sections/__init__.py +1 -0
  199. django_cfg/dashboard/sections/base.py +128 -0
  200. django_cfg/dashboard/sections/commands.py +32 -0
  201. django_cfg/dashboard/sections/overview.py +394 -0
  202. django_cfg/dashboard/sections/stats.py +48 -0
  203. django_cfg/dashboard/sections/system.py +73 -0
  204. django_cfg/management/commands/check_settings.py +6 -2
  205. django_cfg/management/commands/clear_constance.py +6 -1
  206. django_cfg/management/commands/create_token.py +5 -4
  207. django_cfg/management/commands/generate.py +5 -0
  208. django_cfg/management/commands/list_urls.py +7 -2
  209. django_cfg/management/commands/migrate_all.py +6 -2
  210. django_cfg/management/commands/migrator.py +6 -1
  211. django_cfg/management/commands/rundramatiq.py +6 -1
  212. django_cfg/management/commands/rundramatiq_simulator.py +11 -4
  213. django_cfg/management/commands/runserver_ngrok.py +9 -7
  214. django_cfg/management/commands/script.py +25 -21
  215. django_cfg/management/commands/show_config.py +6 -1
  216. django_cfg/management/commands/show_urls.py +8 -3
  217. django_cfg/management/commands/superuser.py +5 -4
  218. django_cfg/management/commands/task_clear.py +8 -3
  219. django_cfg/management/commands/task_status.py +8 -3
  220. django_cfg/management/commands/test_email.py +6 -1
  221. django_cfg/management/commands/test_telegram.py +6 -1
  222. django_cfg/management/commands/test_twilio.py +6 -1
  223. django_cfg/management/commands/tree.py +7 -4
  224. django_cfg/models/__init__.py +88 -3
  225. django_cfg/models/api/__init__.py +27 -0
  226. django_cfg/models/{api.py → api/config.py} +1 -1
  227. django_cfg/models/api/drf/__init__.py +21 -0
  228. django_cfg/models/api/drf/config.py +101 -0
  229. django_cfg/models/api/drf/redoc.py +31 -0
  230. django_cfg/models/api/drf/spectacular.py +129 -0
  231. django_cfg/models/api/drf/swagger.py +59 -0
  232. django_cfg/models/{api_keys.py → api/keys.py} +16 -6
  233. django_cfg/models/{limits.py → api/limits.py} +0 -1
  234. django_cfg/models/base/__init__.py +14 -0
  235. django_cfg/models/django/__init__.py +16 -0
  236. django_cfg/models/{constance.py → django/constance.py} +1 -1
  237. django_cfg/models/{environment.py → django/environment.py} +1 -1
  238. django_cfg/models/infrastructure/__init__.py +17 -0
  239. django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
  240. django_cfg/models/infrastructure/database/__init__.py +22 -0
  241. django_cfg/models/infrastructure/database/config.py +265 -0
  242. django_cfg/models/infrastructure/database/converters.py +91 -0
  243. django_cfg/models/infrastructure/database/parsers.py +96 -0
  244. django_cfg/models/infrastructure/database/routing.py +85 -0
  245. django_cfg/models/infrastructure/database/validators.py +170 -0
  246. django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
  247. django_cfg/models/{security.py → infrastructure/security.py} +2 -2
  248. django_cfg/models/ngrok/__init__.py +11 -0
  249. django_cfg/models/ngrok/auth.py +37 -0
  250. django_cfg/models/ngrok/config.py +77 -0
  251. django_cfg/models/ngrok/tunnel.py +35 -0
  252. django_cfg/models/payments/__init__.py +20 -0
  253. django_cfg/models/payments/api_keys.py +57 -0
  254. django_cfg/models/{payments.py → payments/config.py} +56 -154
  255. django_cfg/models/payments/providers/__init__.py +15 -0
  256. django_cfg/models/payments/providers/base.py +25 -0
  257. django_cfg/models/payments/providers/nowpayments.py +48 -0
  258. django_cfg/models/services/__init__.py +18 -0
  259. django_cfg/models/services/base.py +65 -0
  260. django_cfg/models/{email.py → services/email.py} +1 -1
  261. django_cfg/models/services/telegram.py +172 -0
  262. django_cfg/models/tasks/__init__.py +51 -0
  263. django_cfg/models/tasks/backends.py +250 -0
  264. django_cfg/models/tasks/config.py +314 -0
  265. django_cfg/models/tasks/utils.py +174 -0
  266. django_cfg/modules/base.py +18 -3
  267. django_cfg/modules/django_admin/decorators/actions.py +1 -1
  268. django_cfg/modules/django_admin/decorators/display.py +1 -1
  269. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
  270. django_cfg/modules/django_cfg_rpc_client/README.md +346 -0
  271. django_cfg/modules/django_cfg_rpc_client/__init__.py +51 -0
  272. django_cfg/modules/django_cfg_rpc_client/client.py +540 -0
  273. django_cfg/modules/django_cfg_rpc_client/config.py +207 -0
  274. django_cfg/modules/django_cfg_rpc_client/dashboard/README.md +517 -0
  275. django_cfg/modules/django_cfg_rpc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
  276. django_cfg/modules/django_cfg_rpc_client/dashboard/__init__.py +11 -0
  277. django_cfg/modules/django_cfg_rpc_client/dashboard/apps.py +22 -0
  278. django_cfg/modules/django_cfg_rpc_client/dashboard/monitor.py +435 -0
  279. django_cfg/modules/django_cfg_rpc_client/dashboard/static/django_cfg_rpc_dashboard/js/dashboard.js +373 -0
  280. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/base.html +76 -0
  281. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/dashboard.html +200 -0
  282. django_cfg/modules/django_cfg_rpc_client/dashboard/urls.py +22 -0
  283. django_cfg/modules/django_cfg_rpc_client/dashboard/urls_admin.py +9 -0
  284. django_cfg/modules/django_cfg_rpc_client/dashboard/views.py +251 -0
  285. django_cfg/modules/django_cfg_rpc_client/exceptions.py +201 -0
  286. django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
  287. django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
  288. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
  289. django_cfg/modules/django_drf_theme/README.md +207 -0
  290. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
  291. django_cfg/modules/django_drf_theme/__init__.py +23 -0
  292. django_cfg/modules/django_drf_theme/apps.py +15 -0
  293. django_cfg/modules/django_drf_theme/renderers.py +58 -0
  294. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
  295. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
  296. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
  297. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
  298. django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
  299. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
  300. django_cfg/modules/django_email/__init__.py +14 -0
  301. django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
  302. django_cfg/modules/django_email/utils.py +40 -0
  303. django_cfg/modules/django_health/__init__.py +9 -0
  304. django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
  305. django_cfg/modules/django_llm/llm/client.py +155 -550
  306. django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
  307. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
  308. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
  309. django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
  310. django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
  311. django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
  312. django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
  313. django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
  314. django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
  315. django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
  316. django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
  317. django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
  318. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
  319. django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
  320. django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
  321. django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
  322. django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
  323. django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
  324. django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
  325. django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
  326. django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
  327. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
  328. django_cfg/modules/django_llm/translator/translator.py +150 -603
  329. django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
  330. django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
  331. django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
  332. django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
  333. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
  334. django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
  335. django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
  336. django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
  337. django_cfg/modules/django_logging/__init__.py +14 -0
  338. django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
  339. django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
  340. django_cfg/modules/django_ngrok/__init__.py +39 -0
  341. django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
  342. django_cfg/modules/django_rpc_old/POETRY.md +344 -0
  343. django_cfg/modules/django_rpc_old/README.md +397 -0
  344. django_cfg/modules/django_rpc_old/TESTING.md +358 -0
  345. django_cfg/modules/django_rpc_old/__init__.py +39 -0
  346. django_cfg/modules/django_rpc_old/client.py +531 -0
  347. django_cfg/modules/django_rpc_old/config.py +279 -0
  348. django_cfg/modules/django_rpc_old/exceptions.py +172 -0
  349. django_cfg/modules/django_tailwind/README.md +478 -0
  350. django_cfg/modules/django_tailwind/__init__.py +7 -0
  351. django_cfg/modules/django_tailwind/apps.py +10 -0
  352. django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
  353. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
  354. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
  355. django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
  356. django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
  357. django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
  358. django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
  359. django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
  360. django_cfg/modules/django_tasks/__init__.py +29 -0
  361. django_cfg/modules/django_tasks/factory.py +127 -0
  362. django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
  363. django_cfg/modules/django_tasks/settings.py +107 -0
  364. django_cfg/modules/django_telegram/__init__.py +29 -0
  365. django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
  366. django_cfg/modules/django_telegram/utils.py +62 -0
  367. django_cfg/modules/django_twilio/__init__.py +54 -107
  368. django_cfg/modules/django_twilio/_imports.py +30 -0
  369. django_cfg/modules/django_twilio/base.py +192 -0
  370. django_cfg/modules/django_twilio/email_otp.py +227 -0
  371. django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
  372. django_cfg/modules/django_twilio/simple_service.py +1 -2
  373. django_cfg/modules/django_twilio/sms.py +94 -0
  374. django_cfg/modules/django_twilio/twilio_service.py +2 -3
  375. django_cfg/modules/django_twilio/unified.py +310 -0
  376. django_cfg/modules/django_twilio/utils.py +190 -0
  377. django_cfg/modules/django_twilio/whatsapp.py +137 -0
  378. django_cfg/modules/django_unfold/callbacks/base.py +198 -7
  379. django_cfg/modules/django_unfold/callbacks/main.py +102 -10
  380. django_cfg/modules/django_unfold/dashboard.py +65 -43
  381. django_cfg/modules/django_unfold/models/config.py +13 -12
  382. django_cfg/modules/django_unfold/models/navigation.py +8 -3
  383. django_cfg/modules/django_unfold/models/tabs.py +2 -2
  384. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
  385. django_cfg/registry/core.py +24 -26
  386. django_cfg/registry/modules.py +5 -2
  387. django_cfg/registry/services.py +20 -3
  388. django_cfg/registry/third_party.py +8 -8
  389. django_cfg/static/admin/css/dashboard.css +260 -0
  390. django_cfg/static/admin/js/commands.js +171 -0
  391. django_cfg/static/admin/js/dashboard.js +126 -0
  392. django_cfg/templates/admin/components/management_commands.js +375 -0
  393. django_cfg/templates/admin/components/progress_bar.html +18 -23
  394. django_cfg/templates/admin/index.html +48 -20
  395. django_cfg/templates/admin/index_new.html +106 -0
  396. django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
  397. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
  398. django_cfg/templates/admin/sections/commands_section.html +626 -0
  399. django_cfg/templates/admin/sections/overview_section.html +112 -0
  400. django_cfg/templates/admin/sections/stats_section.html +35 -0
  401. django_cfg/templates/admin/sections/system_section.html +99 -0
  402. django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
  403. django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
  404. django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
  405. django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
  406. django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
  407. django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
  408. django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
  409. django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
  410. django_cfg/templatetags/django_cfg.py +7 -1
  411. django_cfg/utils/smart_defaults.py +4 -4
  412. django_cfg-1.4.0.dist-info/METADATA +920 -0
  413. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/RECORD +424 -195
  414. django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
  415. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
  416. django_cfg/core/generation.py +0 -621
  417. django_cfg/management/commands/validate_config.py +0 -189
  418. django_cfg/models/database.py +0 -480
  419. django_cfg/models/drf.py +0 -272
  420. django_cfg/models/ngrok.py +0 -122
  421. django_cfg/models/services.py +0 -440
  422. django_cfg/models/tasks.py +0 -550
  423. django_cfg/modules/django_twilio/service.py +0 -942
  424. django_cfg/template_archive/django_sample.zip +0 -0
  425. django_cfg/templates/rest_framework/api.html +0 -12
  426. django_cfg/utils/toolkit.py +0 -703
  427. django_cfg-1.3.13.dist-info/METADATA +0 -1029
  428. /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
  429. /django_cfg/core/{environment.py → environment/detector.py} +0 -0
  430. /django_cfg/models/{cors.py → api/cors.py} +0 -0
  431. /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
  432. /django_cfg/models/{base.py → base/config.py} +0 -0
  433. /django_cfg/models/{cfg.py → base/module.py} +0 -0
  434. /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
  435. /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
  436. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/WHEEL +0 -0
  437. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/entry_points.txt +0 -0
  438. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,189 +0,0 @@
1
- # """
2
- # Django management command to validate configuration.
3
-
4
- # Usage:
5
- # python manage.py validate_config
6
- # """
7
-
8
- # from django.core.management.base import BaseCommand, CommandError
9
- # from django.conf import settings
10
- # from django.core.cache import cache
11
-
12
-
13
-
14
- # class Command(BaseCommand):
15
- # help = 'Validate Django Config Toolkit configuration'
16
-
17
- # def add_arguments(self, parser):
18
- # parser.add_argument(
19
- # '--show-details',
20
- # action='store_true',
21
- # help='Show detailed configuration information',
22
- # )
23
- # parser.add_argument(
24
- # '--check-connections',
25
- # action='store_true',
26
- # help='Test database and cache connections',
27
- # )
28
-
29
- # def handle(self, *args, **options):
30
- # """Validate configuration and optionally show details."""
31
- # self.stdout.write(
32
- # self.style.HTTP_INFO('🚀 Django Config Toolkit - Configuration Validation')
33
- # )
34
- # self.stdout.write('=' * 60)
35
-
36
- # try:
37
- # # Initialize toolkit
38
- # toolkit = ConfigToolkit()
39
-
40
- # # Basic validation
41
- # self.stdout.write(
42
- # self.style.SUCCESS(f'✅ Configuration loaded successfully')
43
- # )
44
- # self.stdout.write(f' Environment: {toolkit.environment}')
45
- # self.stdout.write(f' Debug: {toolkit.debug}')
46
- # self.stdout.write(f' Configs loaded: {toolkit._config_count}')
47
- # self.stdout.write(f' Init time: {toolkit._init_time_ms:.2f}ms')
48
-
49
- # # Check secret key
50
- # if len(toolkit.secret_key) >= 50:
51
- # self.stdout.write(self.style.SUCCESS('✅ Secret key is secure'))
52
- # else:
53
- # self.stdout.write(
54
- # self.style.WARNING('⚠️ Secret key is too short (< 50 chars)')
55
- # )
56
-
57
- # # Check extended features
58
- # self.stdout.write('\n🎨 Extended Features:')
59
- # features = [
60
- # ('Unfold Admin', toolkit.unfold_enabled),
61
- # ('Revolution API', toolkit.revolution_enabled),
62
- # ('Constance Settings', toolkit.constance_enabled),
63
- # ('Advanced Logging', toolkit.logging_enabled),
64
- # ]
65
-
66
- # for name, enabled in features:
67
- # status = '✅' if enabled else '❌'
68
- # self.stdout.write(f' {status} {name}')
69
-
70
- # # Detailed information
71
- # if options['show_details']:
72
- # self._show_detailed_config(toolkit)
73
-
74
- # # Connection tests
75
- # if options['check_connections']:
76
- # self._test_connections(toolkit)
77
-
78
- # except Exception as e:
79
- # self.stdout.write(
80
- # self.style.ERROR(f'❌ Configuration validation failed: {e}')
81
- # )
82
- # raise CommandError(f'Configuration error: {e}')
83
-
84
- # self.stdout.write('=' * 60)
85
- # self.stdout.write(
86
- # self.style.SUCCESS('✨ Configuration validation completed!')
87
- # )
88
-
89
- # def _show_detailed_config(self, toolkit):
90
- # """Show detailed configuration information."""
91
- # self.stdout.write('\n📋 Detailed Configuration:')
92
-
93
- # # Environment configuration
94
- # self.stdout.write('\n🌍 Environment:')
95
- # if hasattr(toolkit._config, 'env_mode'):
96
- # self.stdout.write(f' Mode: {toolkit._config.env_mode}')
97
- # self.stdout.write(f' Debug: {toolkit._config.debug}')
98
-
99
- # # Database configuration
100
- # self.stdout.write('\n🗄️ Database:')
101
- # self.stdout.write(f' Engine: {toolkit.database_engine}')
102
- # self.stdout.write(f' Name: {toolkit.database_name}')
103
- # if hasattr(toolkit._db_config, 'has_multiple_databases'):
104
- # self.stdout.write(f' Multiple DBs: {toolkit._db_config.has_multiple_databases}')
105
-
106
- # # Security configuration
107
- # self.stdout.write('\n🔒 Security:')
108
- # self.stdout.write(f' CORS Enabled: {toolkit.cors_enabled}')
109
- # self.stdout.write(f' CSRF Enabled: {toolkit.csrf_enabled}')
110
- # self.stdout.write(f' SSL Redirect: {toolkit.ssl_enabled}')
111
-
112
- # # API configuration
113
- # self.stdout.write('\n🌐 API:')
114
- # self.stdout.write(f' Page Size: {toolkit.api_page_size}')
115
- # self.stdout.write(f' Rate Limiting: {toolkit.api_rate_limit_enabled}')
116
-
117
- # # Cache configuration
118
- # self.stdout.write('\n💾 Cache:')
119
- # self.stdout.write(f' Backend: {toolkit.cache_backend}')
120
- # self.stdout.write(f' Timeout: {toolkit.cache_timeout}s')
121
-
122
- # # Extended features details
123
- # if toolkit.unfold_enabled:
124
- # self.stdout.write('\n🎨 Unfold:')
125
- # self.stdout.write(f' Site Title: {toolkit.site_title}')
126
-
127
- # if toolkit.revolution_enabled:
128
- # self.stdout.write('\n🚀 Revolution:')
129
- # self.stdout.write(f' API Prefix: {toolkit.api_prefix}')
130
-
131
- # if toolkit.constance_enabled:
132
- # self.stdout.write('\n⚙️ Constance:')
133
- # self.stdout.write(f' Backend: {toolkit.constance_backend}')
134
-
135
- # self.stdout.write('\n📝 Logging:')
136
- # self.stdout.write(f' Log Level: {toolkit.log_level}')
137
-
138
- # def _test_connections(self, toolkit):
139
- # """Test database and cache connections."""
140
- # self.stdout.write('\n🔗 Connection Tests:')
141
-
142
- # # Test database connections
143
- # self.stdout.write('\n🗄️ Database connections:')
144
- # try:
145
- # from django.db import connections
146
-
147
- # for db_name in connections:
148
- # try:
149
- # connection = connections[db_name]
150
- # with connection.cursor() as cursor:
151
- # cursor.execute("SELECT 1")
152
- # cursor.fetchone()
153
-
154
- # self.stdout.write(
155
- # self.style.SUCCESS(f' ✅ {db_name}: Connected')
156
- # )
157
- # except Exception as e:
158
- # self.stdout.write(
159
- # self.style.ERROR(f' ❌ {db_name}: {str(e)}')
160
- # )
161
-
162
- # except Exception as e:
163
- # self.stdout.write(
164
- # self.style.ERROR(f' ❌ Database test failed: {e}')
165
- # )
166
-
167
- # # Test cache connection
168
- # self.stdout.write('\n💾 Cache connection:')
169
- # try:
170
-
171
- # test_key = 'config_validation_test'
172
- # test_value = 'test_value'
173
-
174
- # cache.set(test_key, test_value, 30)
175
- # retrieved_value = cache.get(test_key)
176
-
177
- # if retrieved_value == test_value:
178
- # self.stdout.write(
179
- # self.style.SUCCESS(' ✅ Cache: Working')
180
- # )
181
- # else:
182
- # self.stdout.write(
183
- # self.style.WARNING(' ⚠️ Cache: Read/write test failed')
184
- # )
185
-
186
- # except Exception as e:
187
- # self.stdout.write(
188
- # self.style.ERROR(f' ❌ Cache test failed: {e}')
189
- # )
@@ -1,480 +0,0 @@
1
- """
2
- Database configuration models for django_cfg.
3
-
4
- Following CRITICAL_REQUIREMENTS.md:
5
- - No raw Dict/Any usage - everything through Pydantic models
6
- - Proper type annotations for all fields
7
- - No mutable default arguments
8
- - Comprehensive validation with helpful error messages
9
- """
10
-
11
- from typing import Dict, List, Optional, Any, Literal, Union
12
- from pathlib import Path
13
- from pydantic import BaseModel, Field, field_validator, model_validator, PrivateAttr
14
- from urllib.parse import urlparse
15
-
16
- from django_cfg.core.exceptions import DatabaseError, ValidationError
17
-
18
-
19
- class DatabaseConfig(BaseModel):
20
- """
21
- Type-safe database connection configuration.
22
-
23
- Supports both individual connection parameters and connection strings.
24
- Automatically validates connection parameters and provides helpful error messages.
25
- """
26
-
27
- model_config = {
28
- "str_strip_whitespace": True,
29
- "validate_assignment": True,
30
- "extra": "forbid", # Prevent typos in field names
31
- }
32
-
33
- # Core connection parameters
34
- engine: Optional[str] = Field(
35
- default=None,
36
- description="Django database engine (e.g., 'django.db.backends.postgresql'). If not provided, will be auto-detected from database URL scheme.",
37
- min_length=1,
38
- )
39
-
40
- name: str = Field(
41
- ...,
42
- description="Database name or connection string",
43
- min_length=1,
44
- )
45
-
46
- user: Optional[str] = Field(
47
- default=None,
48
- description="Database username",
49
- )
50
-
51
- password: Optional[str] = Field(
52
- default=None,
53
- description="Database password",
54
- repr=False, # Don't show in repr for security
55
- )
56
-
57
- host: str = Field(
58
- default="localhost",
59
- description="Database host",
60
- min_length=1,
61
- )
62
-
63
- port: int = Field(
64
- default=5432,
65
- description="Database port",
66
- ge=1,
67
- le=65535,
68
- )
69
-
70
- # Connection options
71
- connect_timeout: int = Field(
72
- default=10,
73
- description="Connection timeout in seconds",
74
- ge=1,
75
- le=300, # Max 5 minutes
76
- )
77
-
78
- sslmode: str = Field(
79
- default="prefer",
80
- description="SSL mode for connection",
81
- )
82
-
83
- # Additional database options
84
- options: Dict[str, Any] = Field(
85
- default_factory=dict,
86
- description="Additional database-specific options",
87
- )
88
-
89
- # Database routing configuration
90
- apps: List[str] = Field(
91
- default_factory=list,
92
- description="Django app labels that should use this database",
93
- )
94
-
95
- operations: List[Literal["read", "write", "migrate"]] = Field(
96
- default_factory=lambda: ["read", "write", "migrate"],
97
- description="Allowed operations for this database",
98
- min_length=1,
99
- )
100
-
101
- migrate_to: Optional[str] = Field(
102
- default=None,
103
- description="Override database alias for migrations (if different from this database)",
104
- )
105
-
106
- routing_description: str = Field(
107
- default="",
108
- description="Human-readable description of the routing rule",
109
- )
110
-
111
- # Internal fields for parsed connection strings
112
- _is_connection_string: bool = PrivateAttr(default=False)
113
- _parsed_components: Optional[Dict[str, Any]] = PrivateAttr(default=None)
114
-
115
- @field_validator("engine")
116
- @classmethod
117
- def validate_engine(cls, v: Optional[str]) -> Optional[str]:
118
- """Validate Django database engine format."""
119
- if v is None:
120
- return v
121
-
122
- if not v.startswith("django.db.backends."):
123
- raise ValueError(f"Invalid database engine '{v}'. " "Must start with 'django.db.backends.'")
124
-
125
- # Common engines validation
126
- valid_engines = {
127
- "django.db.backends.postgresql",
128
- "django.db.backends.mysql",
129
- "django.db.backends.sqlite3",
130
- "django.db.backends.oracle",
131
- }
132
-
133
- if v not in valid_engines and not v.startswith("django.db.backends."):
134
- # Allow custom backends but warn about common typos
135
- common_typos = {
136
- "postgresql": "django.db.backends.postgresql",
137
- "postgres": "django.db.backends.postgresql",
138
- "mysql": "django.db.backends.mysql",
139
- "sqlite": "django.db.backends.sqlite3",
140
- "sqlite3": "django.db.backends.sqlite3",
141
- }
142
-
143
- if v in common_typos:
144
- raise ValueError(f"Invalid engine '{v}'. Did you mean '{common_typos[v]}'?")
145
-
146
- return v
147
-
148
- @field_validator("name")
149
- @classmethod
150
- def validate_name(cls, v: str) -> str:
151
- """Validate database name or parse connection string."""
152
- # Check if it's a connection string
153
- if "://" in v:
154
- try:
155
- parsed = urlparse(v)
156
- if not parsed.scheme:
157
- raise ValueError("Invalid connection string format")
158
- return v
159
- except Exception as e:
160
- raise ValueError(f"Invalid connection string: {e}") from e
161
-
162
- # Regular database name validation
163
- if v in [":memory:", ""]:
164
- return v # Special cases for SQLite
165
-
166
- # Check for path-like names (SQLite files)
167
- if "/" in v or "\\" in v or v.endswith(".db") or v.endswith(".sqlite3"):
168
- path = Path(v)
169
- if path.is_absolute() or v.startswith("./") or v.startswith("../"):
170
- return v # Valid file path
171
-
172
- return v
173
-
174
- @field_validator("sslmode")
175
- @classmethod
176
- def validate_sslmode(cls, v: str) -> str:
177
- """Validate SSL mode values."""
178
- valid_modes = {"disable", "allow", "prefer", "require", "verify-ca", "verify-full"}
179
-
180
- if v not in valid_modes:
181
- raise ValueError(f"Invalid SSL mode '{v}'. " f"Valid options: {', '.join(sorted(valid_modes))}")
182
-
183
- return v
184
-
185
- @model_validator(mode="before")
186
- @classmethod
187
- def validate_connection_consistency(cls, values: Dict[str, Any]) -> Dict[str, Any]:
188
- """Validate connection parameter consistency and auto-detect engine."""
189
- # Auto-detect engine if not provided
190
- if values.get("engine") is None and values.get("name"):
191
- values["engine"] = cls._detect_engine_from_url(values["name"])
192
-
193
- return values
194
-
195
- @model_validator(mode="after")
196
- def validate_connection_after(self) -> "DatabaseConfig":
197
- """Validate connection after model creation."""
198
- # Parse connection string if present
199
- if "://" in self.name:
200
- self._is_connection_string = True
201
- self._parsed_components = self._parse_connection_string(self.name)
202
-
203
- # Override individual parameters with parsed values if not explicitly set
204
- parsed = self._parsed_components
205
- if parsed and not self.user and parsed.get("user"):
206
- object.__setattr__(self, 'user', parsed["user"])
207
- if parsed and not self.password and parsed.get("password"):
208
- object.__setattr__(self, 'password', parsed["password"])
209
- if parsed and self.host == "localhost" and parsed.get("host"):
210
- object.__setattr__(self, 'host', parsed["host"])
211
- if parsed and self.port == 5432 and parsed.get("port"):
212
- object.__setattr__(self, 'port', parsed["port"])
213
-
214
- # Validate SQLite-specific constraints
215
- if self.engine == "django.db.backends.sqlite3":
216
- if self.name not in [":memory:", ""] and not (self.name.endswith((".db", ".sqlite", ".sqlite3")) or "/" in self.name or "\\" in self.name):
217
- raise ValueError("SQLite database name must be ':memory:', a file path, " "or end with .db, .sqlite, or .sqlite3")
218
-
219
- # Validate PostgreSQL-specific constraints
220
- elif self.engine == "django.db.backends.postgresql":
221
- if not self._is_connection_string and not self.name:
222
- raise ValueError("PostgreSQL database name is required")
223
-
224
- return self
225
-
226
- @staticmethod
227
- def _detect_engine_from_url(url: str) -> str:
228
- """
229
- Automatically detect Django database engine from URL scheme.
230
-
231
- Args:
232
- url: Database URL (e.g., 'postgresql://...', 'sqlite:///...')
233
-
234
- Returns:
235
- Django database engine string
236
-
237
- Raises:
238
- ValueError: If URL scheme is not supported
239
- """
240
- if "://" not in url:
241
- # Assume SQLite for file paths without scheme
242
- return "django.db.backends.sqlite3"
243
-
244
- scheme = url.split("://")[0].lower()
245
-
246
- # Map URL schemes to Django engines
247
- scheme_to_engine = {
248
- "postgresql": "django.db.backends.postgresql",
249
- "postgres": "django.db.backends.postgresql",
250
- "mysql": "django.db.backends.mysql",
251
- "sqlite": "django.db.backends.sqlite3",
252
- "sqlite3": "django.db.backends.sqlite3",
253
- "oracle": "django.db.backends.oracle",
254
- }
255
-
256
- if scheme in scheme_to_engine:
257
- return scheme_to_engine[scheme]
258
-
259
- raise ValueError(
260
- f"Unsupported database scheme '{scheme}'. "
261
- f"Supported schemes: {', '.join(scheme_to_engine.keys())}"
262
- )
263
-
264
- @staticmethod
265
- def _parse_connection_string(connection_string: str) -> Dict[str, Any]:
266
- """Parse database connection string into components."""
267
- try:
268
- parsed = urlparse(connection_string)
269
-
270
- components = {
271
- "scheme": parsed.scheme,
272
- "user": parsed.username,
273
- "password": parsed.password,
274
- "host": parsed.hostname,
275
- "port": parsed.port,
276
- "database": parsed.path.lstrip("/") if parsed.path else None,
277
- }
278
-
279
- # Parse query parameters as options
280
- if parsed.query:
281
- from urllib.parse import parse_qs
282
-
283
- query_params = parse_qs(parsed.query)
284
- components["options"] = {k: v[0] if len(v) == 1 else v for k, v in query_params.items()}
285
-
286
- return components
287
-
288
- except Exception as e:
289
- raise DatabaseError(f"Failed to parse connection string: {e}", context={"connection_string": connection_string}) from e
290
-
291
- def to_django_config(self) -> Dict[str, Any]:
292
- """
293
- Convert to Django database configuration format.
294
-
295
- Returns:
296
- Django-compatible database configuration dictionary
297
-
298
- Raises:
299
- DatabaseError: If configuration cannot be converted
300
- """
301
- try:
302
- # Base configuration
303
- config = {
304
- "ENGINE": self.engine,
305
- "OPTIONS": {**self.options},
306
- }
307
-
308
- # Add database-specific options
309
- if self.engine == "django.db.backends.postgresql":
310
- # PostgreSQL supports connect_timeout and sslmode
311
- config["OPTIONS"]["connect_timeout"] = self.connect_timeout
312
- config["OPTIONS"]["sslmode"] = self.sslmode
313
- elif self.engine == "django.db.backends.mysql":
314
- # MySQL supports connect_timeout but not sslmode
315
- config["OPTIONS"]["connect_timeout"] = self.connect_timeout
316
- # SQLite doesn't support connect_timeout or sslmode, so we skip them
317
-
318
- # Handle connection string vs individual parameters
319
- if self._is_connection_string:
320
- # For connection strings, use the full string as NAME
321
- config["NAME"] = self.name
322
-
323
- # Add parsed components if available
324
- if self._parsed_components:
325
- parsed = self._parsed_components
326
- if parsed.get("database"):
327
- config["NAME"] = parsed["database"]
328
- if parsed.get("user"):
329
- config["USER"] = parsed["user"]
330
- if parsed.get("password"):
331
- config["PASSWORD"] = parsed["password"]
332
- if parsed.get("host"):
333
- config["HOST"] = parsed["host"]
334
- if parsed.get("port"):
335
- config["PORT"] = parsed["port"]
336
- if parsed.get("options"):
337
- config["OPTIONS"].update(parsed["options"])
338
- else:
339
- # Individual parameters
340
- config["NAME"] = self.name
341
-
342
- if self.user:
343
- config["USER"] = self.user
344
-
345
- if self.password:
346
- config["PASSWORD"] = self.password
347
-
348
- if self.host:
349
- config["HOST"] = self.host
350
-
351
- if self.port:
352
- config["PORT"] = self.port
353
-
354
- return config
355
-
356
- except Exception as e:
357
- raise DatabaseError(f"Failed to convert database configuration: {e}", database_alias=getattr(self, "_alias", "unknown"), context={"config": self.model_dump()}) from e
358
-
359
- @field_validator("apps")
360
- @classmethod
361
- def validate_apps(cls, v: List[str]) -> List[str]:
362
- """Validate app labels format."""
363
- for app in v:
364
- if not app or not app.replace("_", "").replace(".", "").isalnum():
365
- raise ValueError(f"Invalid app label '{app}'. " "App labels must contain only letters, numbers, dots, and underscores")
366
- return v
367
-
368
- @field_validator("operations")
369
- @classmethod
370
- def validate_operations(cls, v: List[str]) -> List[str]:
371
- """Validate operations list."""
372
- if not v:
373
- raise ValueError("At least one operation must be specified")
374
-
375
- valid_ops = {"read", "write", "migrate"}
376
- for op in v:
377
- if op not in valid_ops:
378
- raise ValueError(f"Invalid operation '{op}'. " f"Valid operations: {', '.join(sorted(valid_ops))}")
379
- return v
380
-
381
- def matches_app(self, app_label: str) -> bool:
382
- """
383
- Check if this database should be used for the given app.
384
-
385
- Args:
386
- app_label: Django app label to check
387
-
388
- Returns:
389
- True if this database should be used for the app
390
- """
391
- return app_label in self.apps
392
-
393
- def allows_operation(self, operation: str) -> bool:
394
- """
395
- Check if this database allows the given operation.
396
-
397
- Args:
398
- operation: Operation to check ('read', 'write', 'migrate')
399
-
400
- Returns:
401
- True if operation is allowed
402
- """
403
- return operation in self.operations
404
-
405
- def get_migration_database(self) -> Optional[str]:
406
- """
407
- Get the database alias to use for migrations.
408
-
409
- Returns:
410
- Database alias for migrations, or None to use this database
411
- """
412
- return self.migrate_to
413
-
414
- def has_routing_rules(self) -> bool:
415
- """
416
- Check if this database has any routing rules configured.
417
-
418
- Returns:
419
- True if apps list is not empty
420
- """
421
- return bool(self.apps)
422
-
423
- def test_connection(self) -> bool:
424
- """
425
- Test database connection (placeholder for future implementation).
426
-
427
- Returns:
428
- True if connection successful, False otherwise
429
- """
430
- # TODO: Implement actual connection testing
431
- # This would require Django to be available and configured
432
- return True
433
-
434
- @classmethod
435
- def from_url(
436
- cls,
437
- url: str,
438
- *,
439
- apps: Optional[List[str]] = None,
440
- operations: Optional[List[Literal["read", "write", "migrate"]]] = None,
441
- routing_description: str = "",
442
- **kwargs
443
- ) -> "DatabaseConfig":
444
- """
445
- Create DatabaseConfig from URL with automatic engine detection.
446
-
447
- Args:
448
- url: Database URL (e.g., 'postgresql://user:pass@host:port/db')
449
- apps: Django app labels that should use this database
450
- operations: Allowed operations for this database
451
- routing_description: Human-readable description of the routing rule
452
- **kwargs: Additional parameters to override defaults
453
-
454
- Returns:
455
- DatabaseConfig instance with auto-detected engine
456
-
457
- Example:
458
- # Simple SQLite database
459
- db = DatabaseConfig.from_url("sqlite:///db.sqlite3")
460
-
461
- # PostgreSQL with routing
462
- blog_db = DatabaseConfig.from_url(
463
- "postgresql://user:pass@localhost:5432/blog",
464
- apps=["apps.blog"],
465
- routing_description="Blog posts and comments"
466
- )
467
- """
468
- return cls(
469
- name=url,
470
- apps=apps or [],
471
- operations=operations or ["read", "write", "migrate"],
472
- routing_description=routing_description,
473
- **kwargs
474
- )
475
-
476
-
477
- # Export all models
478
- __all__ = [
479
- "DatabaseConfig",
480
- ]