django-cfg 1.4.94__py3-none-any.whl → 1.4.96__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.

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.94"
35
+ __version__ = "1.4.96"
36
36
  __license__ = "MIT"
37
37
 
38
38
  # Import registry for organized lazy loading
@@ -4,8 +4,9 @@ JWT tokens are automatically injected into HTML responses for authenticated user
4
4
  This is specific to Next.js frontend apps only.
5
5
 
6
6
  Features:
7
- - Automatic extraction of ZIP archives with smart update detection
8
- - Auto-reextraction when ZIP is modified within last 5 minutes
7
+ - Automatic extraction of ZIP archives with timestamp comparison
8
+ - Auto-reextraction when ZIP is newer than extracted directory
9
+ - Cache busting (no-store headers for HTML)
9
10
  - SPA routing with fallback strategies
10
11
  - JWT token injection for authenticated users
11
12
  """
@@ -28,24 +29,26 @@ logger = logging.getLogger(__name__)
28
29
 
29
30
  class ZipExtractionMixin:
30
31
  """
31
- Mixin for automatic ZIP extraction with age-based refresh.
32
+ Mixin for automatic ZIP extraction with timestamp-based refresh.
32
33
 
33
34
  Provides intelligent ZIP archive handling:
34
35
  - Auto-extraction when directory doesn't exist
35
- - Auto-reextraction when extracted directory is older than 10 minutes
36
- - Simple age-based logic (no ZIP timestamp comparison needed)
36
+ - Auto-reextraction when ZIP is newer than extracted directory
37
+ - Timestamp comparison ensures fresh builds are always deployed
37
38
 
38
39
  Usage:
39
40
  class MyView(ZipExtractionMixin, View):
40
41
  app_name = 'myapp' # Will look for myapp.zip
41
42
  """
42
43
 
43
- # Maximum age of extracted directory before re-extraction (in seconds)
44
- MAX_DIRECTORY_AGE = 600 # 10 minutes = 600 seconds
45
-
46
44
  def extract_zip_if_needed(self, base_dir: Path, zip_path: Path, app_name: str) -> bool:
47
45
  """
48
- Extract ZIP archive if needed based on directory age.
46
+ Extract ZIP archive if needed based on ZIP modification time comparison.
47
+
48
+ Logic:
49
+ 1. If directory doesn't exist → extract
50
+ 2. If ZIP is newer than directory → remove and re-extract
51
+ 3. If directory is newer than ZIP → use existing
49
52
 
50
53
  Args:
51
54
  base_dir: Target directory for extraction
