django-cfg 1.4.109__py3-none-any.whl → 1.4.110__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.
Files changed (23) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/modules/django_admin/__init__.py +6 -0
  3. django_cfg/modules/django_admin/base/pydantic_admin.py +91 -0
  4. django_cfg/modules/django_admin/config/__init__.py +5 -0
  5. django_cfg/modules/django_admin/config/admin_config.py +7 -0
  6. django_cfg/modules/django_admin/config/documentation_config.py +406 -0
  7. django_cfg/modules/django_admin/config/field_config.py +87 -0
  8. django_cfg/modules/django_admin/templates/django_admin/change_form_docs.html +23 -0
  9. django_cfg/modules/django_admin/templates/django_admin/change_list_docs.html +23 -0
  10. django_cfg/modules/django_admin/templates/django_admin/documentation_block.html +297 -0
  11. django_cfg/modules/django_admin/templates/django_admin/markdown_docs_block.html +37 -0
  12. django_cfg/modules/django_admin/utils/__init__.py +3 -0
  13. django_cfg/modules/django_admin/utils/html_builder.py +94 -1
  14. django_cfg/modules/django_admin/utils/markdown_renderer.py +344 -0
  15. django_cfg/pyproject.toml +2 -2
  16. {django_cfg-1.4.109.dist-info → django_cfg-1.4.110.dist-info}/METADATA +2 -1
  17. {django_cfg-1.4.109.dist-info → django_cfg-1.4.110.dist-info}/RECORD +20 -17
  18. django_cfg/modules/django_admin/CHANGELOG_CODE_METHODS.md +0 -153
  19. django_cfg/modules/django_admin/IMPORT_EXPORT_FIX.md +0 -72
  20. django_cfg/modules/django_admin/RESOURCE_CONFIG_ENHANCEMENT.md +0 -350
  21. {django_cfg-1.4.109.dist-info → django_cfg-1.4.110.dist-info}/WHEEL +0 -0
  22. {django_cfg-1.4.109.dist-info → django_cfg-1.4.110.dist-info}/entry_points.txt +0 -0
  23. {django_cfg-1.4.109.dist-info → django_cfg-1.4.110.dist-info}/licenses/LICENSE +0 -0
