django-cfg 1.4.8__py3-none-any.whl → 1.4.10__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.
@@ -96,12 +96,16 @@ class APIAccessMiddleware(MiddlewareMixin):
96
96
  def process_request(self, request: HttpRequest) -> Optional[JsonResponse]:
97
97
  """
98
98
  Process incoming request for API access control.
99
-
99
+
100
100
  Returns JsonResponse if access should be denied, None to continue.
101
101
  """
102
102
  if not self.enabled:
103
103
  return None
104
-
104
+
105
+ # Check if this is a django-cfg internal endpoint check (bypass API key validation)
106
+ if request.META.get('HTTP_X_DJANGO_CFG_INTERNAL_CHECK') == 'true':
107
+ return None
108
+
105
109
  # Check if this path is protected (whitelist approach)
106
110
  if not self._is_protected_path(request.path):
107
111
  return None
@@ -56,6 +56,7 @@ class RateLimitingMiddleware(MiddlewareMixin):
56
56
  '/admin/',
57
57
  '/static/',
58
58
  '/media/',
59
+ '/schema/', # Exempt schema generation endpoints (Spectacular)
59
60
  ]
60
61
 
61
62
  except Exception as e:
@@ -74,7 +75,7 @@ class RateLimitingMiddleware(MiddlewareMixin):
74
75
  self.burst_allowance = 0.5
75
76
  self.window_size = 60
76
77
  self.window_precision = 10
77
- self.exempt_paths = ['/api/health/', '/cfg/', '/admin/']
78
+ self.exempt_paths = ['/api/health/', '/cfg/', '/admin/', '/schema/']
78
79
  self.cache_timeout = 300
79
80
 