@@ -57,20 +60,27 @@ class ZipExtractionMixin:
57
60
  """
58
61
  should_extract = False
59
62
 
63
+ # Check if ZIP exists first
64
+ if not zip_path.exists():
65
+ logger.error(f"[{app_name}] ZIP not found: {zip_path}")
66
+ return False
67
+
68
+ # Get ZIP modification time
69
+ zip_mtime = datetime.fromtimestamp(zip_path.stat().st_mtime)
70
+
60
71
  # Priority 1: If directory doesn't exist at all - always extract
61
72
  if not base_dir.exists():
62
73
  should_extract = True
63
74
  logger.info(f"[{app_name}] Directory doesn't exist, will extract")
64
75
 
65
- # Priority 2: Directory exists - check if it's too old
76
+ # Priority 2: Directory exists - compare timestamps
66
77
  else:
67
78
  # Get directory modification time
68
79
  dir_mtime = datetime.fromtimestamp(base_dir.stat().st_mtime)
69
- directory_age = (datetime.now() - dir_mtime).total_seconds()
70
80
 
71
- # If directory is older than MAX_DIRECTORY_AGE - re-extract
72
- if directory_age > self.MAX_DIRECTORY_AGE:
73
- logger.info(f"[{app_name}] Directory is old ({directory_age:.0f}s > {self.MAX_DIRECTORY_AGE}s), re-extracting")
81
+ # If ZIP is newer than directory - re-extract
82
+ if zip_mtime > dir_mtime:
83
+ logger.info(f"[{app_name}] ZIP is newer (ZIP: {zip_mtime}, DIR: {dir_mtime}), re-extracting")
74
84
  try:
75
85
  shutil.rmtree(base_dir)
76
86
  should_extract = True
@@ -78,26 +88,22 @@ class ZipExtractionMixin:
78
88
  logger.error(f"[{app_name}] Failed to remove old directory: {e}")
79
89
  return False
80
90
  else:
81
- logger.debug(f"[{app_name}] Directory is fresh ({directory_age:.0f}s), using existing")
91
+ logger.debug(f"[{app_name}] Directory is up-to-date (DIR: {dir_mtime} >= ZIP: {zip_mtime})")
82
92
 
83
93
  # Extract ZIP if needed
84
94
  if should_extract:
85
- if zip_path.exists():
86
- logger.info(f"[{app_name}] Extracting {zip_path.name} to {base_dir}...")
87
- try:
88
- base_dir.parent.mkdir(parents=True, exist_ok=True)
89
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
90
- zip_ref.extractall(base_dir)
91
- logger.info(f"[{app_name}] Successfully extracted {zip_path.name}")
92
- return True
93
- except Exception as e:
94
- logger.error(f"[{app_name}] Failed to extract: {e}")
95
- return False
96
- else:
97
- logger.error(f"[{app_name}] ZIP not found: {zip_path}")
95
+ logger.info(f"[{app_name}] Extracting {zip_path.name} to {base_dir}...")
96
+ try:
97
+ base_dir.parent.mkdir(parents=True, exist_ok=True)
98
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
99
+ zip_ref.extractall(base_dir)
100
+ logger.info(f"[{app_name}] Successfully extracted {zip_path.name}")
101
+ return True
102
+ except Exception as e:
103
+ logger.error(f"[{app_name}] Failed to extract: {e}")
98
104
  return False
99
105
 
100
- # Directory exists and is fresh
106
+ # Directory exists and is up-to-date
101
107
  return True
102
108
 
103
109
 
@@ -108,7 +114,7 @@ class NextJSStaticView(ZipExtractionMixin, View):
108
114
 
109
115
  Features:
110
116
  - Serves Next.js static export files like a static file server
111
- - Smart ZIP extraction: auto-refreshes when directory older than 10 minutes
117
+ - Smart ZIP extraction: auto-refreshes when ZIP is newer than directory
112
118
  - Automatically injects JWT tokens for authenticated users
113
119
  - Tokens injected into HTML responses only
114
120
  - Handles Next.js client-side routing (.html fallback)
@@ -117,9 +123,9 @@ class NextJSStaticView(ZipExtractionMixin, View):
117
123
 
118
124
  ZIP Extraction Logic:
119
125
  - If directory doesn't exist: extract from ZIP
120
- - If directory older than 10 minutes: remove and re-extract
121
- - If directory fresh (< 10 min): use existing files
122
- - This enables auto-refresh during development while caching in production
126
+ - If ZIP is newer than directory: remove and re-extract
127
+ - If directory is up-to-date: use existing files
128
+ - This ensures fresh builds are always deployed automatically
123
129
 
124
130
  Path resolution examples:
125
131
  - /cfg/admin/ → /cfg/admin/index.html
@@ -187,6 +193,12 @@ class NextJSStaticView(ZipExtractionMixin, View):
187
193
  if self._should_inject_jwt(request, response):
188
194
  self._inject_jwt_tokens(request, response)
189
195
 
196
+ # Disable caching for HTML files (prevent Cloudflare/browser caching)
197
+ if is_html_file:
198
+ response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
199
+ response['Pragma'] = 'no-cache'
200
+ response['Expires'] = '0'
201
+
190
202
  return response
191
203
 
192
204
  def _resolve_spa_path(self, base_dir, path):
@@ -4,10 +4,20 @@ Views for Next.js admin integration.
4
4
  Serves Next.js static files with SPA routing support and JWT injection.
5
5
 
6
6
  Features:
7
- - Automatic extraction of ZIP archives with age-based refresh
8
- - Auto-reextraction when directory is older than 10 minutes
7
+ - Priority-based ZIP resolution (solution project package fallback)
8
+ - Automatic extraction with timestamp comparison (ZIP mtime vs directory mtime)
9
+ - Cache busting (no-store headers + timestamp query params)
9
10
  - SPA routing with fallback strategies
10
11
  - JWT token injection for authenticated users
12
+
13
+ ZIP Resolution Priority:
14
+ 1. Solution project: {BASE_DIR}/static/nextjs_admin.zip → {BASE_DIR}/static/nextjs_admin/
15
+ 2. Package fallback: django_cfg/static/frontend/nextjs_admin.zip → django_cfg/static/frontend/nextjs_admin/
16
+
17
+ Extraction Logic:
18
+ - Compares ZIP mtime with directory mtime
19
+ - Re-extracts only when ZIP is newer
20
+ - Ensures fresh builds are deployed automatically
11
21
  """
