django-cfg 1.4.113__py3-none-any.whl → 1.4.114__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 (32) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/dashboard/serializers/__init__.py +10 -8
  3. django_cfg/apps/dashboard/serializers/django_q2.py +50 -0
  4. django_cfg/apps/dashboard/services/__init__.py +2 -2
  5. django_cfg/apps/dashboard/services/django_q2_service.py +159 -0
  6. django_cfg/apps/dashboard/services/system_health_service.py +39 -26
  7. django_cfg/apps/dashboard/urls.py +2 -2
  8. django_cfg/apps/dashboard/views/__init__.py +2 -2
  9. django_cfg/apps/dashboard/views/django_q2_views.py +79 -0
  10. django_cfg/apps/tasks/migrations/0002_delete_tasklog.py +16 -0
  11. django_cfg/core/base/config_model.py +15 -5
  12. django_cfg/core/builders/apps_builder.py +3 -3
  13. django_cfg/core/generation/data_generators/cache.py +28 -2
  14. django_cfg/core/generation/integration_generators/__init__.py +4 -3
  15. django_cfg/core/generation/integration_generators/django_q2.py +133 -0
  16. django_cfg/core/generation/orchestrator.py +7 -7
  17. django_cfg/models/__init__.py +3 -3
  18. django_cfg/models/django/__init__.py +3 -3
  19. django_cfg/models/django/django_q2.py +491 -0
  20. django_cfg/pyproject.toml +2 -2
  21. django_cfg/registry/core.py +3 -3
  22. django_cfg/static/frontend/admin.zip +0 -0
  23. {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/METADATA +3 -2
  24. {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/RECORD +27 -26
  25. django_cfg/apps/dashboard/serializers/crontab.py +0 -84
  26. django_cfg/apps/dashboard/services/crontab_service.py +0 -210
  27. django_cfg/apps/dashboard/views/crontab_views.py +0 -72
  28. django_cfg/core/generation/integration_generators/crontab.py +0 -64
  29. django_cfg/models/django/crontab.py +0 -303
  30. {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/WHEEL +0 -0
  31. {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/entry_points.txt +0 -0
  32. {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py CHANGED
@@ -32,7 +32,7 @@ Example:
32
32
  default_app_config = "django_cfg.apps.DjangoCfgConfig"
33
33
 
34
34
  # Version information
35
- __version__ = "1.4.113"
35
+ __version__ = "1.4.114"
36
36
  __license__ = "MIT"
37
37
 
38
38
  # Import registry for organized lazy loading
@@ -22,10 +22,11 @@ from .commands import (
22
22
  CommandHelpResponseSerializer,
23
23
  )
24
24
  from .apizones import APIZoneSerializer, APIZonesSummarySerializer
25
- from .crontab import (
26
- CrontabJobSerializer,
27
- CrontabJobsSerializer,
28
- CrontabStatusSerializer,
25
+ from .django_q2 import (
26
+ DjangoQ2ScheduleSerializer,
27
+ DjangoQ2TaskSerializer,
28
+ DjangoQ2StatusSerializer,
29
+ DjangoQ2SummarySerializer,
29
30
  )
30
31
 
31
32
  __all__ = [
@@ -65,8 +66,9 @@ __all__ = [
65
66
  'APIZoneSerializer',
66
67
  'APIZonesSummarySerializer',
67
68
 
68
- # Crontab
69
- 'CrontabJobSerializer',
70
- 'CrontabJobsSerializer',
71
- 'CrontabStatusSerializer',
69
+ # Django-Q2
70
+ 'DjangoQ2ScheduleSerializer',
71
+ 'DjangoQ2TaskSerializer',
72
+ 'DjangoQ2StatusSerializer',
73
+ 'DjangoQ2SummarySerializer',
72
74
  ]
@@ -0,0 +1,50 @@
1
+ """
2
+ Django-Q2 Task Serializers
3
+
4
+ Serializers for displaying Django-Q2 scheduled tasks and task history.
5
+ """
6
+
7
+ from rest_framework import serializers
8
+
9
+
10
+ class DjangoQ2ScheduleSerializer(serializers.Serializer):
11
+ """Serializer for Django-Q2 scheduled tasks."""
12
+
13
+ id = serializers.IntegerField(read_only=True)
14
+ name = serializers.CharField(max_length=255)
15
+ func = serializers.CharField(max_length=512)
16
+ schedule_type = serializers.CharField(max_length=24)
17
+ repeats = serializers.IntegerField()
18
+ next_run = serializers.DateTimeField(allow_null=True)
19
+ last_run = serializers.DateTimeField(allow_null=True)
20
+
21
+
22
+ class DjangoQ2TaskSerializer(serializers.Serializer):
23
+ """Serializer for Django-Q2 task execution history."""
24
+
25
+ id = serializers.CharField(max_length=32)
26
+ name = serializers.CharField(max_length=255)
27
+ func = serializers.CharField(max_length=512)
28
+ started = serializers.DateTimeField()
29
+ stopped = serializers.DateTimeField(allow_null=True)
30
+ success = serializers.BooleanField()
31
+ result = serializers.CharField(allow_null=True)
32
+
33
+
34
+ class DjangoQ2StatusSerializer(serializers.Serializer):
35
+ """Serializer for Django-Q2 cluster status."""
36
+
37
+ cluster_running = serializers.BooleanField()
38
+ total_schedules = serializers.IntegerField()
39
+ active_schedules = serializers.IntegerField()
40
+ recent_tasks = serializers.IntegerField()
41
+ successful_tasks = serializers.IntegerField()
42
+ failed_tasks = serializers.IntegerField()
43
+
44
+
45
+ class DjangoQ2SummarySerializer(serializers.Serializer):
46
+ """Summary serializer for Django-Q2 dashboard."""
47
+
48
+ status = DjangoQ2StatusSerializer()
49
+ schedules = DjangoQ2ScheduleSerializer(many=True)
50
+ recent_tasks = DjangoQ2TaskSerializer(many=True)
@@ -11,7 +11,7 @@ from .charts_service import ChartsService
11
11
  from .commands_service import CommandsService
12
12
  from .apizones_service import APIZonesService
13
13
  from .overview_service import OverviewService
14
- from .crontab_service import CrontabService
14
+ from .django_q2_service import DjangoQ2Service
15
15
 
16
16
  __all__ = [
17
17
  'StatisticsService',
@@ -20,5 +20,5 @@ __all__ = [
20
20
  'CommandsService',
21
21
  'APIZonesService',
22
22
  'OverviewService',
23
- 'CrontabService',
23
+ 'DjangoQ2Service',
24
24
  ]
@@ -0,0 +1,159 @@
1
+ """
2
+ Django-Q2 Service
3
+
4
+ Business logic for collecting Django-Q2 task data.
5
+ """
6
+
7
+ from typing import Dict, List, Any
8
+
9
+
10
+ class DjangoQ2Service:
11
+ """Service for aggregating Django-Q2 task information."""
12
+
13
+ @staticmethod
14
+ def get_schedules() -> List[Dict[str, Any]]:
15
+ """
16
+ Get all scheduled tasks from Django-Q2.
17
+
18
+ Returns:
19
+ List of scheduled tasks with their configurations
20
+ """
21
+ try:
22
+ from django_q.models import Schedule
23
+
24
+ schedules = Schedule.objects.all().order_by('-next_run')
25
+ return [
26
+ {
27
+ 'id': schedule.id,
28
+ 'name': schedule.name,
29
+ 'func': schedule.func,
30
+ 'schedule_type': schedule.schedule_type,
31
+ 'repeats': schedule.repeats,
32
+ 'next_run': schedule.next_run,
33
+ 'last_run': getattr(schedule, 'last_run', None),
34
+ }
35
+ for schedule in schedules
36
+ ]
37
+ except ImportError:
38
+ # django-q2 not installed
39
+ return []
40
+ except Exception:
41
+ # Database error or table doesn't exist yet
42
+ return []
43
+
44
+ @staticmethod
45
+ def get_recent_tasks(limit: int = 20) -> List[Dict[str, Any]]:
46
+ """
47
+ Get recent task executions from Django-Q2.
48
+
49
+ Args:
50
+ limit: Maximum number of tasks to return
51
+
52
+ Returns:
53
+ List of recent task executions with their results
54
+ """
55
+ try:
56
+ from django_q.models import Task
57
+
58
+ tasks = Task.objects.all().order_by('-started')[:limit]
59
+ return [
60
+ {
61
+ 'id': task.id,
62
+ 'name': task.name,
63
+ 'func': task.func,
64
+ 'started': task.started,
65
+ 'stopped': task.stopped,
66
+ 'success': task.success,
67
+ 'result': str(task.result) if task.result else None,
68
+ }
69
+ for task in tasks
70
+ ]
71
+ except ImportError:
72
+ # django-q2 not installed
73
+ return []
74
+ except Exception:
75
+ # Database error or table doesn't exist yet
76
+ return []
77
+
78
+ @staticmethod
79
+ def get_cluster_status() -> Dict[str, Any]:
80
+ """
81
+ Get Django-Q2 cluster status.
82
+
83
+ Returns:
84
+ Dictionary with cluster status information
85
+ """
86
+ try:
87
+ from django_q.models import Schedule, Task
88
+ from django_q.cluster import Cluster
89
+
90
+ # Count schedules
91
+ total_schedules = Schedule.objects.count()
92
+ active_schedules = Schedule.objects.filter(repeats__gt=0).count()
93
+
94
+ # Count recent tasks (last 24 hours)
95
+ from django.utils import timezone
96
+ from datetime import timedelta
97
+
98
+ last_24h = timezone.now() - timedelta(hours=24)
99
+ recent_tasks = Task.objects.filter(started__gte=last_24h).count()
100
+ successful_tasks = Task.objects.filter(
101
+ started__gte=last_24h, success=True
102
+ ).count()
103
+ failed_tasks = Task.objects.filter(
104
+ started__gte=last_24h, success=False
105
+ ).count()
106
+
107
+ # Check if cluster is running
108
+ cluster_running = False
109
+ try:
110
+ # Check for recent task activity as proxy for cluster status
111
+ recent_task = Task.objects.filter(
112
+ started__gte=timezone.now() - timedelta(minutes=5)
113
+ ).exists()
114
+ cluster_running = recent_task
115
+ except Exception:
116
+ pass
117
+
118
+ return {
119
+ 'cluster_running': cluster_running,
120
+ 'total_schedules': total_schedules,
121
+ 'active_schedules': active_schedules,
122
+ 'recent_tasks': recent_tasks,
123
+ 'successful_tasks': successful_tasks,
124
+ 'failed_tasks': failed_tasks,
125
+ }
126
+ except ImportError:
127
+ # django-q2 not installed
128
+ return {
129
+ 'cluster_running': False,
130
+ 'total_schedules': 0,
131
+ 'active_schedules': 0,
132
+ 'recent_tasks': 0,
133
+ 'successful_tasks': 0,
134
+ 'failed_tasks': 0,
135
+ }
136
+ except Exception:
137
+ # Database error or table doesn't exist yet
138
+ return {
139
+ 'cluster_running': False,
140
+ 'total_schedules': 0,
141
+ 'active_schedules': 0,
142
+ 'recent_tasks': 0,
143
+ 'successful_tasks': 0,
144
+ 'failed_tasks': 0,
145
+ }
146
+
147
+ @classmethod
148
+ def get_summary(cls) -> Dict[str, Any]:
149
+ """
150
+ Get complete Django-Q2 summary for dashboard.
151
+
152
+ Returns:
153
+ Dictionary with status, schedules, and recent tasks
154
+ """
155
+ return {
156
+ 'status': cls.get_cluster_status(),
157
+ 'schedules': cls.get_schedules(),
158
+ 'recent_tasks': cls.get_recent_tasks(limit=10),
159
+ }
@@ -191,73 +191,86 @@ class SystemHealthService:
191
191
  'health_percentage': 0,
192
192
  }
193
193
 
194
- def check_crontab_health(self) -> Dict[str, Any]:
194
+ def check_django_q2_health(self) -> Dict[str, Any]:
195
195
  """
196
- Check crontab/scheduled jobs configuration and status.
196
+ Check Django-Q2 task scheduling configuration and status.
197
197
 
198
198
  Returns:
199
- Health status dictionary with job count and configuration details
199
+ Health status dictionary with schedule count and cluster status
200
200
  """
201
201
  try:
202
202
  from django_cfg.core.config import get_current_config
203
203
 
204
204
  config = get_current_config()
205
205
 
206
- # Check if crontab is configured
207
- if not hasattr(config, 'crontab') or not config.crontab:
206
+ # Check if django_q2 is configured
207
+ if not hasattr(config, 'django_q2') or not config.django_q2:
208
208
  return {
209
- 'component': 'crontab',
209
+ 'component': 'django_q2',
210
210
  'status': 'info',
211
- 'description': 'Crontab scheduling not configured',
211
+ 'description': 'Django-Q2 scheduling not configured',
212
212
  'last_check': datetime.now().isoformat(),
213
213
  'health_percentage': 100,
214
214
  'details': {
215
215
  'enabled': False,
216
- 'jobs_count': 0,
216
+ 'schedules_count': 0,
217
217
  }
218
218
  }
219
219
 
220
- crontab_config = config.crontab
220
+ django_q2_config = config.django_q2
221
221
 
222
222
  # Check if enabled
223
- if not crontab_config.enabled:
223
+ if not django_q2_config.enabled:
224
224
  return {
225
- 'component': 'crontab',
225
+ 'component': 'django_q2',
226
226
  'status': 'warning',
227
- 'description': 'Crontab scheduling is disabled',
227
+ 'description': 'Django-Q2 scheduling is disabled',
228
228
  'last_check': datetime.now().isoformat(),
229
229
  'health_percentage': 50,
230
230
  'details': {
231
231
  'enabled': False,
232
- 'jobs_count': len(crontab_config.jobs),
232
+ 'schedules_count': len(django_q2_config.schedules) if django_q2_config.schedules else 0,
233
233
  }
234
234
  }
235
235
 
236
- # Count enabled jobs
237
- enabled_jobs = [job for job in crontab_config.jobs if job.enabled]
238
- jobs_count = len(enabled_jobs)
236
+ # Count schedules
237
+ schedules_count = len(django_q2_config.schedules) if django_q2_config.schedules else 0
238
+
239
+ # Try to check cluster status from database
240
+ cluster_running = False
241
+ try:
242
+ from django_q.models import Schedule, Task
243
+ from django.utils import timezone
244
+ from datetime import timedelta
245
+
246
+ # Check for recent task activity
247
+ recent_task = Task.objects.filter(
248
+ started__gte=timezone.now() - timedelta(minutes=5)
249
+ ).exists()
250
+ cluster_running = recent_task
251
+ except Exception:
252
+ pass
239
253
 
240
254
  return {
241
- 'component': 'crontab',
255
+ 'component': 'django_q2',
242
256
  'status': 'healthy',
243
- 'description': f'{jobs_count} scheduled job(s) configured',
257
+ 'description': f'{schedules_count} schedule(s) configured, cluster {"running" if cluster_running else "idle"}',
244
258
  'last_check': datetime.now().isoformat(),
245
259
  'health_percentage': 100,
246
260
  'details': {
247
261
  'enabled': True,
248
- 'jobs_count': jobs_count,
249
- 'total_jobs': len(crontab_config.jobs),
250
- 'lock_jobs': crontab_config.lock_jobs,
251
- 'comment': crontab_config.comment,
262
+ 'schedules_count': schedules_count,
263
+ 'cluster_running': cluster_running,
264
+ 'workers': django_q2_config.workers,
252
265
  }
253
266
  }
254
267
 
255
268
  except Exception as e:
256
- self.logger.error(f"Crontab health check failed: {e}")
269
+ self.logger.error(f"Django-Q2 health check failed: {e}")
257
270
  return {
258
- 'component': 'crontab',
271
+ 'component': 'django_q2',
259
272
  'status': 'error',
260
- 'description': f'Crontab check error: {str(e)}',
273
+ 'description': f'Django-Q2 check error: {str(e)}',
261
274
  'last_check': datetime.now().isoformat(),
262
275
  'health_percentage': 0,
263
276
  }
@@ -276,7 +289,7 @@ class SystemHealthService:
276
289
  self.check_cache_health(),
277
290
  self.check_queue_health(),
278
291
  self.check_storage_health(),
279
- self.check_crontab_health(),
292
+ self.check_django_q2_health(),
280
293
  ]
281
294
 
282
295
  return checks
@@ -21,7 +21,7 @@ from .views import (
21
21
  ChartsViewSet,
22
22
  CommandsViewSet,
23
23
  APIZonesViewSet,
24
- CrontabViewSet,
24
+ DjangoQ2ViewSet,
25
25
  )
26
26
 
27
27
  app_name = 'django_cfg_dashboard'
@@ -35,7 +35,7 @@ router.register(r'activity', ActivityViewSet, basename='activity')
35
35
  router.register(r'charts', ChartsViewSet, basename='charts')
36
36
  router.register(r'commands', CommandsViewSet, basename='commands')
37
37
  router.register(r'zones', APIZonesViewSet, basename='zones')
38
- router.register(r'crontab', CrontabViewSet, basename='crontab')
38
+ router.register(r'django_q2', DjangoQ2ViewSet, basename='django_q2')
39
39
 
40
40
  urlpatterns = [
41
41
  # RESTful API endpoints using ViewSets
@@ -11,7 +11,7 @@ from .activity_views import ActivityViewSet
11
11
  from .charts_views import ChartsViewSet
12
12
  from .commands_views import CommandsViewSet
13
13
  from .apizones_views import APIZonesViewSet
14
- from .crontab_views import CrontabViewSet
14
+ from .django_q2_views import DjangoQ2ViewSet
15
15
 
16
16
  __all__ = [
17
17
  'OverviewViewSet',
@@ -21,5 +21,5 @@ __all__ = [
21
21
  'ChartsViewSet',
22
22
  'CommandsViewSet',
23
23
  'APIZonesViewSet',
24
- 'CrontabViewSet',
24
+ 'DjangoQ2ViewSet',
25
25
  ]
@@ -0,0 +1,79 @@
1
+ """
2
+ Django-Q2 ViewSet
3
+
4
+ API endpoints for Django-Q2 task monitoring.
5
+ """
6
+
7
+ from rest_framework import viewsets, status
8
+ from rest_framework.decorators import action
9
+ from rest_framework.response import Response
10
+ from rest_framework.permissions import IsAuthenticated
11
+
12
+ from ..services.django_q2_service import DjangoQ2Service
13
+ from ..serializers.django_q2 import (
14
+ DjangoQ2ScheduleSerializer,
15
+ DjangoQ2TaskSerializer,
16
+ DjangoQ2StatusSerializer,
17
+ DjangoQ2SummarySerializer,
18
+ )
19
+
20
+
21
+ class DjangoQ2ViewSet(viewsets.ViewSet):
22
+ """
23
+ ViewSet for Django-Q2 task monitoring.
24
+
25
+ Provides endpoints for:
26
+ - Scheduled tasks list
27
+ - Recent task executions
28
+ - Cluster status
29
+ - Complete summary
30
+ """
31
+
32
+ permission_classes = [IsAuthenticated]
33
+
34
+ @action(detail=False, methods=['get'])
35
+ def schedules(self, request):
36
+ """
37
+ Get all scheduled tasks.
38
+
39
+ GET /api/django_q2/schedules/
40
+ """
41
+ schedules = DjangoQ2Service.get_schedules()
42
+ serializer = DjangoQ2ScheduleSerializer(schedules, many=True)
43
+ return Response(serializer.data)
44
+
45
+ @action(detail=False, methods=['get'])
46
+ def tasks(self, request):
47
+ """
48
+ Get recent task executions.
49
+
50
+ GET /api/django_q2/tasks/
51
+ Query params:
52
+ - limit: Number of tasks to return (default: 20)
53
+ """
54
+ limit = int(request.query_params.get('limit', 20))
55
+ tasks = DjangoQ2Service.get_recent_tasks(limit=limit)
56
+ serializer = DjangoQ2TaskSerializer(tasks, many=True)
57
+ return Response(serializer.data)
58
+
59
+ @action(detail=False, methods=['get'])
60
+ def status(self, request):
61
+ """
62
+ Get Django-Q2 cluster status.
63
+
64
+ GET /api/django_q2/status/
65
+ """
66
+ status_data = DjangoQ2Service.get_cluster_status()
67
+ serializer = DjangoQ2StatusSerializer(status_data)
68
+ return Response(serializer.data)
69
+
70
+ def list(self, request):
71
+ """
72
+ Get complete Django-Q2 summary.
73
+
74
+ GET /api/django_q2/
75
+ Returns status, schedules, and recent tasks.
76
+ """
77
+ summary = DjangoQ2Service.get_summary()
78
+ serializer = DjangoQ2SummarySerializer(summary)
79
+ return Response(serializer.data)
@@ -0,0 +1,16 @@
1
+ # Generated by Django 5.2.7 on 2025-10-31 05:54
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("tasks", "0001_initial"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.DeleteModel(
14
+ name="TaskLog",
15
+ ),
16
+ ]
@@ -20,7 +20,7 @@ from ...models import (
20
20
  ApiKeys,
21
21
  AxesConfig,
22
22
  CacheConfig,
23
- CrontabConfig,
23
+ DjangoQ2Config,
24
24
  CryptoFieldsConfig,
25
25
  DatabaseConfig,
26
26
  DRFConfig,
@@ -217,9 +217,19 @@ class DjangoConfig(BaseModel):
217
217
  )
218
218
 
219
219
  # === Cache Configuration ===
220
+ # Redis URL - used for automatic cache configuration if cache_default is not set
221
+ redis_url: Optional[str] = Field(
222
+ default=None,
223
+ description=(
224
+ "Redis connection URL (redis://host:port/db). "
225
+ "If set and cache_default is None, automatically creates RedisCache backend. "
226
+ "Also used by tasks (ReArq, Django-Q2) if they don't specify broker_url."
227
+ ),
228
+ )
229
+
220
230
  cache_default: Optional[CacheConfig] = Field(
221
231
  default=None,
222
- description="Default cache backend",
232
+ description="Default cache backend (auto-created from redis_url if not set)",
223
233
  )
224
234
 
225
235
  cache_sessions: Optional[CacheConfig] = Field(
@@ -319,10 +329,10 @@ class DjangoConfig(BaseModel):
319
329
  description="Background task processing configuration (ReArq)",
320
330
  )
321
331
 
322
- # === Crontab Scheduling ===
323
- crontab: Optional[CrontabConfig] = Field(
332
+ # === Django-Q2 Task Scheduling ===
333
+ django_q2: Optional[DjangoQ2Config] = Field(
324
334
  default=None,
325
- description="Crontab scheduling configuration (django-crontab integration)",
335
+ description="Django-Q2 task scheduling and queue configuration",
326
336
  )
327
337
 
328
338
  # === Centrifugo Configuration ===
@@ -163,9 +163,9 @@ class InstalledAppsBuilder:
163
163
  # No external app needed - ReArq is embedded
164
164
  apps.append("django_cfg.apps.tasks")
165
165
 
166
- # Add django-crontab if enabled
167
- if hasattr(self.config, "crontab") and self.config.crontab and self.config.crontab.enabled:
168
- apps.append("django_crontab")
166
+ # Add django-q2 if enabled
167
+ if hasattr(self.config, "django_q2") and self.config.django_q2 and self.config.django_q2.enabled:
168
+ apps.append("django_q")
169
169
 
170
170
  # Add DRF Tailwind theme module (uses Tailwind via CDN)
171
171
  if self.config.enable_drf_tailwind:
@@ -58,13 +58,18 @@ class CacheSettingsGenerator:
58
58
 
59
59
  # Default cache - always provide one
60
60
  if self.config.cache_default:
61
+ # User explicitly configured cache_default
61
62
  caches["default"] = self.config.cache_default.to_django_config(
62
63
  self.config.env_mode,
63
64
  self.config.debug,
64
65
  "default"
65
66
  )
67
+ elif self.config.redis_url:
68
+ # Auto-create Redis cache from redis_url
69
+ logger.info(f"Auto-creating Redis cache from redis_url: {self.config.redis_url}")
70
+ caches["default"] = self._get_redis_cache_config()
66
71
  else:
67
- # Create default cache backend
72
+ # Fallback to default cache backend (LocMem/FileBased depending on env)
68
73
  caches["default"] = self._get_default_cache_config()
69
74
 
70
75
  # Sessions cache
@@ -88,9 +93,30 @@ class CacheSettingsGenerator:
88
93
 
89
94
  return settings
90
95
 
96
+ def _get_redis_cache_config(self) -> Dict[str, Any]:
97
+ """
98
+ Auto-create Redis cache from config.redis_url.
99
+
100
+ Returns:
101
+ Dictionary with Redis cache backend configuration
102
+ """
103
+ from ....models.infrastructure.cache import CacheConfig
104
+
105
+ redis_cache = CacheConfig(
106
+ redis_url=self.config.redis_url,
107
+ timeout=300, # 5 minutes default
108
+ max_connections=50,
109
+ key_prefix=self.config.project_name.lower().replace(" ", "_") if self.config.project_name else "django",
110
+ )
111
+ return redis_cache.to_django_config(
112
+ self.config.env_mode,
113
+ self.config.debug,
114
+ "default"
115
+ )
116
+
91
117
  def _get_default_cache_config(self) -> Dict[str, Any]:
92
118
  """
93
- Get default cache configuration.
119
+ Get default cache configuration (fallback when no redis_url).
94
120
 
95
121
  Returns:
96
122
  Dictionary with default cache backend configuration
@@ -6,11 +6,12 @@ Contains generators for third-party integrations and frameworks:
6
6
  - External services (Telegram, Unfold, Constance)
7
7
  - API frameworks (JWT, DRF, Spectacular, OpenAPI Client)
8
8
  - Background tasks (ReArq)
9
- - Crontab scheduling (django-crontab)
9
+ - Task scheduling (django-q2)
10
+ - Tailwind CSS configuration
10
11
  """
11
12
 
12
13
  from .api import APIFrameworksGenerator
13
- from .crontab import CrontabSettingsGenerator
14
+ from .django_q2 import DjangoQ2SettingsGenerator
14
15
  from .sessions import SessionSettingsGenerator
15
16
  from .tasks import TasksSettingsGenerator
16
17
  from .third_party import ThirdPartyIntegrationsGenerator
@@ -20,5 +21,5 @@ __all__ = [
20
21
  "ThirdPartyIntegrationsGenerator",
21
22
  "APIFrameworksGenerator",
22
23
  "TasksSettingsGenerator",
23
- "CrontabSettingsGenerator",
24
+ "DjangoQ2SettingsGenerator",
24
25
  ]