django-cfg 1.4.120__py3-none-any.whl → 1.5.2__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (182) hide show
  1. django_cfg/__init__.py +8 -4
  2. django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
  3. django_cfg/apps/dashboard/TRANSACTION_FIX.md +73 -0
  4. django_cfg/apps/dashboard/serializers/__init__.py +0 -12
  5. django_cfg/apps/dashboard/serializers/activity.py +1 -1
  6. django_cfg/apps/dashboard/services/__init__.py +0 -2
  7. django_cfg/apps/dashboard/services/charts_service.py +4 -3
  8. django_cfg/apps/dashboard/services/statistics_service.py +11 -2
  9. django_cfg/apps/dashboard/services/system_health_service.py +64 -106
  10. django_cfg/apps/dashboard/urls.py +0 -2
  11. django_cfg/apps/dashboard/views/__init__.py +0 -2
  12. django_cfg/apps/dashboard/views/commands_views.py +3 -6
  13. django_cfg/apps/dashboard/views/overview_views.py +14 -13
  14. django_cfg/apps/grpc/__init__.py +9 -0
  15. django_cfg/apps/grpc/admin/__init__.py +11 -0
  16. django_cfg/apps/{tasks → grpc}/admin/config.py +32 -41
  17. django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
  18. django_cfg/apps/grpc/apps.py +28 -0
  19. django_cfg/apps/grpc/auth/__init__.py +9 -0
  20. django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
  21. django_cfg/apps/grpc/interceptors/__init__.py +19 -0
  22. django_cfg/apps/grpc/interceptors/errors.py +241 -0
  23. django_cfg/apps/grpc/interceptors/logging.py +270 -0
  24. django_cfg/apps/grpc/interceptors/metrics.py +306 -0
  25. django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
  26. django_cfg/apps/grpc/management/__init__.py +1 -0
  27. django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
  28. django_cfg/apps/grpc/managers/__init__.py +10 -0
  29. django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
  30. django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
  31. django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
  32. django_cfg/apps/grpc/models/__init__.py +9 -0
  33. django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
  34. django_cfg/apps/grpc/serializers/__init__.py +23 -0
  35. django_cfg/apps/grpc/serializers/health.py +18 -0
  36. django_cfg/apps/grpc/serializers/requests.py +18 -0
  37. django_cfg/apps/grpc/serializers/services.py +50 -0
  38. django_cfg/apps/grpc/serializers/stats.py +22 -0
  39. django_cfg/apps/grpc/services/__init__.py +16 -0
  40. django_cfg/apps/grpc/services/base.py +375 -0
  41. django_cfg/apps/grpc/services/discovery.py +415 -0
  42. django_cfg/apps/grpc/urls.py +23 -0
  43. django_cfg/apps/grpc/utils/__init__.py +13 -0
  44. django_cfg/apps/grpc/utils/proto_gen.py +423 -0
  45. django_cfg/apps/grpc/views/__init__.py +9 -0
  46. django_cfg/apps/grpc/views/monitoring.py +497 -0
  47. django_cfg/apps/knowbase/apps.py +2 -2
  48. django_cfg/apps/maintenance/admin/api_key_admin.py +7 -9
  49. django_cfg/apps/maintenance/admin/site_admin.py +5 -4
  50. django_cfg/apps/newsletter/admin/newsletter_admin.py +12 -11
  51. django_cfg/apps/payments/admin/balance_admin.py +26 -36
  52. django_cfg/apps/payments/admin/payment_admin.py +65 -85
  53. django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
  54. django_cfg/apps/rq/__init__.py +9 -0
  55. django_cfg/apps/rq/apps.py +80 -0
  56. django_cfg/apps/rq/management/__init__.py +1 -0
  57. django_cfg/apps/rq/management/commands/__init__.py +1 -0
  58. django_cfg/apps/rq/management/commands/rqscheduler.py +31 -0
  59. django_cfg/apps/rq/management/commands/rqstats.py +33 -0
  60. django_cfg/apps/rq/management/commands/rqworker.py +31 -0
  61. django_cfg/apps/rq/management/commands/rqworker_pool.py +27 -0
  62. django_cfg/apps/rq/serializers/__init__.py +40 -0
  63. django_cfg/apps/rq/serializers/health.py +60 -0
  64. django_cfg/apps/rq/serializers/job.py +100 -0
  65. django_cfg/apps/rq/serializers/queue.py +80 -0
  66. django_cfg/apps/rq/serializers/schedule.py +178 -0
  67. django_cfg/apps/rq/serializers/testing.py +139 -0
  68. django_cfg/apps/rq/serializers/worker.py +58 -0
  69. django_cfg/apps/rq/services/__init__.py +25 -0
  70. django_cfg/apps/rq/services/config_helper.py +233 -0
  71. django_cfg/apps/rq/services/models/README.md +417 -0
  72. django_cfg/apps/rq/services/models/__init__.py +30 -0
  73. django_cfg/apps/rq/services/models/event.py +123 -0
  74. django_cfg/apps/rq/services/models/job.py +99 -0
  75. django_cfg/apps/rq/services/models/queue.py +92 -0
  76. django_cfg/apps/rq/services/models/worker.py +104 -0
  77. django_cfg/apps/rq/services/rq_converters.py +183 -0
  78. django_cfg/apps/rq/tasks/__init__.py +23 -0
  79. django_cfg/apps/rq/tasks/demo_tasks.py +284 -0
  80. django_cfg/apps/rq/urls.py +54 -0
  81. django_cfg/apps/rq/views/__init__.py +19 -0
  82. django_cfg/apps/rq/views/jobs.py +882 -0
  83. django_cfg/apps/rq/views/monitoring.py +248 -0
  84. django_cfg/apps/rq/views/queues.py +261 -0
  85. django_cfg/apps/rq/views/schedule.py +400 -0
  86. django_cfg/apps/rq/views/testing.py +761 -0
  87. django_cfg/apps/rq/views/workers.py +195 -0
  88. django_cfg/apps/urls.py +13 -8
  89. django_cfg/config.py +106 -0
  90. django_cfg/core/base/config_model.py +16 -26
  91. django_cfg/core/builders/apps_builder.py +7 -11
  92. django_cfg/core/generation/integration_generators/__init__.py +3 -6
  93. django_cfg/core/generation/integration_generators/django_rq.py +80 -0
  94. django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
  95. django_cfg/core/generation/orchestrator.py +15 -15
  96. django_cfg/core/integration/display/startup.py +6 -20
  97. django_cfg/mixins/__init__.py +2 -0
  98. django_cfg/mixins/superadmin_api.py +59 -0
  99. django_cfg/models/__init__.py +3 -3
  100. django_cfg/models/api/grpc/__init__.py +59 -0
  101. django_cfg/models/api/grpc/config.py +364 -0
  102. django_cfg/models/django/__init__.py +3 -3
  103. django_cfg/models/django/django_rq.py +621 -0
  104. django_cfg/models/django/revolution_legacy.py +1 -1
  105. django_cfg/modules/base.py +19 -6
  106. django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
  107. django_cfg/modules/django_admin/config/background_task_config.py +4 -4
  108. django_cfg/modules/django_admin/utils/__init__.py +41 -3
  109. django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
  110. django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
  111. django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
  112. django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
  113. django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
  114. django_cfg/modules/django_admin/utils/html/badges.py +47 -0
  115. django_cfg/modules/django_admin/utils/html/base.py +167 -0
  116. django_cfg/modules/django_admin/utils/html/code.py +87 -0
  117. django_cfg/modules/django_admin/utils/html/composition.py +205 -0
  118. django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
  119. django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
  120. django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
  121. django_cfg/modules/django_admin/utils/html/progress.py +127 -0
  122. django_cfg/modules/django_admin/utils/html_builder.py +55 -408
  123. django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
  124. django_cfg/modules/django_unfold/navigation.py +21 -18
  125. django_cfg/pyproject.toml +4 -6
  126. django_cfg/registry/core.py +4 -7
  127. django_cfg/registry/modules.py +6 -0
  128. django_cfg/static/frontend/admin.zip +0 -0
  129. django_cfg/templates/admin/constance/includes/results_list.html +73 -0
  130. django_cfg/templates/admin/index.html +187 -62
  131. django_cfg/templatetags/django_cfg.py +61 -1
  132. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/METADATA +12 -4
  133. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/RECORD +140 -96
  134. django_cfg/apps/dashboard/permissions.py +0 -48
  135. django_cfg/apps/dashboard/serializers/django_q2.py +0 -50
  136. django_cfg/apps/dashboard/services/django_q2_service.py +0 -159
  137. django_cfg/apps/dashboard/views/django_q2_views.py +0 -79
  138. django_cfg/apps/tasks/__init__.py +0 -64
  139. django_cfg/apps/tasks/admin/__init__.py +0 -4
  140. django_cfg/apps/tasks/admin/task_log.py +0 -265
  141. django_cfg/apps/tasks/apps.py +0 -15
  142. django_cfg/apps/tasks/filters/__init__.py +0 -10
  143. django_cfg/apps/tasks/filters/task_log.py +0 -121
  144. django_cfg/apps/tasks/migrations/0001_initial.py +0 -196
  145. django_cfg/apps/tasks/migrations/0002_delete_tasklog.py +0 -16
  146. django_cfg/apps/tasks/models/__init__.py +0 -4
  147. django_cfg/apps/tasks/models/task_log.py +0 -246
  148. django_cfg/apps/tasks/serializers/__init__.py +0 -28
  149. django_cfg/apps/tasks/serializers/task_log.py +0 -249
  150. django_cfg/apps/tasks/services/__init__.py +0 -10
  151. django_cfg/apps/tasks/services/client/__init__.py +0 -7
  152. django_cfg/apps/tasks/services/client/client.py +0 -234
  153. django_cfg/apps/tasks/services/config_helper.py +0 -63
  154. django_cfg/apps/tasks/services/sync.py +0 -204
  155. django_cfg/apps/tasks/urls.py +0 -16
  156. django_cfg/apps/tasks/views/__init__.py +0 -10
  157. django_cfg/apps/tasks/views/task_log.py +0 -41
  158. django_cfg/apps/tasks/views/task_log_base.py +0 -41
  159. django_cfg/apps/tasks/views/task_log_overview.py +0 -100
  160. django_cfg/apps/tasks/views/task_log_related.py +0 -41
  161. django_cfg/apps/tasks/views/task_log_stats.py +0 -91
  162. django_cfg/apps/tasks/views/task_log_timeline.py +0 -81
  163. django_cfg/core/generation/integration_generators/django_q2.py +0 -133
  164. django_cfg/core/generation/integration_generators/tasks.py +0 -88
  165. django_cfg/models/django/django_q2.py +0 -514
  166. django_cfg/models/tasks/__init__.py +0 -49
  167. django_cfg/models/tasks/backends.py +0 -122
  168. django_cfg/models/tasks/config.py +0 -209
  169. django_cfg/models/tasks/utils.py +0 -162
  170. django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
  171. django_cfg/modules/django_q2/README.md +0 -140
  172. django_cfg/modules/django_q2/__init__.py +0 -8
  173. django_cfg/modules/django_q2/apps.py +0 -107
  174. django_cfg/modules/django_q2/management/commands/__init__.py +0 -0
  175. django_cfg/modules/django_q2/management/commands/sync_django_q_schedules.py +0 -74
  176. /django_cfg/apps/{tasks/migrations → grpc/management/commands}/__init__.py +0 -0
  177. /django_cfg/{modules/django_q2/management → apps/grpc/migrations}/__init__.py +0 -0
  178. /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
  179. /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
  180. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/WHEEL +0 -0
  181. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/entry_points.txt +0 -0
  182. {django_cfg-1.4.120.dist-info → django_cfg-1.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,364 @@
1
+ """
2
+ gRPC Configuration Models
3
+
4
+ Type-safe Pydantic v2 models for gRPC server, authentication, and proto generation.
5
+
6
+ Example:
7
+ >>> from django_cfg.models.api.grpc import GRPCConfig
8
+ >>> config = GRPCConfig(
9
+ ... enabled=True,
10
+ ... server=GRPCServerConfig(port=50051),
11
+ ... auth=GRPCAuthConfig(require_auth=True)
12
+ ... )
13
+ """
14
+
15
+ import warnings
16
+ from typing import Dict, List, Optional
17
+
18
+ from pydantic import Field, field_validator, model_validator
19
+
20
+ from django_cfg.models.base import BaseConfig
21
+
22
+
23
+ class GRPCServerConfig(BaseConfig):
24
+ """
25
+ gRPC server configuration.
26
+
27
+ Configures the gRPC server including host, port, workers, compression,
28
+ message limits, and keepalive settings.
29
+
30
+ Example:
31
+ >>> config = GRPCServerConfig(
32
+ ... host="0.0.0.0",
33
+ ... port=50051,
34
+ ... max_workers=10,
35
+ ... compression="gzip"
36
+ ... )
37
+ """
38
+
39
+ enabled: bool = Field(
40
+ default=True,
41
+ description="Enable gRPC server",
42
+ )
43
+
44
+ host: str = Field(
45
+ default="[::]",
46
+ description="Server bind address (IPv6 by default, use 0.0.0.0 for IPv4)",
47
+ )
48
+
49
+ port: int = Field(
50
+ default=50051,
51
+ description="Server port",
52
+ ge=1024,
53
+ le=65535,
54
+ )
55
+
56
+ max_workers: int = Field(
57
+ default=10,
58
+ description="ThreadPoolExecutor max workers",
59
+ ge=1,
60
+ le=1000,
61
+ )
62
+
63
+ enable_reflection: bool = Field(
64
+ default=False,
65
+ description="Enable server reflection for dynamic clients (grpcurl, etc.)",
66
+ )
67
+
68
+ enable_health_check: bool = Field(
69
+ default=True,
70
+ description="Enable gRPC health check service",
71
+ )
72
+
73
+ compression: Optional[str] = Field(
74
+ default=None,
75
+ description="Compression algorithm: 'gzip', 'deflate', or None",
76
+ )
77
+
78
+ max_send_message_length: int = Field(
79
+ default=4 * 1024 * 1024, # 4 MB
80
+ description="Maximum outbound message size in bytes",
81
+ ge=1024, # Min 1KB
82
+ le=100 * 1024 * 1024, # Max 100MB
83
+ )
84
+
85
+ max_receive_message_length: int = Field(
86
+ default=4 * 1024 * 1024, # 4 MB
87
+ description="Maximum inbound message size in bytes",
88
+ ge=1024,
89
+ le=100 * 1024 * 1024,
90
+ )
91
+
92
+ keepalive_time_ms: int = Field(
93
+ default=7200000, # 2 hours
94
+ description="Keepalive ping interval in milliseconds",
95
+ ge=1000, # Min 1 second
96
+ )
97
+
98
+ keepalive_timeout_ms: int = Field(
99
+ default=20000, # 20 seconds
100
+ description="Keepalive ping timeout in milliseconds",
101
+ ge=1000,
102
+ )
103
+
104
+ interceptors: List[str] = Field(
105
+ default_factory=list,
106
+ description="Server interceptor import paths (e.g., 'myapp.interceptors.AuthInterceptor')",
107
+ )
108
+
109
+ @field_validator("compression")
110
+ @classmethod
111
+ def validate_compression(cls, v: Optional[str]) -> Optional[str]:
112
+ """Validate compression algorithm."""
113
+ if v and v not in ("gzip", "deflate"):
114
+ raise ValueError(
115
+ f"Invalid compression: {v}. Must be 'gzip', 'deflate', or None"
116
+ )
117
+ return v
118
+
119
+ @field_validator("host")
120
+ @classmethod
121
+ def validate_host(cls, v: str) -> str:
122
+ """Validate host format."""
123
+ if not v or not v.strip():
124
+ raise ValueError("Host cannot be empty")
125
+ return v.strip()
126
+
127
+
128
+ class GRPCAuthConfig(BaseConfig):
129
+ """
130
+ gRPC authentication configuration.
131
+
132
+ Supports JWT authentication with configurable token handling.
133
+
134
+ Example:
135
+ >>> config = GRPCAuthConfig(
136
+ ... enabled=True,
137
+ ... require_auth=True,
138
+ ... jwt_algorithm="HS256"
139
+ ... )
140
+ """
141
+
142
+ enabled: bool = Field(
143
+ default=True,
144
+ description="Enable authentication",
145
+ )
146
+
147
+ require_auth: bool = Field(
148
+ default=True,
149
+ description="Require authentication for all services (except public_methods)",
150
+ )
151
+
152
+ token_header: str = Field(
153
+ default="authorization",
154
+ description="Metadata key for auth token",
155
+ )
156
+
157
+ token_prefix: str = Field(
158
+ default="Bearer",
159
+ description="Token prefix (e.g., 'Bearer' for JWT)",
160
+ )
161
+
162
+ jwt_secret_key: Optional[str] = Field(
163
+ default=None,
164
+ description="JWT secret key (defaults to Django SECRET_KEY if None)",
165
+ )
166
+
167
+ jwt_algorithm: str = Field(
168
+ default="HS256",
169
+ description="JWT signing algorithm",
170
+ )
171
+
172
+ jwt_verify_exp: bool = Field(
173
+ default=True,
174
+ description="Verify JWT expiration",
175
+ )
176
+
177
+ jwt_leeway: int = Field(
178
+ default=0,
179
+ description="JWT expiration leeway in seconds",
180
+ ge=0,
181
+ )
182
+
183
+ public_methods: List[str] = Field(
184
+ default_factory=lambda: [
185
+ "/grpc.health.v1.Health/Check",
186
+ "/grpc.health.v1.Health/Watch",
187
+ ],
188
+ description="RPC methods that don't require authentication",
189
+ )
190
+
191
+ @field_validator("jwt_algorithm")
192
+ @classmethod
193
+ def validate_jwt_algorithm(cls, v: str) -> str:
194
+ """Validate JWT algorithm."""
195
+ valid_algorithms = {
196
+ "HS256",
197
+ "HS384",
198
+ "HS512",
199
+ "RS256",
200
+ "RS384",
201
+ "RS512",
202
+ "ES256",
203
+ "ES384",
204
+ "ES512",
205
+ }
206
+ if v not in valid_algorithms:
207
+ raise ValueError(
208
+ f"Invalid JWT algorithm: {v}. "
209
+ f"Must be one of: {', '.join(sorted(valid_algorithms))}"
210
+ )
211
+ return v
212
+
213
+
214
+ class GRPCProtoConfig(BaseConfig):
215
+ """
216
+ Proto file generation configuration.
217
+
218
+ Controls automatic proto file generation from Django models.
219
+
220
+ Example:
221
+ >>> config = GRPCProtoConfig(
222
+ ... auto_generate=True,
223
+ ... output_dir="protos",
224
+ ... package_prefix="mycompany"
225
+ ... )
226
+ """
227
+
228
+ auto_generate: bool = Field(
229
+ default=True,
230
+ description="Auto-generate proto files from Django models",
231
+ )
232
+
233
+ output_dir: str = Field(
234
+ default="protos",
235
+ description="Proto files output directory (relative to BASE_DIR)",
236
+ )
237
+
238
+ package_prefix: str = Field(
239
+ default="",
240
+ description="Package prefix for all generated protos (e.g., 'mycompany')",
241
+ )
242
+
243
+ include_services: bool = Field(
244
+ default=True,
245
+ description="Include service definitions in generated protos",
246
+ )
247
+
248
+ field_naming: str = Field(
249
+ default="snake_case",
250
+ description="Proto field naming convention",
251
+ )
252
+
253
+ @field_validator("field_naming")
254
+ @classmethod
255
+ def validate_field_naming(cls, v: str) -> str:
256
+ """Validate field naming convention."""
257
+ if v not in ("snake_case", "camelCase"):
258
+ raise ValueError(
259
+ f"Invalid field_naming: {v}. Must be 'snake_case' or 'camelCase'"
260
+ )
261
+ return v
262
+
263
+ @field_validator("output_dir")
264
+ @classmethod
265
+ def validate_output_dir(cls, v: str) -> str:
266
+ """Validate output directory."""
267
+ if not v or not v.strip():
268
+ raise ValueError("output_dir cannot be empty")
269
+ # Remove leading/trailing slashes
270
+ return v.strip().strip("/")
271
+
272
+
273
+ class GRPCConfig(BaseConfig):
274
+ """
275
+ Main gRPC configuration.
276
+
277
+ Combines server, authentication, and proto generation settings.
278
+
279
+ Example:
280
+ Basic setup:
281
+ >>> config = GRPCConfig(enabled=True)
282
+
283
+ Advanced setup:
284
+ >>> config = GRPCConfig(
285
+ ... enabled=True,
286
+ ... server=GRPCServerConfig(port=8080, max_workers=50),
287
+ ... auth=GRPCAuthConfig(require_auth=True),
288
+ ... auto_register_apps=["accounts", "support"]
289
+ ... )
290
+ """
291
+
292
+ enabled: bool = Field(
293
+ default=False,
294
+ description="Enable gRPC integration",
295
+ )
296
+
297
+ server: GRPCServerConfig = Field(
298
+ default_factory=GRPCServerConfig,
299
+ description="Server configuration",
300
+ )
301
+
302
+ auth: GRPCAuthConfig = Field(
303
+ default_factory=GRPCAuthConfig,
304
+ description="Authentication configuration",
305
+ )
306
+
307
+ proto: GRPCProtoConfig = Field(
308
+ default_factory=GRPCProtoConfig,
309
+ description="Proto generation configuration",
310
+ )
311
+
312
+ handlers_hook: str = Field(
313
+ default="{ROOT_URLCONF}.grpc_handlers",
314
+ description="Import path to grpc_handlers function",
315
+ )
316
+
317
+ auto_register_apps: bool = Field(
318
+ default=True,
319
+ description="Auto-register gRPC services for Django-CFG apps",
320
+ )
321
+
322
+ enabled_apps: List[str] = Field(
323
+ default_factory=lambda: [
324
+ "accounts",
325
+ "support",
326
+ "knowbase",
327
+ "agents",
328
+ "payments",
329
+ "leads",
330
+ ],
331
+ description="Django-CFG apps to expose via gRPC (if auto_register_apps=True)",
332
+ )
333
+
334
+ custom_services: Dict[str, str] = Field(
335
+ default_factory=dict,
336
+ description="Custom service import paths: {service_name: 'path.to.Service'}",
337
+ )
338
+
339
+ @model_validator(mode="after")
340
+ def validate_grpc_config(self) -> "GRPCConfig":
341
+ """Cross-field validation."""
342
+ # Check dependencies if enabled
343
+ if self.enabled:
344
+ from django_cfg.config import require_feature
345
+
346
+ require_feature("grpc")
347
+
348
+ # Validate server enabled
349
+ if not self.server.enabled:
350
+ raise ValueError(
351
+ "Cannot enable gRPC with server disabled. "
352
+ "Set server.enabled=True or grpc.enabled=False"
353
+ )
354
+
355
+ # Warn if auto_register but no apps
356
+ if self.auto_register_apps and not self.enabled_apps:
357
+ warnings.warn(
358
+ "auto_register_apps is True but enabled_apps is empty. "
359
+ "No services will be auto-registered.",
360
+ UserWarning,
361
+ stacklevel=2,
362
+ )
363
+
364
+ return self
@@ -6,7 +6,7 @@ Django integrations and extensions.
6
6
 
7
7
  from .axes import AxesConfig
8
8
  from .constance import ConstanceConfig, ConstanceField
9
- from .django_q2 import DjangoQ2Config, DjangoQ2ScheduleConfig
9
+ from .django_rq import DjangoRQConfig, RQQueueConfig
10
10
  from .environment import EnvironmentConfig
11
11
  from .openapi import OpenAPIClientConfig
12
12
 
@@ -14,8 +14,8 @@ __all__ = [
14
14
  "EnvironmentConfig",
15
15
  "ConstanceConfig",
16
16
  "ConstanceField",
17
- "DjangoQ2Config",
18
- "DjangoQ2ScheduleConfig",
17
+ "DjangoRQConfig",
18
+ "RQQueueConfig",
19
19
  "OpenAPIClientConfig",
20
20
  "AxesConfig",
21
21
  ]