@@ -1,72 +0,0 @@
1
- # Import/Export Button Fix
2
-
3
- ## Problem
4
-
5
- Import/Export buttons in `PydanticAdmin` were displaying incorrectly because:
6
-
7
- 1. `PydanticAdmin` was using the original `ImportExportModelAdmin` from django-import-export
8
- 2. Original django-import-export templates don't integrate properly with Unfold UI
9
- 3. Buttons were styled as tabs instead of toolbar buttons
10
-
11
- ## Solution
12
-
13
- Updated `PydanticAdmin` base class to use django_cfg's custom `ImportExportMixin`:
14
-
15
- ### Before
16
- ```python
17
- class UnfoldImportExportModelAdmin(ImportExportModelAdmin, UnfoldModelAdmin):
18
- pass
19
- ```
20
-
21
- ### After
22
- ```python
23
- class UnfoldImportExportModelAdmin(UnfoldModelAdmin, ImportExportMixin):
24
- pass
25
- ```
26
-
27
- ## Changes Made
28
-
29
- 1. **MRO (Method Resolution Order)**:
30
- - `UnfoldModelAdmin` comes first (for template priority)
31
- - `ImportExportMixin` comes second (adds import/export functionality)
32
-
33
- 2. **Custom Templates** (`django_cfg.modules.django_import_export`):
34
- - Custom `change_list_*.html` templates that extend Unfold's base
35
- - Properly styled import/export buttons as round icons
36
- - Import button: green with upload icon
37
- - Export button: blue with download icon
38
-
39
- 3. **Integration**:
40
- - Uses Unfold's forms (`ImportForm`, `ExportForm`)
41
- - Buttons appear in `object-tools-items` block (next to "Add" button)
42
- - Full dark mode support
43
-
44
- ## Result
45
-
46
- Now `PydanticAdmin` admins with `import_export_enabled=True` will have:
47
- - ✅ Properly styled import/export buttons
48
- - ✅ Consistent Unfold UI
49
- - ✅ Round icon buttons matching the design system
50
- - ✅ Correct positioning in the toolbar
51
-
52
- ## Usage
53
-
54
- No changes required in user code - this fix is automatic:
55
-
56
- ```python
57
- from django_cfg.modules.django_admin import AdminConfig
58
- from django_cfg.modules.django_admin.base import PydanticAdmin
59
-
60
- config = AdminConfig(
61
- model=MyModel,
62
- import_export_enabled=True,
63
- resource_class=MyModelResource,
64
- list_display=["name", "status"],
65
- )
66
-
67
- @admin.register(MyModel)
68
- class MyModelAdmin(PydanticAdmin):
69
- config = config
70
- ```
71
-
72
- The import/export buttons will now display correctly!
@@ -1,350 +0,0 @@
1
- # ResourceConfig & BackgroundTaskConfig Enhancement
2
-
3
- ## Summary
4
-
5
- Enhanced django-admin module with declarative import/export configuration and background task support.
6
-
7
- ## New Features
8
-
9
- ### 1. ResourceConfig
10
-
11
- Declarative configuration for django-import-export Resource classes.
12
-
13
- **Location:** `django_cfg/modules/django_admin/config/resource_config.py`
14
-
15
- **Features:**
16
- - Field selection and exclusion
17
- - Import ID fields configuration
18
- - Import/export behavior control
19
- - Hook support (before/after import, per-row hooks)
20
- - Export field ordering
21
- - Batch processing options
22
-
23
- **Example:**
24
- ```python
25
- from django_cfg.modules.django_admin import ResourceConfig
26
-
27
- resource_config = ResourceConfig(
28
- fields=['host', 'port', 'username', 'password'],
29
- exclude=['metadata', 'config'],
30
- import_id_fields=['host', 'port'],
31
- skip_unchanged=True,
32
- after_import_row='apps.myapp.tasks.test_after_import',
33
- batch_size=100,
34
- )
35
- ```
36
-
37
- ### 2. BackgroundTaskConfig
38
-
39
- Configuration for background task processing.
40
-
41
- **Location:** `django_cfg/modules/django_admin/config/background_task_config.py`
42
-
43
- **Features:**
44
- - Task runner selection (rearq, celery, django_q, sync)
45
- - Batch size configuration
46
- - Timeout settings
47
- - Retry policy
48
- - Priority levels
49
-
50
- **Example:**
51
- ```python
52
- from django_cfg.modules.django_admin import BackgroundTaskConfig
53
-
54
- background_config = BackgroundTaskConfig(
55
- enabled=True,
56
- task_runner='rearq',
57
- batch_size=50,
58
- timeout=300,
59
- retry_on_failure=True,
60
- max_retries=3,
61
- )
62
- ```
63
-
64
- ### 3. Enhanced AdminConfig
65
-
66
- **Updated:** `django_cfg/modules/django_admin/config/admin_config.py`
67
-
68
- **New Fields:**
69
- ```python
70
- class AdminConfig(BaseModel):
71
- # ... existing fields ...
72
-
73
- # Import/Export enhancement
74
- resource_config: Optional[ResourceConfig] = None
75
-
76
- # Background task processing
77
- background_task_config: Optional[BackgroundTaskConfig] = None
78
- ```
79
-
80
- ### 4. Enhanced PydanticAdmin
81
-
82
- **Updated:** `django_cfg/modules/django_admin/base/pydantic_admin.py`
83
-
84
- **Key Changes:**
85
- - `_generate_resource_class()` now uses ResourceConfig if provided
86
- - Auto-generates Resource with hooks support
87
- - Dynamically attaches hook methods to Resource class
88
-
89
- **Hook Support:**
90
- - `before_import` - Called before import starts
91
- - `after_import` - Called after import completes
92
- - `before_import_row` - Called before each row import
93
- - `after_import_row` - Called after each row import (★ most useful)
94
-
95
- ## Usage Example
96
-
97
- ### Complete Proxy Admin with Import/Export
98
-
99
- ```python
100
- from django_cfg.modules.django_admin import (
101
- ActionConfig,
102
- AdminConfig,
103
- BackgroundTaskConfig,
104
- ResourceConfig,
105
- )
106
-
107
- proxy_config = AdminConfig(
108
- model=Proxy,
109
-
110
- # Enable import/export with ResourceConfig
111
- import_export_enabled=True,
112
- resource_config=ResourceConfig(
113
- fields=[
114
- 'host', 'port', 'proxy_type', 'proxy_mode',
115
- 'username', 'password',
116
- 'provider', 'country',
117
- ],
118
- exclude=['metadata', 'config', 'last_error'],
119
- import_id_fields=['host', 'port', 'provider'],
120
- skip_unchanged=True,
121
- # Auto-test after import
122
- after_import_row='apps.proxies.tasks.after_import_row_test_proxy',
123
- ),
124
-
125
- # Background task configuration
126
- background_task_config=BackgroundTaskConfig(
127
- enabled=True,
128
- task_runner='rearq',
129
- batch_size=50,
130
- timeout=300,
131
- ),
132
-
133
- # Admin actions
134
- actions=[
135
- ActionConfig(
136
- name='test_selected_proxies',
137
- description='Test selected proxies',
138
- variant='warning',
139
- icon='speed',
140
- handler='apps.proxies.admin.actions.test_selected_proxies',
141
- ),
142
- ],
143
-
144
- list_display=['host', 'port', 'status', 'success_rate'],
145
- )
146
-
147
- @admin.register(Proxy)
148
- class ProxyAdmin(PydanticAdmin):
149
- config = proxy_config
150
- ```
151
-
152
- ### Hook Implementation
153
-
154
- ```python
155
- # apps/proxies/tasks.py
156
-
157
- def after_import_row_test_proxy(row, row_result, **kwargs):
158
- """Hook called after each proxy import."""
159
-
160
- # Skip if dry run
161
- if kwargs.get('dry_run'):
162
- return
163
-
164
- # Only test new proxies
165
- if row_result.import_type == 'new':
166
- proxy = row_result.instance
167
-
168
- # Queue async test
169
- from api.workers import get_worker
170
- worker = get_worker()
171
- worker.enqueue_task(
172
- 'apps.proxies.tasks.test_proxy_async',
173
- proxy_id=str(proxy.id)
174
- )
175
- ```
176
-
177
- ## Benefits
178
-
179
- ### Before (Manual Resource Class)
180
- ```python
181
- from import_export import resources
182
-
183
- class ProxyResource(resources.ModelResource):
184
- class Meta:
185
- model = Proxy
186
- fields = ('host', 'port', 'username', 'password')
187
- import_id_fields = ['host', 'port']
188
- skip_unchanged = True
189
-
190
- def after_import_row(self, row, row_result, **kwargs):
191
- # Custom logic here
192
- pass
193
-
194
- proxy_config = AdminConfig(
195
- model=Proxy,
196
- import_export_enabled=True,
197
- resource_class=ProxyResource, # Manual class
198
- )
199
- ```
200
-
201
- ### After (Declarative ResourceConfig)
202
- ```python
203
- proxy_config = AdminConfig(
204
- model=Proxy,
205
- import_export_enabled=True,
206
- resource_config=ResourceConfig(
207
- fields=['host', 'port', 'username', 'password'],
208
- import_id_fields=['host', 'port'],
209
- skip_unchanged=True,
210
- after_import_row='apps.proxies.tasks.after_import_row_test_proxy',
211
- ),
212
- )
213
- ```
214
-
215
- **Advantages:**
216
- - ✅ No separate Resource class needed
217
- - ✅ All configuration in one place
218
- - ✅ Type-safe with Pydantic validation
219
- - ✅ Reusable across multiple admins
220
- - ✅ Hook as string path (lazy import)
221
- - ✅ Auto-generated Resource with full control
222
-
223
- ## Dependencies Added
224
-
225
- **pyproject.toml updates:**
226
- ```toml
227
- dependencies = [
228
- # ... existing ...
229
- "pytz>=2025.1",
230
- "httpx>=0.28.1,<1.0",
231
- ]
232
- ```
233
-
234
- - `pytz` - Timezone support for datetime operations
235
- - `httpx` - Modern HTTP client for proxy testing
236
-
237
- ## Files Changed
238
-
239
- ### django-cfg Core
240
- 1. `config/resource_config.py` - NEW
241
- 2. `config/background_task_config.py` - NEW
242
- 3. `config/admin_config.py` - MODIFIED (added new configs)
243
- 4. `config/__init__.py` - MODIFIED (exports)
244
- 5. `base/pydantic_admin.py` - MODIFIED (Resource generation)
245
- 6. `__init__.py` - MODIFIED (exports)
246
- 7. `pyproject.toml` - MODIFIED (dependencies)
247
-
248
- ### stockapis Implementation
249
- 1. `apps/proxies/admin/proxy_admin.py` - Uses ResourceConfig
250
- 2. `apps/proxies/admin/actions.py` - NEW (admin actions)
251
- 3. `apps/proxies/services/proxy_tester.py` - NEW (testing logic)
252
- 4. `apps/proxies/tasks.py` - NEW (background tasks)
253
- 5. `apps/proxies/@docs/IMPORT_EXPORT_SETUP.md` - NEW (docs)
254
-
255
- ## Backward Compatibility
256
-
257
- ✅ **100% Backward Compatible**
258
-
259
- Old code still works:
260
- ```python
261
- # Old way - still works
262
- proxy_config = AdminConfig(
263
- model=Proxy,
264
- import_export_enabled=True,
265
- resource_class=MyCustomResource, # Manual class
266
- )
267
-
268
- # New way - alternative
269
- proxy_config = AdminConfig(
270
- model=Proxy,
271
- import_export_enabled=True,
272
- resource_config=ResourceConfig(...), # Declarative
273
- )
274
- ```
275
-
276
- Priority:
277
- 1. If `resource_class` provided → use it (legacy)
278
- 2. If `resource_config` provided → auto-generate Resource
279
- 3. If neither → auto-generate basic Resource
280
-
281
- ## Testing
282
-
283
- ```bash
284
- # Test django-cfg imports
285
- cd django-cfg-dev
286
- poetry run python -c "from django_cfg.modules.django_admin import ResourceConfig, BackgroundTaskConfig; print('✅ OK')"
287
-
288
- # Test stockapis admin
289
- cd stockapis
290
- poetry run python manage.py check --tag admin
291
-
292
- # Test in browser
293
- poetry run python manage.py runserver
294
- # Visit: http://localhost:8000/admin/proxies/proxy/
295
- ```
296
-
297
- ## Future Enhancements
298
-
299
- - [ ] `ResourceConfig.field_widgets` - Custom widgets for fields
300
- - [ ] `ResourceConfig.validators` - Custom validation rules
301
- - [ ] `ResourceConfig.transformers` - Data transformation before import
302
- - [ ] Progress tracking for large imports
303
- - [ ] Import history and rollback
304
- - [ ] Scheduled imports via cron
305
- - [ ] API endpoint for programmatic imports
306
-
307
- ## Migration Guide
308
-
309
- ### For Existing Projects
310
-
311
- 1. Update django-cfg to latest version
312
- 2. Optional: Replace manual Resource classes with ResourceConfig
313
- 3. Optional: Add BackgroundTaskConfig for async operations
314
- 4. Optional: Add after_import_row hooks for post-import processing
315
-
316
- ### Example Migration
317
-
318
- **Before:**
319
- ```python
320
- # resources.py
321
- class ProxyResource(resources.ModelResource):
322
- class Meta:
323
- model = Proxy
324
- fields = ('host', 'port')
325
-
326
- # admin.py
327
- config = AdminConfig(
328
- model=Proxy,
329
- import_export_enabled=True,
330
- resource_class=ProxyResource,
331
- )
332
- ```
333
-
334
- **After:**
335
- ```python
336
- # admin.py only - no resources.py needed
337
- config = AdminConfig(
338
- model=Proxy,
339
- import_export_enabled=True,
340
- resource_config=ResourceConfig(
341
- fields=['host', 'port'],
342
- ),
343
- )
344
- ```
345
-
346
- ## Version
347
-
348
- - **django-cfg**: 1.4.106+
349
- - **Python**: 3.12+
350
- - **Django**: 5.2+