12
22
 
13
23
  import logging
@@ -31,20 +41,26 @@ class NextJsAdminView(ZipExtractionMixin, LoginRequiredMixin, View):
31
41
 
32
42
  Features:
33
43
  - Serves Next.js static build files
34
- - Smart ZIP extraction: auto-refreshes when directory older than 10 minutes
44
+ - Priority-based ZIP resolution (solution first, package fallback)
45
+ - Smart ZIP extraction: compares ZIP mtime vs directory mtime
46
+ - Cache busting: no-store headers for HTML files
35
47
  - Automatic JWT token injection for authenticated users
36
48
  - SPA routing support (path/to/route → path/to/route/index.html)
37
- - Development mode support (proxies to dev server conceptually)
49
+
50
+ ZIP Resolution Priority:
51
+ 1. Solution: {BASE_DIR}/static/nextjs_admin.zip → {BASE_DIR}/static/nextjs_admin/
52
+ 2. Package: django_cfg/static/frontend/nextjs_admin.zip → django_cfg/static/frontend/nextjs_admin/
38
53
 
39
54
  ZIP Extraction Logic:
40
55
  - If directory doesn't exist: extract from ZIP
41
- - If directory older than 10 minutes: remove and re-extract
42
- - If directory fresh (< 10 min): use existing files
56
+ - If ZIP is newer than directory: remove and re-extract
57
+ - If directory is up-to-date: use existing files
58
+ - Ensures fresh builds are deployed automatically
43
59
 
44
60
  URL Examples:
