django-cfg 1.1.71__py3-none-any.whl → 1.1.73__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
django_cfg/__init__.py CHANGED
@@ -38,7 +38,7 @@ default_app_config = "django_cfg.apps.DjangoCfgConfig"
38
38
  from typing import TYPE_CHECKING
39
39
 
40
40
  # Version information
41
- __version__ = "1.1.71"
41
+ __version__ = "1.1.73"
42
42
  __author__ = "Unrealos Team"
43
43
  __email__ = "info@unrealos.com"
44
44
  __license__ = "MIT"
django_cfg/core/config.py CHANGED
@@ -100,7 +100,7 @@ class DjangoConfig(BaseModel):
100
100
 
101
101
  model_config = {
102
102
  "validate_assignment": True,
103
- "extra": "allow", # Allow additional fields for extensibility
103
+ "extra": "forbid", # Forbid additional fields for strict typing
104
104
  "env_prefix": "DJANGO_",
105
105
  "populate_by_name": True,
106
106
  "validate_default": True,
@@ -222,6 +222,11 @@ class DjangoConfig(BaseModel):
222
222
  default=None,
223
223
  description="Force SSL redirect on/off (None = auto based on domains and environment)",
224
224
  )
225
+
226
+ cors_allow_headers: Optional[List[str]] = Field(
227
+ default=None,
228
+ description="Custom CORS allowed headers (None = use smart defaults including X-API-Key)",
229
+ )
225
230
 
226
231
  # === Services Configuration ===