80
81
  logger.info(f"Rate Limiting Middleware initialized", extra={
@@ -70,7 +70,11 @@ class UsageTrackingMiddleware(MiddlewareMixin):
70
70
  """
71
71
  if not self.enabled:
72
72
  return None
73
-
73
+
74
+ # Check if this is a django-cfg internal endpoint check (skip tracking)
75
+ if request.META.get('HTTP_X_DJANGO_CFG_INTERNAL_CHECK') == 'true':
76
+ return None
77
+
74
78
  # Check if we should track this request
75
79
  if not self._should_track_request(request):
76
80
  return None
@@ -319,7 +319,6 @@ class APIKeyManager(models.Manager):
319
319
  # Usage statistics
320
320
  usage_stats = queryset.aggregate(
321
321
  total_requests=models.Sum('total_requests'),
322
- avg_requests=models.Avg('total_requests'),
323
322
  max_requests=models.Max('total_requests')
324
323
  )
325
324
  stats.update(usage_stats)
@@ -196,7 +196,6 @@ class SubscriptionQuerySet(models.QuerySet):
196
196
  """Get usage statistics."""
197
197
  return self.aggregate(
198
198
  total_requests=models.Sum('total_requests'),
199
- avg_requests=models.Avg('total_requests'),
200
199
  max_requests=models.Max('total_requests'),
201
200
  active_users=models.Count('user', distinct=True)
202
201
  )
@@ -340,16 +340,16 @@ class BalanceService(BaseService):
340
340
  created_at__gte=since
341
341
  ).aggregate(
342
342
  total_transactions=models.Count('id'),
343
- total_volume=models.Sum('amount'),
343
+ total_volume=models.Sum('amount_usd'),
344
344
  deposits=models.Sum(
345
- 'amount',
345
+ 'amount_usd',
346
346
  filter=models.Q(transaction_type='deposit')
347
347
  ),
348
348
  withdrawals=models.Sum(
349
- 'amount',
349
+ 'amount_usd',
350
350
  filter=models.Q(transaction_type='withdrawal')
351
351
  ),
352
- avg_transaction=models.Avg('amount')
352
+ avg_transaction=models.Avg('amount_usd')
353
353
  )
354
354
 
355
355
  # Transaction type breakdown
@@ -357,7 +357,7 @@ class BalanceService(BaseService):
357
357
  created_at__gte=since
358
358
  ).values('transaction_type').annotate(
359
359
  count=models.Count('id'),
360
- volume=models.Sum('amount')
360
+ volume=models.Sum('amount_usd')
361
361
  ).order_by('-count')
362
362
 
363
363
  stats = {
@@ -473,8 +473,7 @@ class SubscriptionService(BaseService):
473
473
  created_at__gte=since
474
474
  ).aggregate(
475
475
  new_subscriptions=models.Count('id'),
476
- total_requests=models.Sum('total_requests'),
477
- avg_requests=models.Avg('total_requests')
476
+ total_requests=models.Sum('total_requests')
478
477
  )
479
478
 
480
479
  stats = {
@@ -10,6 +10,7 @@ from rest_framework.response import Response
10
10
  from django_filters.rest_framework import DjangoFilterBackend
11
11
  from django.contrib.auth import get_user_model
12
12
  from django.db import models
13
+ from django.utils import timezone
13
14
 
14
15
  from .base import PaymentBaseViewSet, NestedPaymentViewSet, ReadOnlyPaymentViewSet
15
16
  from ...models import UserBalance, Transaction
@@ -245,12 +246,12 @@ class TransactionViewSet(ReadOnlyPaymentViewSet):
245
246
  'total_transactions': type_transactions.count(),
246
247
  'total_amount': float(
247
248
  type_transactions.aggregate(
248
- total=models.Sum('amount')
249
+ total=models.Sum('amount_usd')
249
250
  )['total'] or 0
250
251
  ),
251
252
  'average_amount': float(
252
253
  type_transactions.aggregate(
253
- avg=models.Avg('amount')
254
+ avg=models.Avg('amount_usd')
254
255
  )['avg'] or 0
255
256
  ),
256
257
  }
@@ -344,14 +345,14 @@ class UserTransactionViewSet(NestedPaymentViewSet):
344
345
  summary = queryset.aggregate(
345
346
  total_transactions=models.Count('id'),
346
347
  total_credits=models.Sum(
347
- 'amount',
348
- filter=models.Q(amount__gt=0)
348
+ 'amount_usd',
349
+ filter=models.Q(amount_usd__gt=0)
349
350
  ),
350
351
  total_debits=models.Sum(
351
- 'amount',
352
- filter=models.Q(amount__lt=0)
352
+ 'amount_usd',
353
+ filter=models.Q(amount_usd__lt=0)
353
354
  ),
354
- net_amount=models.Sum('amount'),
355
+ net_amount=models.Sum('amount_usd'),
355
356
  )
356
357
 
357
358
  # Get type breakdown
@@ -82,10 +82,10 @@ class PaymentBaseViewSet(viewsets.ModelViewSet):
82
82
  return context
83
83
 
84
84
  @action(detail=False, methods=['get'])
85
- def stats(self, request):
85
+ def stats(self, request, **kwargs):
86
86
  """
87
87
  Get statistics for the current queryset.
88
-
88
+
89
89
  Returns counts, aggregates, and breakdowns.
90
90
  """
91
91
  try:
@@ -120,10 +120,10 @@ class PaymentBaseViewSet(viewsets.ModelViewSet):
120
120
  )
121
121
 
122
122
  @action(detail=False, methods=['get'])
123
- def health(self, request):
123
+ def health(self, request, **kwargs):
124
124
  """
125
125
  Health check for the ViewSet and related services.
126
-
126
+
127
127
  Returns service status and basic metrics.
128
128
  """
129
129
  try:
@@ -264,12 +264,16 @@ class NestedPaymentViewSet(PaymentBaseViewSet):
264
264
  def get_queryset(self):
265
265
  """Filter queryset by parent object from URL."""
266
266
  queryset = super().get_queryset()
267
-
267
+
268
268
  parent_id = self.kwargs.get(self.parent_lookup_field)
269
269
  if parent_id:
270
+ # Skip filtering for schema generation placeholders
271
+ if str(parent_id).lower() in ['test', 'string', 'example']:
272
+ return queryset.none()
273
+
270
274
  filter_kwargs = {self.parent_model_field + '_id': parent_id}
271
275
  queryset = queryset.filter(**filter_kwargs)
272
-
276
+
273
277
  return queryset
274
278
 
275
279
  def perform_create(self, serializer):
@@ -204,7 +204,7 @@ class NetworkViewSet(ReadOnlyPaymentViewSet):
204
204
 
205
205
  def get_queryset(self):
206
206
  """Optimize queryset with related objects."""
207
- return super().get_queryset().select_related('currency')
207
+ return super().get_queryset().select_related('native_currency')
208
208
 
209
209
  @action(detail=False, methods=['get'])
210
210
  def by_currency(self, request):
@@ -218,11 +218,11 @@ class NetworkViewSet(ReadOnlyPaymentViewSet):
218
218
 
219
219
  networks_by_currency = {}
220
220
  for network in queryset:
221
- currency_code = network.currency.code
222
-
221
+ currency_code = network.native_currency.code
222
+
223
223
  if currency_code not in networks_by_currency:
224
224
  networks_by_currency[currency_code] = {
225
- 'currency': CurrencyListSerializer(network.currency).data,
225
+ 'currency': CurrencyListSerializer(network.native_currency).data,
226
226
  'networks': []
227
227
  }
228
228
 
@@ -10,6 +10,8 @@ from rest_framework.response import Response
10
10
  from django_filters.rest_framework import DjangoFilterBackend
11
11
  from django.contrib.auth import get_user_model
12
12
  from django.shortcuts import get_object_or_404
13
+ from django.utils import timezone
14
+ from django.db import models
13
15
 
14
16
  from .base import PaymentBaseViewSet, NestedPaymentViewSet
15
17
  from ...models import UniversalPayment
@@ -371,7 +373,7 @@ class PaymentStatusView(generics.RetrieveAPIView):
371
373
  queryset = UniversalPayment.objects.all()
372
374
  serializer_class = PaymentSerializer
373
375
  permission_classes = [permissions.IsAuthenticated]
374
- lookup_field = 'id'
376
+ lookup_field = 'pk' # URL uses <uuid:pk>
375
377
 
376
378
  def get_object(self):
377
379
  """Get payment with permission check."""
@@ -344,7 +344,6 @@ class UserSubscriptionViewSet(NestedPaymentViewSet):
344
344
  filter=models.Q(expires_at__lt=timezone.now())
345
345
  ),
346
346
  total_requests=models.Sum('total_requests'),
347
- requests_used=models.Sum('requests_used'),
348
347
  )
349
348
 
350
349
  return Response({
@@ -352,8 +351,6 @@ class UserSubscriptionViewSet(NestedPaymentViewSet):
352
351
  'summary': {
353
352
  **summary,
354
353
  'total_requests': summary['total_requests'] or 0,
355
- 'requests_used': summary['requests_used'] or 0,
356
- 'requests_remaining': (summary['total_requests'] or 0) - (summary['requests_used'] or 0),
357
354
  },
358
355
  'generated_at': timezone.now().isoformat()
359
356
  })
@@ -430,7 +427,7 @@ class TariffViewSet(ReadOnlyPaymentViewSet):
430
427
 
431
428
  GET /api/tariffs/free/
432
429
  """
433
- free_tariffs = self.get_queryset().filter(monthly_price=0)
430
+ free_tariffs = self.get_queryset().filter(monthly_price_usd=0)
434
431
  serializer = self.get_serializer(free_tariffs, many=True)
435
432
 
436
433
  return Response({
@@ -447,7 +444,7 @@ class TariffViewSet(ReadOnlyPaymentViewSet):
447
444
 
448
445
  GET /api/tariffs/paid/
449
446
  """
450
- paid_tariffs = self.get_queryset().filter(monthly_price__gt=0)
447
+ paid_tariffs = self.get_queryset().filter(monthly_price_usd__gt=0)
451
448
  serializer = self.get_serializer(paid_tariffs, many=True)
452
449
 
453
450
  return Response({
@@ -123,14 +123,24 @@ class APIFrameworksGenerator:
123
123
  "description": getattr(self.config.revolution, "drf_description", "RESTful API"),
124
124
  "version": getattr(self.config.revolution, "drf_version", "1.0.0"),
125
125
  "schema_path_prefix": f"/{self.config.revolution.api_prefix}/",
126
- "enable_browsable_api": getattr(self.config.revolution, "drf_enable_browsable_api", False),
126
+ "enable_browsable_api": getattr(self.config.revolution, "drf_enable_browsable_api", True),
127
127
  "enable_throttling": getattr(self.config.revolution, "drf_enable_throttling", False),
128
+
129
+ # Django-CFG specific settings
130
+ "REST_FRAMEWORK_DEFAULT_PAGINATION_CLASS": "django_cfg.middleware.pagination.DefaultPagination",
131
+ "REST_FRAMEWORK_PAGE_SIZE": 100,
132
+ "REST_FRAMEWORK_DEFAULT_RENDERER_CLASSES": [
133
+ "rest_framework.renderers.JSONRenderer",
134
+ "django_cfg.modules.django_drf_theme.renderers.TailwindBrowsableAPIRenderer",
135
+ ],
128
136
  }
129
137
 
130
138
  # Create DRF + Spectacular config with Revolution's comprehensive settings
131
139
  drf_settings = create_drf_spectacular_config(**drf_kwargs)
132
140
 
133
141
  logger.info("🚀 Generated DRF + Spectacular settings using Revolution's create_drf_spectacular_config")
142
+ logger.info(" - Pagination: django_cfg.middleware.pagination.DefaultPagination")
143
+ logger.info(" - Renderer: TailwindBrowsableAPIRenderer")
134
144
 
135
145
  return drf_settings
136
146
 
@@ -205,9 +215,17 @@ class APIFrameworksGenerator:
205
215
  """
206
216
  Apply DRF settings extensions.
207
217
 
218
+ Note: This method should NOT overwrite existing REST_FRAMEWORK settings.
219
+ It should only add missing settings or extend existing ones.
220
+
208
221
  Returns:
209
222
  Dictionary with DRF settings
210
223
  """
224
+ # Don't override if Revolution already created full DRF config
225
+ if self.config.revolution:
226
+ logger.info("🔧 DRF settings already configured by Revolution, skipping django-cfg extensions")
227
+ return {}
228
+
211
229
  settings = {}
212
230
 
213
231
  if self.config.drf:
@@ -49,7 +49,8 @@ class Command(BaseCommand):
49
49
  # Show basic info
50
50
  self.show_environment_info()
51
51
  self.show_email_config()
52
-
52
+ self.show_drf_config()
53
+
53
54
  if options['verbose']:
54
55
  self.show_database_config()
55
56
  self.show_app_config()
@@ -122,6 +123,88 @@ class Command(BaseCommand):
122
123
  except Exception as e:
123
124
  self.stdout.write(self.style.ERROR(f" ❌ Django CFG Email Service error: {e}"))
124
125
 
126
+ def show_drf_config(self):
127
+ """Show DRF and Spectacular configuration."""
128
+ self.stdout.write(self.style.SUCCESS("\n🔌 DRF & Spectacular Configuration:"))
129
+
130
+ # Check REST_FRAMEWORK settings
131
+ rest_framework = getattr(settings, 'REST_FRAMEWORK', {})
132
+ if rest_framework:
133
+ self.stdout.write(" ✅ REST_FRAMEWORK configured")
134
+
135
+ # Show key DRF settings
136
+ drf_settings = {
137
+ 'DEFAULT_SCHEMA_CLASS': rest_framework.get('DEFAULT_SCHEMA_CLASS', 'Not set'),
138
+ 'DEFAULT_AUTHENTICATION_CLASSES': rest_framework.get('DEFAULT_AUTHENTICATION_CLASSES', []),
139
+ 'DEFAULT_PERMISSION_CLASSES': rest_framework.get('DEFAULT_PERMISSION_CLASSES', []),
140
+ 'DEFAULT_PAGINATION_CLASS': rest_framework.get('DEFAULT_PAGINATION_CLASS', 'Not set'),
141
+ 'PAGE_SIZE': rest_framework.get('PAGE_SIZE', 'Not set'),
142
+ }
143
+
144
+ for key, value in drf_settings.items():
145
+ icon = "✅" if value and value != 'Not set' else "❌"
146
+ if isinstance(value, list):
147
+ if value:
148
+ self.stdout.write(f" {icon} {key}:")
149
+ for item in value:
150
+ self.stdout.write(f" - {item}")
151
+ else:
152
+ self.stdout.write(f" {icon} {key}: []")
153
+ else:
154
+ self.stdout.write(f" {icon} {key}: {value}")
155
+ else:
156
+ self.stdout.write(" ❌ REST_FRAMEWORK not configured")
157
+
158
+ # Check SPECTACULAR_SETTINGS
159
+ spectacular = getattr(settings, 'SPECTACULAR_SETTINGS', {})
160
+ if spectacular:
161
+ self.stdout.write("\n ✅ SPECTACULAR_SETTINGS configured")
162
+
163
+ # Show key Spectacular settings
164
+ spectacular_settings = {
165
+ 'TITLE': spectacular.get('TITLE', 'Not set'),
166
+ 'VERSION': spectacular.get('VERSION', 'Not set'),
167
+ 'SCHEMA_PATH_PREFIX': spectacular.get('SCHEMA_PATH_PREFIX', 'Not set'),
168
+ 'SERVE_INCLUDE_SCHEMA': spectacular.get('SERVE_INCLUDE_SCHEMA', 'Not set'),
169
+ }
170
+
171
+ for key, value in spectacular_settings.items():
172
+ icon = "✅" if value != 'Not set' else "❌"
173
+ self.stdout.write(f" {icon} {key}: {value}")
174
+ else:
175
+ self.stdout.write("\n ❌ SPECTACULAR_SETTINGS not configured")
176
+
177
+ # Check SimpleJWT settings
178
+ simple_jwt = getattr(settings, 'SIMPLE_JWT', {})
179
+ if simple_jwt:
180
+ self.stdout.write("\n ✅ SIMPLE_JWT configured")
181
+
182
+ jwt_settings = {
183
+ 'ACCESS_TOKEN_LIFETIME': simple_jwt.get('ACCESS_TOKEN_LIFETIME', 'Not set'),
184
+ 'REFRESH_TOKEN_LIFETIME': simple_jwt.get('REFRESH_TOKEN_LIFETIME', 'Not set'),
185
+ 'ALGORITHM': simple_jwt.get('ALGORITHM', 'Not set'),
186
+ }
187
+
188
+ for key, value in jwt_settings.items():
189
+ icon = "✅" if value != 'Not set' else "❌"
190
+ self.stdout.write(f" {icon} {key}: {value}")
191
+ else:
192
+ self.stdout.write("\n ❌ SIMPLE_JWT not configured")
193
+
194
+ # Get django-cfg config
195
+ try:
196
+ from django_cfg.core.state import get_current_config
197
+ config = get_current_config()
198
+
199
+ if config:
200
+ self.stdout.write("\n 📋 Django-CFG Config:")
201
+ self.stdout.write(f" drf: {'✅ Configured' if config.drf else '❌ Not set'}")
202
+ self.stdout.write(f" spectacular: {'✅ Configured' if config.spectacular else '❌ Not set'}")
203
+ self.stdout.write(f" jwt: {'✅ Configured' if config.jwt else '❌ Not set'}")
204
+ self.stdout.write(f" revolution: {'✅ Configured' if config.revolution else '❌ Not set'}")
205
+ except Exception as e:
206
+ self.stdout.write(self.style.ERROR(f" ❌ Error getting django-cfg config: {e}"))
207
+
125
208
  def show_database_config(self):
126
209
  """Show database configuration."""
127
210
  self.stdout.write(self.style.SUCCESS("\n🗄️ Database Configuration:"))
@@ -117,6 +117,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
117
117
  description="Support tickets and messages API",
118
118
  public=False,
119
119
  auth_required=True,
120
+ group="cfg",
120
121
  # version="v1",
121
122
  )
122
123
 
@@ -129,6 +130,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
129
130
  description="User management, OTP, profiles, and activity tracking API",
130
131
  public=False,
131
132
  auth_required=True,
133
+ group="cfg",
132
134
  # version="v1",
133
135
  )
134
136
 
@@ -141,6 +143,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
141
143
  description="Email campaigns, subscriptions, and newsletter management API",
142
144
  public=False,
143
145
  auth_required=True,
146
+ group="cfg",
144
147
  # version="v1",
145
148
  )
146
149
 
@@ -153,6 +156,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
153
156
  description="Lead collection, contact forms, and CRM integration API",
154
157
  public=True, # Leads can be public for contact forms
155
158
  auth_required=False,
159
+ group="cfg",
156
160
  # version="v1",
157
161
  )
158
162
 
@@ -165,6 +169,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
165
169
  description="Knowledge base, AI chat, embeddings, and search API",
166
170
  public=False,
167
171
  auth_required=True,
172
+ group="cfg",
168
173
  # version="v1",
169
174
  )
170
175
 
@@ -177,6 +182,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
177
182
  description="Agent definitions, executions, workflows, and tools API",
178
183
  public=False,
179
184
  auth_required=True,
185
+ group="cfg",
180
186
  # version="v1",
181
187
  )
182
188
 
@@ -189,6 +195,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
189
195
  description="Tasks, workflows, and automation API",
190
196
  public=False,
191
197
  auth_required=True,
198
+ group="cfg",
192
199
  # version="v1",
193
200
  )
194
201
 
@@ -201,6 +208,7 @@ class ExtendedRevolutionConfig(BaseDjangoRevolutionConfig):
201
208
  description="Payments, subscriptions, and billing API",
202
209
  public=False,
203
210
  auth_required=True,
211
+ group="cfg",
204
212
  # version="v1",
205
213
  )
206
214
 
@@ -60,7 +60,7 @@ class DashboardManager(BaseCfgModule):
60
60
  items=[
61
61
  NavigationItem(title="Overview", icon=Icons.DASHBOARD, link="/admin/"),
62
62
  NavigationItem(title="Settings", icon=Icons.SETTINGS, link="/admin/constance/config/"),
63
- NavigationItem(title="Health Check", icon=Icons.HEALTH_AND_SAFETY, link="/cfg/health/"),
63
+ NavigationItem(title="Health Check", icon=Icons.HEALTH_AND_SAFETY, link="/cfg/health/drf/"),
64
64
  NavigationItem(title="Endpoints Status", icon=Icons.API, link="/cfg/endpoints/drf/"),
65
65
  ]
66
66
  ),
django_cfg/pyproject.toml CHANGED
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "django-cfg"
7
- version = "1.4.8"
7
+ version = "1.4.10"
8
8
  description = "Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django."
9
9
  readme = "README.md"
10
10
  keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "ai-agents", "enterprise-django", "django-settings", "type-safe-config",]
11
11
  classifiers = [ "Development Status :: 4 - Beta", "Framework :: Django", "Framework :: Django :: 5.2", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Systems Administration", "Typing :: Typed",]
12
12
  requires-python = ">=3.12,<4.0"
13
- dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "pydantic-yaml>=1.6.0,<2.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "djangorestframework>=3.16.0,<4.0", "djangorestframework-simplejwt>=5.5.0,<6.0", "djangorestframework-simplejwt[token-blacklist]>=5.5.0,<6.0", "drf-nested-routers>=0.94.0,<1.0", "django-filter>=25.0,<26.0", "django-ratelimit>=4.1.0,<5.0.0", "drf-spectacular>=0.28.0,<1.0", "drf-spectacular-sidecar>=2025.8.0,<2026.0", "django-json-widget>=2.0.0,<3.0", "django-import-export>=4.3.0,<5.0", "django-extensions>=4.1.0,<5.0", "django-constance>=4.3.0,<5.0", "django-unfold>=0.64.0,<1.0", "django-redis>=6.0.0,<7.0", "redis>=6.4.0,<7.0", "hiredis>=2.0.0,<4.0", "dramatiq[redis]>=1.18.0,<2.0", "django-dramatiq>=0.14.0,<1.0", "pyTelegramBotAPI>=4.28.0,<5.0", "coolname>=2.2.0,<3.0", "django-admin-rangefilter>=0.13.0,<1.0", "python-json-logger>=3.3.0,<4.0", "requests>=2.32.0,<3.0", "tiktoken>=0.11.0,<1.0", "openai>=1.107.0,<2.0", "twilio>=9.8.0,<10.0", "sendgrid>=6.12.0,<7.0", "beautifulsoup4>=4.13.0,<5.0", "lxml>=6.0.0,<7.0", "pgvector>=0.4.0,<1.0", "pydantic-ai>=1.0.10,<2.0", "django-revolution>=1.0.44,<2.0", "tenacity>=9.1.2,<10.0.0", "mypy (>=1.18.2,<2.0.0)", "django-tailwind[reload] (>=4.2.0,<5.0.0)",]
13
+ dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "pydantic-yaml>=1.6.0,<2.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "djangorestframework>=3.16.0,<4.0", "djangorestframework-simplejwt>=5.5.0,<6.0", "djangorestframework-simplejwt[token-blacklist]>=5.5.0,<6.0", "drf-nested-routers>=0.94.0,<1.0", "django-filter>=25.0,<26.0", "django-ratelimit>=4.1.0,<5.0.0", "drf-spectacular>=0.28.0,<1.0", "drf-spectacular-sidecar>=2025.8.0,<2026.0", "django-json-widget>=2.0.0,<3.0", "django-import-export>=4.3.0,<5.0", "django-extensions>=4.1.0,<5.0", "django-constance>=4.3.0,<5.0", "django-unfold>=0.64.0,<1.0", "django-redis>=6.0.0,<7.0", "redis>=6.4.0,<7.0", "hiredis>=2.0.0,<4.0", "dramatiq[redis]>=1.18.0,<2.0", "django-dramatiq>=0.14.0,<1.0", "pyTelegramBotAPI>=4.28.0,<5.0", "coolname>=2.2.0,<3.0", "django-admin-rangefilter>=0.13.0,<1.0", "python-json-logger>=3.3.0,<4.0", "requests>=2.32.0,<3.0", "tiktoken>=0.11.0,<1.0", "openai>=1.107.0,<2.0", "twilio>=9.8.0,<10.0", "sendgrid>=6.12.0,<7.0", "beautifulsoup4>=4.13.0,<5.0", "lxml>=6.0.0,<7.0", "pgvector>=0.4.0,<1.0", "pydantic-ai>=1.0.10,<2.0", "django-revolution>=1.0.46", "tenacity>=9.1.2,<10.0.0", "mypy (>=1.18.2,<2.0.0)", "django-tailwind[reload] (>=4.2.0,<5.0.0)",]
14
14
  [[project.authors]]
15
15
  name = "Django-CFG Team"
16
16
  email = "info@djangocfg.com"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.4.8
3
+ Version: 1.4.10
4
4
  Summary: Django AI framework with built-in agents, type-safe Pydantic v2 configuration, and 8 enterprise apps. Replace settings.py, validate at startup, 90% less code. Production-ready AI workflows for Django.
5
5
  Project-URL: Homepage, https://djangocfg.com
6
6
  Project-URL: Documentation, https://djangocfg.com
@@ -45,7 +45,7 @@ Requires-Dist: django-import-export<5.0,>=4.3.0
45
45
  Requires-Dist: django-json-widget<3.0,>=2.0.0
46
46
  Requires-Dist: django-ratelimit<5.0.0,>=4.1.0
47
47
  Requires-Dist: django-redis<7.0,>=6.0.0
48
- Requires-Dist: django-revolution<2.0,>=1.0.44
48
+ Requires-Dist: django-revolution>=1.0.46
49
49
  Requires-Dist: django-tailwind[reload]<5.0.0,>=4.2.0
50
50
  Requires-Dist: django-unfold<1.0,>=0.64.0
51
51
  Requires-Dist: djangorestframework-simplejwt<6.0,>=5.5.0
@@ -357,9 +357,9 @@ django_cfg/apps/payments/management/commands/manage_providers.py,sha256=wtN4wttl
357
357
  django_cfg/apps/payments/management/commands/process_pending_payments.py,sha256=hh49miYeK4Zbxlp8BXEzgpuiee4lIepLk5leSNBiKh4,13309
358
358
  django_cfg/apps/payments/management/commands/test_providers.py,sha256=IvvJhTNw6KQm1EeWYTUMew0ZHzgUGWpG07JOhrpJEP0,18476
359
359
  django_cfg/apps/payments/middleware/__init__.py,sha256=eL5TmlCKmpW53Ift5rtwS8ss1wUqp4j2gzjGhcAQUQY,380
360
- django_cfg/apps/payments/middleware/api_access.py,sha256=lWX9A1UpIwPNC5320QcSVhHU_mg-LxzKaYG1bNjvN-I,16713
361
- django_cfg/apps/payments/middleware/rate_limiting.py,sha256=nbObLQwIssxsVwovG6S_SiEpQcYmJIyAmA4tUtIt2cg,15163
362
- django_cfg/apps/payments/middleware/usage_tracking.py,sha256=dY7n6lZFUo-5a49VzJnZAT6UmbaU7kHei9Xu02KXACw,11815
360
+ django_cfg/apps/payments/middleware/api_access.py,sha256=_j9VnyMtIiTSgNOeprSgRN10VOmOyDJdjot63JpWoJg,16889
361
+ django_cfg/apps/payments/middleware/rate_limiting.py,sha256=49VBgxD5Hed9dD56-oYtQj-KXFD8_mQUgfdrsPWsf0I,15255
362
+ django_cfg/apps/payments/middleware/usage_tracking.py,sha256=uxY1Sb0p-ycXDV6ACGXvNd12GdLBtAy26mB48z2Svdc,11987
363
363
  django_cfg/apps/payments/migrations/0001_initial.py,sha256=uLkgbaSvdPjoTHZ3pVB7aEgVPq_hAyQRWXFqC9-2oGc,48359
364
364
  django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py,sha256=MmxPMKYOzafTeVRj1cOOzVEDszKa_VYyqkUD8z7jZEk,1512
365
365
  django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py,sha256=EEs1EzIfpG-tfgx220KZsF8lnn83iwW4blRATJO2vi8,659
@@ -373,11 +373,11 @@ django_cfg/apps/payments/models/payments.py,sha256=8uAMreO1tqLZuinFi6fE3fHCaxP5S
373
373
  django_cfg/apps/payments/models/subscriptions.py,sha256=o3C3CIupcz3lyvg_hszvHQaiWR7RJQ-pP1eebIDJfBE,10332
374
374
  django_cfg/apps/payments/models/tariffs.py,sha256=b2iDC7hBdZR8TX8aEskM5nTEa5_f0H6-j6wZdcbHdyk,6471
375
375
  django_cfg/apps/payments/models/managers/__init__.py,sha256=56kdXtRJOLHhtnY4arYi15fEAmWWrWJP0F8kn8okpzU,1090
376
- django_cfg/apps/payments/models/managers/api_key_managers.py,sha256=08B_SeW5bAKiIzTEW9hh4vvK9-iunEePTv3gEa_HLko,10548
376
+ django_cfg/apps/payments/models/managers/api_key_managers.py,sha256=u-KJkzIKuOpT3eTDFwbZkBpZ3d0_NrSDxpG8aZSYpNA,10493
377
377
  django_cfg/apps/payments/models/managers/balance_managers.py,sha256=exsd4jJEeKlsF3Q566zrXb-8my2NmxR3b-3Xkc9JTLg,20299
378
378
  django_cfg/apps/payments/models/managers/currency_managers.py,sha256=y-VwYGpnE8zlaKkgx7PDfHZ9VQACTZyhPTUSN7DsCws,16265
379
379
  django_cfg/apps/payments/models/managers/payment_managers.py,sha256=hqyzSvYGuixSmscsrkThn6na2zBlj1vBeRWx7b4dpJw,22525
380
- django_cfg/apps/payments/models/managers/subscription_managers.py,sha256=j8CG5FGZ2Uua6fvlPlk6QOq1Rq7c6Az94vtV7XFmtBQ,21689
380
+ django_cfg/apps/payments/models/managers/subscription_managers.py,sha256=2xDYk17CpK9KYdThUtqxFIAn1fq4SdxHriRIkfJizTE,21634
381
381
  django_cfg/apps/payments/services/__init__.py,sha256=QUFVfTwliUvQWtaw0JqDss_LDamgNZwaej8fzL6Qzco,6147
382
382
  django_cfg/apps/payments/services/cache/__init__.py,sha256=eUUtnNU1gPyJOAHaUeaDD5WOnPb0aSI7klvTGbgccOE,354
383
383
  django_cfg/apps/payments/services/cache_service/__init__.py,sha256=nPNc6N2OZtnt7Mr104wQPrAS0HrCqqgVK6aY185AQao,4292
@@ -387,11 +387,11 @@ django_cfg/apps/payments/services/cache_service/keys.py,sha256=U37Dwkboxn0E_B5Mp
387
387
  django_cfg/apps/payments/services/cache_service/rate_limit_cache.py,sha256=MjFn5q23WjupNI2wZ9KpUJZR5TxX1zkYp6Cu1okZIfQ,1785
388
388
  django_cfg/apps/payments/services/cache_service/simple_cache.py,sha256=_3PfGAsKzK0crgAxE2T_eHEDt2PqcbzZYwRinZGFqSE,3406
389
389
  django_cfg/apps/payments/services/core/__init__.py,sha256=CY2M4ID3rqcdpbokQSdO_fxtdCfHjsGgBsTznyGPw3k,526
390
- django_cfg/apps/payments/services/core/balance_service.py,sha256=WjXYfTGlSSiX047IZSoeHvagSnID9qpSrjVueQUabIA,18636
390
+ django_cfg/apps/payments/services/core/balance_service.py,sha256=cCtk2Mu48L6nWFzCAff9eaqz-ti3NXTyEX4ARNKz6L4,18656
391
391
  django_cfg/apps/payments/services/core/base.py,sha256=KiecVjsjsMGdFI-aPr0nTQnu2Tih_oJG_nhBTKAWjlg,5442
392
392
  django_cfg/apps/payments/services/core/currency_service.py,sha256=krA89MU7asLSB_1C-3330XPfXx9uOLZphPYqQib_lkw,18508
393
393
  django_cfg/apps/payments/services/core/payment_service.py,sha256=ZJQ-8bmbfA_qhudMEo4-2HOLzUJqtwaYhWLwY3b4Bgo,6469
394
- django_cfg/apps/payments/services/core/subscription_service.py,sha256=1kfxaW-BybIwQkbEpizxNJG_Egz6aF1qCVF2mX4v7Q4,21125
394
+ django_cfg/apps/payments/services/core/subscription_service.py,sha256=LOWex6OzzUte322giH5RrAomcYYWCXq23nPkWK0wNfI,21066
395
395
  django_cfg/apps/payments/services/core/webhook_service.py,sha256=5Ly44QDUQJYm7V5xkOoKaPzobwf5MkLjFI6uamrpTY0,16222
396
396
  django_cfg/apps/payments/services/core/currency/__init__.py,sha256=NZk-PHnlTAEE1IvxxNZxXKQj-gy_uAUswrKvSZ8I0TM,275
397
397
  django_cfg/apps/payments/services/core/currency/currency_converter.py,sha256=yFs8wim52mCYLvJRU6XLiRCOYowkpggoZ-BWDXTJifc,1684
@@ -460,11 +460,11 @@ django_cfg/apps/payments/templatetags/__init__.py,sha256=K8PcAAZu-q6LgCbrH29BSxw
460
460
  django_cfg/apps/payments/templatetags/payment_tags.py,sha256=ooO9a5E6kWyaGoLmx2fam4dHnzb9_drhFYmgPT9em1g,11910
461
461
  django_cfg/apps/payments/views/api/__init__.py,sha256=gKd8dE4i-ebCxjquFHI6UaW6KKgV0RE3RlH22c8O4pU,2005
462
462
  django_cfg/apps/payments/views/api/api_keys.py,sha256=nzlRdkMjDY3-hChbSnAo3MFDqd5lulOcKgeajdQr7KQ,13854
463
- django_cfg/apps/payments/views/api/balances.py,sha256=1x8wyGZrM_dyXfkYMtB8YkLnLMFKv4Vv_mauXP-nI5Y,13090
464
- django_cfg/apps/payments/views/api/base.py,sha256=iUsI3L4eolTOqVZ-ZP8AgZp58_EsTkhZUcVcCxZuIis,10389
465
- django_cfg/apps/payments/views/api/currencies.py,sha256=B1Wi9MCoSgyFISrQLiqMHXtVwxOHbTLZ3X6BMEIUW3Y,13866
466
- django_cfg/apps/payments/views/api/payments.py,sha256=5bLdp_FfpfGtoNS5L4FHFJZ-mRfUvBU672fPoZH7Pek,14625
467
- django_cfg/apps/payments/views/api/subscriptions.py,sha256=y0JyLdqypPl0qOAXoFsm2FhcPtlAjeSBQUa8DsiDt3g,16643
463
+ django_cfg/apps/payments/views/api/balances.py,sha256=7V5UCFWQRYO0ZwWN4N1tDvayt9mip4tqhlu79Rk1OQ8,13152
464
+ django_cfg/apps/payments/views/api/base.py,sha256=Q5AtoFq9R8EkVsqew8mZiNCzkLn4EsogNvo4fqTh0Hs,10553
465
+ django_cfg/apps/payments/views/api/currencies.py,sha256=A5Tuy9vwYQoCPS1p4GswQ2xwUgbxHwuB3uiq7NP-SRY,13871
466
+ django_cfg/apps/payments/views/api/payments.py,sha256=s94lkQYv3SrcUG4BQJekxb3-03ULO3VKoSehCP94U2s,14710
467
+ django_cfg/apps/payments/views/api/subscriptions.py,sha256=q-QBRrkOc4GBe0iCb1ZJMUnm8roX15-ra0eBBK1GRzU,16414
468
468
  django_cfg/apps/payments/views/api/webhooks.py,sha256=8jCPDYRtg2Hf-JuaaDNt7sOexKjJbxAswIWt8FRgtEE,17289
469
469
  django_cfg/apps/payments/views/overview/__init__.py,sha256=2SbWIJzExZFsOiBWnaIMURUhXnJDJ8mBcueuKFkBhJw,987
470
470
  django_cfg/apps/payments/views/overview/serializers.py,sha256=uxDlzMIrn7hhS0aNExuR2YHZ5Tl1LgeFBfwZwLEu4lo,9654
@@ -571,7 +571,7 @@ django_cfg/core/generation/data_generators/__init__.py,sha256=t8YepmMhMysy95tRYG
571
571
  django_cfg/core/generation/data_generators/cache.py,sha256=IEwyVBJ-QJgOm5C13z-974YzV73aZO9MCresGweE7PM,3840
572
572
  django_cfg/core/generation/data_generators/database.py,sha256=ixJOB5e-e3N06F2QNQ1NJV0KLy26RxyvoKaRI1x5FIE,3481
573
573
  django_cfg/core/generation/integration_generators/__init__.py,sha256=oarpk8gVezvMJWVjC2wwV4ILLkB3z9Oa_oAhdT3Iwu0,595
574
- django_cfg/core/generation/integration_generators/api.py,sha256=JcoJxhedwtOqTh_4x_pXuPIXTLSFLTxuNAUvDtBT8tg,8229
574
+ django_cfg/core/generation/integration_generators/api.py,sha256=Xi6mba7dqwkopMfT4BdpEW0RWuewNG_gpNuU83Wmp9E,9233
575
575
  django_cfg/core/generation/integration_generators/sessions.py,sha256=W2KJetdF-lgfo54fouLCM6a_iTWGpXZrj1xI2CrtZ7g,1644
576
576
  django_cfg/core/generation/integration_generators/tailwind.py,sha256=nEcaBu-uNJ_O2Y2lHCAc1pG7m8LthnrFFHPxDJqSh3k,1208
577
577
  django_cfg/core/generation/integration_generators/tasks.py,sha256=Wlh9f1dpn_05k7dZxGEm2TegGK-TuP4zVwbCMg5ocM4,2514
@@ -618,7 +618,7 @@ django_cfg/dashboard/sections/system.py,sha256=IP4SJMPOL-gqDancE_g46ZbmlveYDvljp
618
618
  django_cfg/management/__init__.py,sha256=NrLAhiS59hqjy-bipOC1abNuRiNm5BpKXmjN05VzKbM,28
619
619
  django_cfg/management/commands/__init__.py,sha256=GqJDbjiwRa9Y9uvf695EZ-Y42vQIMHp5YkjhMoeAM9I,417
620
620
  django_cfg/management/commands/check_endpoints.py,sha256=5I-8cbVD6aA9g6_j_JI76NoZCSwZTy21B7hxNKbR4OI,6275
621
- django_cfg/management/commands/check_settings.py,sha256=YyYKBMT3XaILD6PFKQGPALNnDv9rNtnF2U8RlkCoYiA,11770
621
+ django_cfg/management/commands/check_settings.py,sha256=lh5G4FmwGRpmQG20OikL6aqf-BgEb0I8wWbNnco-QKw,15771
622
622
  django_cfg/management/commands/clear_constance.py,sha256=tX6YUeJsmxJxXLQRDX3VUkUP9t6B1gAyVrBl4krQ6K0,8263
623
623
  django_cfg/management/commands/create_token.py,sha256=NspV-9j-T0dDjqY6ccJeuVqTB3v4ne1Jc43G2tKuioI,12015
624
624
  django_cfg/management/commands/generate.py,sha256=tvBahlXOu63H7d-7Ree1WuR_6saebUrcbk5DuqDdMpc,4358
@@ -661,7 +661,7 @@ django_cfg/models/base/module.py,sha256=P6YowmE-VOqp_L25Ijxj2hjjNhB9xtlm8G35DHWq
661
661
  django_cfg/models/django/__init__.py,sha256=i0GblTO8rF1J_WjT55WjhdbWN10l0UeR6mSFqdnOfak,347
662
662
  django_cfg/models/django/constance.py,sha256=IVklMTtusxWnWaU3PSatGLQfg5qY_Y89MZQjsJFwbCk,9175
663
663
  django_cfg/models/django/environment.py,sha256=jdg6DXQrnuLSdfZNV4KoFlkiPl1n2jOicPU8NFzyB5U,9439
664
- django_cfg/models/django/revolution.py,sha256=H4FqK24I3JOCsi5-FDPwMgRhRJxlYTMPMEOC53Ixj_U,8741
664
+ django_cfg/models/django/revolution.py,sha256=NONFa3U-w2HSMKumEh0BOD5HVI3ghiMvDbISpWC_wr4,9005
665
665
  django_cfg/models/infrastructure/__init__.py,sha256=If0XLyDNaR_F6rOhDJBCT5RmkOOoNcY61L70pQvaO1s,369
666
666
  django_cfg/models/infrastructure/cache.py,sha256=N6LWinyokWcmuJmInn0q48TQq0Je-xXMJdZ0DbelGPU,12175
667
667
  django_cfg/models/infrastructure/logging.py,sha256=6nQNQPUKEL7TAYX1KcYgsqHBKnHWoUnqhR54bxcr40s,10637
@@ -856,7 +856,7 @@ django_cfg/modules/django_twilio/templates/guide.md,sha256=nZfwx-sgWyK5NApm93zOe
856
856
  django_cfg/modules/django_twilio/templates/sendgrid_otp_email.html,sha256=sXR6_D9hmOFfk9CrfPizpLddVhkRirBWpZd_ioEsxVk,6671
857
857
  django_cfg/modules/django_twilio/templates/sendgrid_test_data.json,sha256=fh1VyuSiDELHsS_CIz9gp7tlsMAEjaDOoqbAPSZ3yyo,339
858
858
  django_cfg/modules/django_unfold/__init__.py,sha256=Z91x1iGmkzlRbEb2L9OCFmYDKNAV9C4G3i15j5S0esc,1898
859
- django_cfg/modules/django_unfold/dashboard.py,sha256=WXz7TUQp2mchdAcPBWn7HaFWwkHzEUomckKNZK224mY,18108
859
+ django_cfg/modules/django_unfold/dashboard.py,sha256=qzbk4LblELnQYE_HLVrf25-XHrksoaZAMbfWC59qLE8,18112
860
860
  django_cfg/modules/django_unfold/models.py,sha256=bY6QSSaH_-r9vOTkSQjxeIkl5RaED7XkxXkT8-W5stk,4014
861
861
  django_cfg/modules/django_unfold/system_monitor.py,sha256=cznZqldRJqiSLSJbs4U7R2rX8ClzoIpqdfXdXqI2iQw,6955
862
862
  django_cfg/modules/django_unfold/tailwind.py,sha256=X9o1K3QL0VwUISgJ26sLb6zkdK-00qiDuekqTw-fydc,10846
@@ -950,9 +950,9 @@ django_cfg/utils/version_check.py,sha256=jI4v3YMdQriUEeb_TvRl511sDghy6I75iKRDUaN
950
950
  django_cfg/CHANGELOG.md,sha256=jtT3EprqEJkqSUh7IraP73vQ8PmKUMdRtznQsEnqDZk,2052
951
951
  django_cfg/CONTRIBUTING.md,sha256=DU2kyQ6PU0Z24ob7O_OqKWEYHcZmJDgzw-lQCmu6uBg,3041
952
952
  django_cfg/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
953
- django_cfg/pyproject.toml,sha256=uWYBJ80rrhJ9oyJnQboOMe-WSoTd8D1Es1AbNCaY3Gw,8329
954
- django_cfg-1.4.8.dist-info/METADATA,sha256=gW5wIlTOK9GnPUWX8PVC5SI9kdii5DXizX4HReJwI4o,22542
955
- django_cfg-1.4.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
956
- django_cfg-1.4.8.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
957
- django_cfg-1.4.8.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
958
- django_cfg-1.4.8.dist-info/RECORD,,
953
+ django_cfg/pyproject.toml,sha256=1ESG8akuC9NoeAKzjod1amQLwukZTA589WlVQYcOQV4,8325
954
+ django_cfg-1.4.10.dist-info/METADATA,sha256=Q6efBHctBNjYMMNf60dYw5ZG5s1TWYkeb7V0xRT_lLU,22538
955
+ django_cfg-1.4.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
956
+ django_cfg-1.4.10.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
957
+ django_cfg-1.4.10.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
958
+ django_cfg-1.4.10.dist-info/RECORD,,