45
- /cfg/admin/ → admin/index.html
46
- /cfg/admin/crypto → admin/crypto/index.html
47
- /cfg/admin/_next/static/... → _next/static/...
61
+ /cfg/nextjs-admin/admin/ → admin/index.html
62
+ /cfg/nextjs-admin/admin/crypto → admin/crypto/index.html
63
+ /cfg/nextjs-admin/admin/_next/static/... → _next/static/...
48
64
  """
49
65
 
50
66
  def get(self, request, path=''):
@@ -58,17 +74,27 @@ class NextJsAdminView(ZipExtractionMixin, LoginRequiredMixin, View):
58
74
 
59
75
  nextjs_config = config.nextjs_admin
60
76
 
61
- # Use extracted directory from static/frontend/nextjs_admin/
62
- base_dir = Path(django_cfg.__file__).parent / 'static' / 'frontend' / 'nextjs_admin'
63
- zip_path = Path(django_cfg.__file__).parent / 'static' / 'frontend' / 'nextjs_admin.zip'
64
-
65
- # Fallback: Try solution project static directory
66
- if not zip_path.exists():
67
- from django.conf import settings
68
- solution_zip = Path(settings.BASE_DIR) / 'static' / 'nextjs_admin.zip'
69
- if solution_zip.exists():
70
- zip_path = solution_zip
71
- logger.info(f"[nextjs_admin] Using ZIP from solution project: {solution_zip}")
77
+ # Priority 1: Try solution project static directory first
78
+ from django.conf import settings
79
+ solution_zip = Path(settings.BASE_DIR) / 'static' / 'nextjs_admin.zip'
80
+ solution_base_dir = Path(settings.BASE_DIR) / 'static' / 'nextjs_admin'
81
+
82
+ # Priority 2: Fallback to django_cfg package
83
+ default_zip = Path(django_cfg.__file__).parent / 'static' / 'frontend' / 'nextjs_admin.zip'
84
+ default_base_dir = Path(django_cfg.__file__).parent / 'static' / 'frontend' / 'nextjs_admin'
85
+
86
+ # Choose which ZIP to use
87
+ if solution_zip.exists():
88
+ zip_path = solution_zip
89
+ base_dir = solution_base_dir
90
+ logger.info(f"[nextjs_admin] Using ZIP from solution project: {solution_zip}")
91
+ elif default_zip.exists():
92
+ zip_path = default_zip
93
+ base_dir = default_base_dir
94
+ logger.info(f"[nextjs_admin] Using ZIP from django_cfg package: {default_zip}")
95
+ else:
96
+ logger.error(f"[nextjs_admin] No ZIP found in solution ({solution_zip}) or package ({default_zip})")
97
+ return render(request, 'frontend/404.html', status=404)
72
98
 
73
99
  # Extract ZIP if needed using mixin
74
100
  if not self.extract_zip_if_needed(base_dir, zip_path, 'nextjs_admin'):
@@ -114,6 +140,12 @@ class NextJsAdminView(ZipExtractionMixin, LoginRequiredMixin, View):
114
140
  if is_html and request.user.is_authenticated:
115
141
  self._inject_jwt_tokens(request, response)
116
142
 
143
+ # Disable caching for HTML files (prevent Cloudflare/browser caching)
144
+ if is_html:
145
+ response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
146
+ response['Pragma'] = 'no-cache'
147
+ response['Expires'] = '0'
148
+
117
149
  return response
118
150
 
119
151
  def _resolve_spa_path(self, base_dir: Path, path: str, nextjs_config) -> str:
django_cfg/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "django-cfg"
7
- version = "1.4.94"
7
+ version = "1.4.96"
8
8
  description = "Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features."
9
9
  readme = "README.md"
10
10
  keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "nextjs-admin", "react-admin", "websocket", "centrifugo", "real-time", "typescript-generation", "ai-agents", "enterprise-django", "django-settings", "type-safe-config", "modern-django",]
@@ -6,6 +6,7 @@ Provides template tags for accessing django-cfg configuration constants.
6
6
 
7
7
  import os
8
8
  import socket
9
+ import time
9
10
  from django import template
10
11
  from django.conf import settings
11
12
  from django.utils.safestring import mark_safe
@@ -183,20 +184,27 @@ def nextjs_admin_url(path=''):
183
184
  # Normalize path - remove leading/trailing slashes
184
185
  path = path.strip('/')
185
186
 
187
+ # Add cache busting parameter (timestamp in milliseconds)
188
+ cache_buster = f'_={int(time.time() * 1000)}'
189
+
186
190
  if not settings.DEBUG:
187
- # Production mode: always use static files
188
- return f'/cfg/admin/admin/{path}' if path else '/cfg/admin/admin/'
191
+ # Production mode: always use static files with cache buster
192
+ base_url = f'/cfg/admin/admin/{path}' if path else '/cfg/admin/admin/'
193
+ return f'{base_url}?{cache_buster}'
189
194
 
190
195
  # Check if port 3001 is available for Tab 1 (built-in admin)
191
196
  port_3001_available = _is_port_available('localhost', 3001)
192
197
 
193
198
  if port_3001_available:
194
- # Dev server is running on 3001 - use it
195
- base_url = 'http://localhost:3001/admin'
196
- return f'{base_url}/{path}' if path else base_url
199
+ # Dev server is running on 3001 - use it (builtin admin has no /admin prefix)
200
+ base_url = 'http://localhost:3001'
201
+ url = f'{base_url}/{path}' if path else base_url
202
+ return f'{url}?{cache_buster}'
197
203
  else:
198
- # No dev server or dev server stopped - use static files
199
- return f'/cfg/admin/admin/{path}' if path else '/cfg/admin/admin/'
204
+ # No dev server or dev server stopped - use static files with cache buster
205
+ # Static files are served from /cfg/admin/ but ZIP contains files in root (no /admin prefix)
206
+ base_url = f'/cfg/admin/{path}' if path else '/cfg/admin/'
207
+ return f'{base_url}?{cache_buster}'
200
208
 
201
209
 
202
210
  @register.simple_tag
@@ -272,14 +280,20 @@ def nextjs_external_admin_url(route=''):
272
280
 
273
281
  route = route.strip('/')
274
282
 
283
+ # Add cache busting parameter (timestamp in milliseconds)
284
+ cache_buster = f'_={int(time.time() * 1000)}'
285
+
275
286
  # Auto-detect development mode: DEBUG=True + port 3000 available
276
287
  if settings.DEBUG and _is_port_available('localhost', 3000):
277
288
  # Development mode: solution project on port 3000
289
+ # Routes start with /admin in Next.js (e.g., /admin, /admin/crypto)
278
290
  base_url = 'http://localhost:3000/admin'
279
- return f'{base_url}/{route}' if route else base_url
291
+ url = f'{base_url}/{route}' if route else base_url
292
+ return f'{url}?{cache_buster}'
280
293
  else:
281
294
  # Production mode: use relative URL - Django serves from extracted ZIP with /admin prefix
282
- return f"/cfg/nextjs-admin/admin/{route}" if route else "/cfg/nextjs-admin/admin/"
295
+ base_url = f"/cfg/nextjs-admin/admin/{route}" if route else "/cfg/nextjs-admin/admin/"
296
+ return f'{base_url}?{cache_buster}'
283
297
  except Exception:
284
298
  return ''
285
299
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.4.94
3
+ Version: 1.4.96
4
4
  Summary: Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features.
5
5
  Project-URL: Homepage, https://djangocfg.com
6
6
  Project-URL: Documentation, https://djangocfg.com
@@ -1,5 +1,5 @@
1
1
  django_cfg/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- django_cfg/__init__.py,sha256=-eM13Z1Uie8EJUy2384SNHfso1SqzwpkDsmrQgWQN3w,1620
2
+ django_cfg/__init__.py,sha256=UbaqH6yGdQLEgNwn0Hmp7oKhbtKyZTVYU4UIvyIPn_c,1620
3
3
  django_cfg/apps.py,sha256=72m3uuvyqGiLx6gOfE-BD3P61jddCCERuBOYpxTX518,1605
4
4
  django_cfg/config.py,sha256=y4Z3rnYsHBE0TehpwAIPaxr---mkvyKrZGGsNwYso74,1398
5
5
  django_cfg/apps/__init__.py,sha256=JtDmEYt1OcleWM2ZaeX0LKDnRQzPOavfaXBWG4ECB5Q,26
@@ -228,7 +228,7 @@ django_cfg/apps/frontend/apps.py,sha256=9eEK0Tq2nOsol7xSK5aobdwTDJTJrWx6Iy1I1DQb
228
228
  django_cfg/apps/frontend/setup.py,sha256=TxKQwQw4xTF6VSyhrQBzbUsdsVQR9JHdjc36LZKeQh4,2444
229
229
  django_cfg/apps/frontend/test_routing.py,sha256=fshJOR9ln7m3gXY9EI1_ix_6E5xua6DR264b16RIF-w,4832
230
230
  django_cfg/apps/frontend/urls.py,sha256=Vz22_2i2w1J0KQYDCxHnTF5rUf32kUUSBDJZrP07XgY,284
231
- django_cfg/apps/frontend/views.py,sha256=JkObFoAJATT2gy6TnyFi0LrjQm7HGWaRy3vr2zdTs4E,13586
231
+ django_cfg/apps/frontend/views.py,sha256=SOYOgZdJWnNQLOMLY1Lx7xkGnI_pS4OKV5UNydQsh48,13922
232
232
  django_cfg/apps/frontend/templates/frontend/404.html,sha256=LCFig_dcgDDmYKhgOLu8R2KDs_aQS6Es6rAxLTAEXWs,2175
233
233
  django_cfg/apps/knowbase/README.md,sha256=HXt_J6WCN-LsMhA7p9mdvih07_vp_r_hkPdmqHhNEeo,3965
234
234
  django_cfg/apps/knowbase/__init__.py,sha256=cfGnxDQwjajPhUoleKkgvdabJcB0LdXEglnsBojKkPo,1045
@@ -1021,7 +1021,7 @@ django_cfg/modules/django_unfold/models/navigation.py,sha256=PPEeqA2HBaA1-VjADiX
1021
1021
  django_cfg/modules/nextjs_admin/__init__.py,sha256=lfrZYyNRExH3Z5De8G4hQBIZoFlW5Ejze3couNrztbY,312
1022
1022
  django_cfg/modules/nextjs_admin/apps.py,sha256=HxVUMmWTKdYpwJ00iIfWVFsBzsawsOVhEPZqjk_izjI,347
1023
1023
  django_cfg/modules/nextjs_admin/urls.py,sha256=7n0yStm0WNchw14Rtu_mgsIA3WKQsYP9WZt3-YOUWjU,603
1024
- django_cfg/modules/nextjs_admin/views.py,sha256=lOcK-XLucWn-W4LORgk0XBEJkolYvSvsnp4Pq77oBBY,9657
1024
+ django_cfg/modules/nextjs_admin/views.py,sha256=4gzdo2gxY2zSs9MxxZc2Z7FfJHGsg5ZcGXWOo4i3sLA,11246
1025
1025
  django_cfg/modules/nextjs_admin/models/__init__.py,sha256=WGw9KXcYd1O9AoA_bpMoz2gLZUlRzjGmUBjjbObcUi0,100
1026
1026
  django_cfg/modules/nextjs_admin/models/config.py,sha256=0ADqLuiywSCQfx_z9dkwjFCca3lr3F2uQffIjTr_QXw,5864
1027
1027
  django_cfg/modules/nextjs_admin/templatetags/__init__.py,sha256=ChVBnJggCIY8rMhfyJFoA8k0qKo-8FtJknrk54Vx4wM,51
@@ -1051,7 +1051,6 @@ django_cfg/static/admin/js/alpine/dashboard-tabs.js,sha256=ob8Q_I9lFLDv_hFERXgTy
1051
1051
  django_cfg/static/admin/js/alpine/system-metrics.js,sha256=m-Fg55K_vpHXToD46PXL9twl4OBF_V9MONvbSWbQqDw,440
1052
1052
  django_cfg/static/admin/js/alpine/toggle-section.js,sha256=T141NFmy0fRJyGGuuaCJRjJXwPam-xxtQNW1hi8BJbc,672
1053
1053
  django_cfg/static/frontend/admin.zip,sha256=n2G8ajruLqojcjqvw2pMEPjgpSTTwcmJxkeIQxJVw9U,7626768
1054
- django_cfg/static/frontend/nextjs_admin.zip,sha256=BsnMjrr9vx1Lh1zadBEBFGeP-Cn_eLjhWfkWk1m0fEw,7548272
1055
1054
  django_cfg/static/js/api-loader.mjs,sha256=boGqqRGnFR-Mzo_RQOjhAzNvsb7QxZddSwMKROzkk9Q,5163
1056
1055
  django_cfg/static/js/api/base.mjs,sha256=KUxZHHdELAV8mNnACpwJRvaQhdJxp-n5LFEQ4oUZxBo,4707
1057
1056
  django_cfg/static/js/api/index.mjs,sha256=_-Q04jjHcgwi4CGfiaLyiOR6NW7Yu1HBhJWp2J1cjpc,2538
@@ -1077,7 +1076,7 @@ django_cfg/templates/admin/index.html,sha256=RidRvZwc6LFzRi8l6vHBgyM_CD0yvhPWvr4
1077
1076
  django_cfg/templates/emails/base_email.html,sha256=TWcvYa2IHShlF_E8jf1bWZStRO0v8G4L_GexPxvz6XQ,8836
1078
1077
  django_cfg/templates/unfold/layouts/skeleton.html,sha256=2ArkcNZ34mFs30cOAsTQ1EZiDXcB0aVxkO71lJq9SLE,718
1079
1078
  django_cfg/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1080
- django_cfg/templatetags/django_cfg.py,sha256=0m7YadW6ifWuUEA9qe9IZ6zY4wt4F4ke0RXo3ngA5p8,9334
1079
+ django_cfg/templatetags/django_cfg.py,sha256=BLkdH6Pl32itRafOpPxXGg1QhZ9huacAAqFv-W8LTkM,10044
1081
1080
  django_cfg/utils/__init__.py,sha256=64wwXJuXytvwt8Ze_erSR2HmV07nGWJ6DV5wloRBvYE,435
1082
1081
  django_cfg/utils/path_resolution.py,sha256=2n0I04lQkSssFaELu3A93YyMAl1K10KPdpxMt5k4Iy0,13341
1083
1082
  django_cfg/utils/smart_defaults.py,sha256=ZUj6K_Deq-fp5O0Dy_Emt257UWFn0f9bkgFv9YCR58U,9239
@@ -1085,9 +1084,9 @@ django_cfg/utils/version_check.py,sha256=WO51J2m2e-wVqWCRwbultEwu3q1lQasV67Mw2aa
1085
1084
  django_cfg/CHANGELOG.md,sha256=jtT3EprqEJkqSUh7IraP73vQ8PmKUMdRtznQsEnqDZk,2052
1086
1085
  django_cfg/CONTRIBUTING.md,sha256=DU2kyQ6PU0Z24ob7O_OqKWEYHcZmJDgzw-lQCmu6uBg,3041
1087
1086
  django_cfg/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
1088
- django_cfg/pyproject.toml,sha256=J8hwDLhnybgAGUsvUNdXFimKoEuj7Lc9SH1n5f_Q0gY,8572
1089
- django_cfg-1.4.94.dist-info/METADATA,sha256=Xhg1mauCgGfgGYkYBGmGWH19KcqlRxLi4z-kGAGFvVs,23733
1090
- django_cfg-1.4.94.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1091
- django_cfg-1.4.94.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
1092
- django_cfg-1.4.94.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
1093
- django_cfg-1.4.94.dist-info/RECORD,,
1087
+ django_cfg/pyproject.toml,sha256=Npc1mjOUxl_Dvp1uFVjLCbrQo1tlTMMxj4Oemc6kLvo,8572
1088
+ django_cfg-1.4.96.dist-info/METADATA,sha256=6LS9GzmiwHVvee547cEZjnwrdkib9Kw9Zja8LowXnk0,23733
1089
+ django_cfg-1.4.96.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1090
+ django_cfg-1.4.96.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
1091
+ django_cfg-1.4.96.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
1092
+ django_cfg-1.4.96.dist-info/RECORD,,
Binary file