227
232
  email: Optional[EmailConfig] = Field(
@@ -143,13 +143,16 @@ class Command(BaseCommand):
143
143
  # Migrate each app
144
144
  for app in apps:
145
145
  try:
146
+ # Convert full module path to app_label if needed
147
+ app_label = self.get_app_label_from_path(app)
148
+
146
149
  # Skip apps without migrations
147
- if not self.app_has_migrations(app):
148
- # self.stdout.write(f" ⚠️ Skipping {app} - no migrations")
150
+ if not self.app_has_migrations(app_label):
151
+ # self.stdout.write(f" ⚠️ Skipping {app_label} - no migrations")
149
152
  continue
150
153
 
151
- self.stdout.write(f" 📦 Migrating {app}...")
152
- call_command("migrate", app, database=db_name, verbosity=1)
154
+ self.stdout.write(f" 📦 Migrating {app_label}...")
155
+ call_command("migrate", app_label, database=db_name, verbosity=1)
153
156
  except Exception as e:
154
157
  self.stdout.write(self.style.WARNING(f" ⚠️ Warning migrating {app}: {e}"))
155
158
 
@@ -185,9 +188,11 @@ class Command(BaseCommand):
185
188
  for db_name in databases:
186
189
  apps = self.get_apps_for_database(db_name)
187
190
  if app_name in apps:
188
- self.stdout.write(f" 📊 Migrating {app_name} on {db_name}...")
191
+ # Convert full module path to app_label if needed
192
+ app_label = self.get_app_label_from_path(app_name)
193
+ self.stdout.write(f" 📊 Migrating {app_label} on {db_name}...")
189
194
  try:
190
- call_command("migrate", app_name, database=db_name, verbosity=1)
195
+ call_command("migrate", app_label, database=db_name, verbosity=1)
191
196
  except Exception as e:
192
197
  self.stdout.write(self.style.WARNING(f" ⚠️ Warning: {e}"))
193
198
 
@@ -285,7 +290,10 @@ class Command(BaseCommand):
285
290
  # Collect apps from all non-default databases
286
291
  for other_db_name, other_db_config in config.databases.items():
287
292
  if other_db_name != "default" and hasattr(other_db_config, 'apps'):
288
- apps_in_other_dbs.update(other_db_config.apps)
293
+ # Convert full paths to app_labels for comparison
294
+ for app_path in other_db_config.apps:
295
+ app_label = self.get_app_label_from_path(app_path)
296
+ apps_in_other_dbs.add(app_label)
289
297
 
290
298
  return [app for app in all_apps if app not in apps_in_other_dbs]
291
299
 
@@ -424,3 +432,41 @@ class Command(BaseCommand):
424
432
  except Exception:
425
433
  # Silently return False for apps that don't exist or have issues
426
434
  return False
435
+
436
+ def get_app_label_from_path(self, app_path: str) -> str:
437
+ """
438
+ Convert full module path to Django app_label.
439
+
440
+ Args:
441
+ app_path: Full module path (e.g., 'apps.vehicles_data') or app_label (e.g., 'vehicles_data')
442
+
443
+ Returns:
444
+ Django app_label that can be used with migrate command
445
+
446
+ Examples:
447
+ 'apps.vehicles_data' -> 'vehicles_data'
448
+ 'vehicles_data' -> 'vehicles_data'
449
+ 'myproject.apps.blog' -> 'blog'
450
+ """
451
+ try:
452
+ # Try to get app config by full path first
453
+ try:
454
+ app_config = apps.get_app_config(app_path)
455
+ return app_config.label
456
+ except LookupError:
457
+ pass
458
+
459
+ # Fallback: extract last part of the path as potential app_label
460
+ potential_label = app_path.split('.')[-1]
461
+ try:
462
+ app_config = apps.get_app_config(potential_label)
463
+ return app_config.label
464
+ except LookupError:
465
+ pass
466
+
467
+ # If all fails, return original path
468
+ return app_path
469
+
470
+ except Exception:
471
+ # Fallback to original path
472
+ return app_path
@@ -194,9 +194,23 @@ class SmartDefaults:
194
194
  settings['CORS_ALLOW_ALL_ORIGINS'] = True
195
195
  settings['CORS_ALLOW_CREDENTIALS'] = True
196
196
 
197
- # Add custom headers if provided
197
+ # Add CORS headers (custom or smart defaults)
198
198
  if cors_allow_headers:
199
199
  settings['CORS_ALLOW_HEADERS'] = cors_allow_headers
200
+ else:
201
+ # Smart defaults including X-API-Key
202
+ settings['CORS_ALLOW_HEADERS'] = [
203
+ "accept",
204
+ "accept-encoding",
205
+ "authorization",
206
+ "content-type",
207
+ "dnt",
208
+ "origin",
209
+ "user-agent",
210
+ "x-csrftoken",
211
+ "x-requested-with",
212
+ "x-api-key", # Add X-API-Key by default
213
+ ]
200
214
 
201
215
  # For development, add ALL domains to CSRF trusted origins
202
216
  # This allows testing with production domains in dev environment
@@ -247,9 +261,23 @@ class SmartDefaults:
247
261
  settings['CORS_ALLOWED_ORIGINS'] = allowed_origins
248
262
  settings['CORS_ALLOW_CREDENTIALS'] = True
249
263
 
250
- # Add custom headers if provided
264
+ # Add CORS headers (custom or smart defaults)
251
265
  if cors_allow_headers:
252
266
  settings['CORS_ALLOW_HEADERS'] = cors_allow_headers
267
+ else:
268
+ # Smart defaults including X-API-Key
269
+ settings['CORS_ALLOW_HEADERS'] = [
270
+ "accept",
271
+ "accept-encoding",
272
+ "authorization",
273
+ "content-type",
274
+ "dnt",
275
+ "origin",
276
+ "user-agent",
277
+ "x-csrftoken",
278
+ "x-requested-with",
279
+ "x-api-key", # Add X-API-Key by default
280
+ ]
253
281
 
254
282
  # Set CSRF trusted origins for HTTPS domains
255
283
  if csrf_trusted_origins:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.1.71
3
+ Version: 1.1.73
4
4
  Summary: 🚀 Production-ready Django configuration framework with type-safe settings, smart automation, and modern developer experience
5
5
  Project-URL: Homepage, https://github.com/markolofsen/django-cfg
6
6
  Project-URL: Documentation, https://django-cfg.readthedocs.io
@@ -1,5 +1,5 @@
1
1
  django_cfg/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- django_cfg/__init__.py,sha256=mPW2h89gQoeiTI09ugERfUgEdcrPiGjw-yZSi5ACHrU,14288
2
+ django_cfg/__init__.py,sha256=uM3TJPCp4dy3Ql9MguqYKJzHp5k02lHHMjAIjDWaxr4,14288
3
3
  django_cfg/apps.py,sha256=k84brkeXJI7EgKZLEpTkM9YFZofKI4PzhFOn1cl9Msc,1656
4
4
  django_cfg/exceptions.py,sha256=RTQEoU3PfR8lqqNNv5ayd_HY2yJLs3eioqUy8VM6AG4,10378
5
5
  django_cfg/integration.py,sha256=jUO-uZXLmBXy9iugqgsl_xnYA_xoH3LZg5RxZbobVrc,4988
@@ -154,7 +154,7 @@ django_cfg/cli/commands/__init__.py,sha256=EKLXDAx-QttnGmdjsmVANAfhxWplxl2V_2I0S
154
154
  django_cfg/cli/commands/create_project.py,sha256=bxgf_YCVAhaGx-mvpuJvcx8fjMJe-EPiuw7pbD4iNxA,21053
155
155
  django_cfg/cli/commands/info.py,sha256=tLZmiZX2nEpwrcN9cUwrGKb95X7dasuoeePrqTmK2do,4932
156
156
  django_cfg/core/__init__.py,sha256=eVK57qFOok9kTeHoNEMQ1BplkUOaQ7NB9kP9eQK1vg0,358
157
- django_cfg/core/config.py,sha256=J8SZhirJTw0nJ7Z6wkiUqFan4s7IXUmgB-QbvLAWd_k,27820
157
+ django_cfg/core/config.py,sha256=aJAXzHGyORiVyX8bLcaFJMA4e2jMmRqNbCIM6QQY11Q,28007
158
158
  django_cfg/core/environment.py,sha256=AXNKVxcV_3_3gtlafDx3wFTnTPPMGQ9gl40vYm2w-Hg,9101
159
159
  django_cfg/core/generation.py,sha256=i3c0RI4vUk3X2JZiULfoH5_H8ZjO7rOZTY83eJDfDYA,24715
160
160
  django_cfg/core/validation.py,sha256=j0q57oJEJjI6ylb3AzvsgupmvBKsUcrxpmkfKF3ZRF4,6585
@@ -165,7 +165,7 @@ django_cfg/management/commands/clear_constance.py,sha256=bSUhxEIKFLmXVilQGn3s9FZ
165
165
  django_cfg/management/commands/create_token.py,sha256=beHtUTuyFZhG97F9vSkaX-u7tieAZW-C6pntujGw1C8,11796
166
166
  django_cfg/management/commands/generate.py,sha256=w0BF7IMftxNjxTxFuY8cw5pNKGW-LmTScJ8kZpxHu_8,4248
167
167
  django_cfg/management/commands/list_urls.py,sha256=D8ikInA3uE1LbQGLWmfdLnEqPg7wqrI3caQA6iTe_-0,11009
168
- django_cfg/management/commands/migrator.py,sha256=swU9bA0eV4ILgcmrn0vJZrmKNYkrTZ7eYOf3qLdmyH8,17969
168
+ django_cfg/management/commands/migrator.py,sha256=KPWbn46sGWj3y1PBq4vXjE2cY_N_UMmnNdeJaTXIJ18,19799
169
169
  django_cfg/management/commands/rundramatiq.py,sha256=62l7PvtVabtfRtrdktj_5uBbXDXi8oEde0W4IsmoHXw,8980
170
170
  django_cfg/management/commands/runserver_ngrok.py,sha256=mcTioDIzHgha6sGo5eazlJhdKr8y5-uEQIc3qG3AvCI,5237
171
171
  django_cfg/management/commands/script.py,sha256=I6zOEQEGaED0HoLxl2EqKz39HwbKg9HhdxnGKybfH5s,16974
@@ -261,9 +261,9 @@ django_cfg/templates/admin/snippets/zones/zones_table.html,sha256=2oaiCXVof2F7Li
261
261
  django_cfg/templates/emails/base_email.html,sha256=TWcvYa2IHShlF_E8jf1bWZStRO0v8G4L_GexPxvz6XQ,8836
262
262
  django_cfg/utils/__init__.py,sha256=64wwXJuXytvwt8Ze_erSR2HmV07nGWJ6DV5wloRBvYE,435
263
263
  django_cfg/utils/path_resolution.py,sha256=eML-6-RIGTs5TePktIQN8nxfDUEFJ3JA0AzWBcihAbs,13894
264
- django_cfg/utils/smart_defaults.py,sha256=H0Q3dzXOok3mNV7358lZLNYOJoiX_eIay8c83ugvygk,21049
265
- django_cfg-1.1.71.dist-info/METADATA,sha256=TcxUVLdipoW_LuCbiFi6Ei_4qiH6w8U4toWVhfatTb0,44134
266
- django_cfg-1.1.71.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
267
- django_cfg-1.1.71.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
268
- django_cfg-1.1.71.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
269
- django_cfg-1.1.71.dist-info/RECORD,,
264
+ django_cfg/utils/smart_defaults.py,sha256=-qaoiOQ1HKDOzwK2uxoNlmrOX6l8zgGlVPgqtdj3y4g,22319
265
+ django_cfg-1.1.73.dist-info/METADATA,sha256=_3gdAPOfJNmlbXK9kI_pJl-97NCDqoXF8IOK8NwZ9_s,44134
266
+ django_cfg-1.1.73.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
267
+ django_cfg-1.1.73.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
268
+ django_cfg-1.1.73.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
269
+ django_cfg-1.1.73.dist-info/RECORD,,