django-cfg 1.3.9__py3-none-any.whl → 1.3.11__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 +1 -1
- django_cfg/apps/payments/admin/networks_admin.py +12 -1
- django_cfg/apps/payments/admin/payments_admin.py +13 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/payment_service.py +265 -38
- django_cfg/apps/payments/services/providers/base.py +209 -3
- django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
- django_cfg/apps/payments/services/providers/models/base.py +25 -2
- django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
- django_cfg/apps/payments/services/providers/registry.py +5 -5
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/views/api/currencies.py +3 -0
- django_cfg/apps/payments/views/serializers/currencies.py +18 -5
- django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/registry/core.py +4 -9
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/app_agent_diagnose.py +0 -470
- django_cfg/management/commands/app_agent_generate.py +0 -342
- django_cfg/management/commands/app_agent_info.py +0 -308
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/modules/django_app_agent/__init__.py +0 -87
- django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
- django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
- django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
- django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
- django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
- django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
- django_cfg/modules/django_app_agent/core/__init__.py +0 -33
- django_cfg/modules/django_app_agent/core/config.py +0 -300
- django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
- django_cfg/modules/django_app_agent/models/__init__.py +0 -71
- django_cfg/modules/django_app_agent/models/base.py +0 -283
- django_cfg/modules/django_app_agent/models/context.py +0 -496
- django_cfg/modules/django_app_agent/models/enums.py +0 -481
- django_cfg/modules/django_app_agent/models/requests.py +0 -500
- django_cfg/modules/django_app_agent/models/responses.py +0 -585
- django_cfg/modules/django_app_agent/pytest.ini +0 -6
- django_cfg/modules/django_app_agent/services/__init__.py +0 -42
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
- django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
- django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
- django_cfg/modules/django_app_agent/services/base.py +0 -437
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
- django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
- django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
- django_cfg/modules/django_app_agent/services/report_service.py +0 -332
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
- django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
- django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
- django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
- django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
- django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
- django_cfg/modules/django_app_agent/ui/cli.py +0 -419
- django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
- django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
- django_cfg/modules/django_app_agent/utils/logging.py +0 -360
- django_cfg/modules/django_app_agent/utils/validation.py +0 -417
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,44 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Django-CFG configuration for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django_cfg.config import BaseCfgConfig
|
8
|
-
from pydantic import Field
|
9
|
-
from typing import Optional, List
|
10
|
-
|
11
|
-
|
12
|
-
class {{ app_name|pascal_case }}Config(BaseCfgConfig):
|
13
|
-
"""Configuration for {{ app_name }} application."""
|
14
|
-
|
15
|
-
# Basic settings
|
16
|
-
enabled: bool = Field(default=True, description="Enable {{ app_name }} functionality")
|
17
|
-
debug_mode: bool = Field(default=False, description="Enable debug mode for {{ app_name }}")
|
18
|
-
|
19
|
-
# Feature toggles
|
20
|
-
{% if features.api %}
|
21
|
-
api_enabled: bool = Field(default=True, description="Enable API endpoints")
|
22
|
-
api_rate_limit: int = Field(default=100, description="API rate limit per hour")
|
23
|
-
{% endif %}
|
24
|
-
|
25
|
-
{% if features.caching %}
|
26
|
-
cache_timeout: int = Field(default=300, description="Cache timeout in seconds")
|
27
|
-
cache_key_prefix: str = Field(default="{{ app_name }}", description="Cache key prefix")
|
28
|
-
{% endif %}
|
29
|
-
|
30
|
-
{% if features.notifications %}
|
31
|
-
notifications_enabled: bool = Field(default=True, description="Enable notifications")
|
32
|
-
email_notifications: bool = Field(default=False, description="Send email notifications")
|
33
|
-
{% endif %}
|
34
|
-
|
35
|
-
# Business logic settings
|
36
|
-
max_items_per_user: Optional[int] = Field(default=None, description="Maximum items per user")
|
37
|
-
allowed_file_types: List[str] = Field(
|
38
|
-
default=["jpg", "png", "pdf"],
|
39
|
-
description="Allowed file upload types"
|
40
|
-
)
|
41
|
-
|
42
|
-
class Meta:
|
43
|
-
app_name = "{{ app_name }}"
|
44
|
-
config_prefix = "{{ app_name|upper }}"
|
@@ -1,81 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Django-CFG module for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django_cfg.modules import BaseCfgModule
|
8
|
-
from django_cfg.decorators import cfg_module
|
9
|
-
from .config import {{ app_name|pascal_case }}Config
|
10
|
-
|
11
|
-
|
12
|
-
@cfg_module
|
13
|
-
class {{ app_name|pascal_case }}Module(BaseCfgModule[{{ app_name|pascal_case }}Config]):
|
14
|
-
"""Django-CFG module for {{ app_name }}."""
|
15
|
-
|
16
|
-
config_class = {{ app_name|pascal_case }}Config
|
17
|
-
|
18
|
-
def __init__(self):
|
19
|
-
"""Initialize {{ app_name }} module."""
|
20
|
-
super().__init__()
|
21
|
-
self.name = "{{ app_name }}"
|
22
|
-
self.version = "1.0.0"
|
23
|
-
self.description = "{{ description }}"
|
24
|
-
|
25
|
-
async def initialize(self):
|
26
|
-
"""Initialize module resources."""
|
27
|
-
self.logger.info(f"Initializing {{ app_name }} module")
|
28
|
-
|
29
|
-
{% if features.database_setup %}
|
30
|
-
# Setup database connections if needed
|
31
|
-
await self._setup_database()
|
32
|
-
{% endif %}
|
33
|
-
|
34
|
-
{% if features.cache_setup %}
|
35
|
-
# Setup cache if needed
|
36
|
-
await self._setup_cache()
|
37
|
-
{% endif %}
|
38
|
-
|
39
|
-
self.logger.info(f"{{ app_name|title_case }} module initialized successfully")
|
40
|
-
|
41
|
-
async def cleanup(self):
|
42
|
-
"""Cleanup module resources."""
|
43
|
-
self.logger.info(f"Cleaning up {{ app_name }} module")
|
44
|
-
|
45
|
-
{% if features.cleanup_tasks %}
|
46
|
-
# Perform cleanup tasks
|
47
|
-
await self._cleanup_resources()
|
48
|
-
{% endif %}
|
49
|
-
|
50
|
-
def get_health_status(self) -> dict:
|
51
|
-
"""Get module health status."""
|
52
|
-
return {
|
53
|
-
"status": "healthy",
|
54
|
-
"module": self.name,
|
55
|
-
"version": self.version,
|
56
|
-
"config_loaded": self.config is not None,
|
57
|
-
{% if features.database_setup %}
|
58
|
-
"database_connected": self._check_database_connection(),
|
59
|
-
{% endif %}
|
60
|
-
}
|
61
|
-
|
62
|
-
{% if features.database_setup %}
|
63
|
-
async def _setup_database(self):
|
64
|
-
"""Setup database connections."""
|
65
|
-
# Implement database setup logic
|
66
|
-
pass
|
67
|
-
{% endif %}
|
68
|
-
|
69
|
-
{% if features.cache_setup %}
|
70
|
-
async def _setup_cache(self):
|
71
|
-
"""Setup cache connections."""
|
72
|
-
# Implement cache setup logic
|
73
|
-
pass
|
74
|
-
{% endif %}
|
75
|
-
|
76
|
-
{% if features.cleanup_tasks %}
|
77
|
-
async def _cleanup_resources(self):
|
78
|
-
"""Cleanup module resources."""
|
79
|
-
# Implement cleanup logic
|
80
|
-
pass
|
81
|
-
{% endif %}
|
@@ -1,107 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Forms for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django import forms
|
8
|
-
from django.core.exceptions import ValidationError
|
9
|
-
{% if features.crispy_forms %}
|
10
|
-
from crispy_forms.helper import FormHelper
|
11
|
-
from crispy_forms.layout import Layout, Submit, Row, Column
|
12
|
-
{% endif %}
|
13
|
-
from .models import {{ app_name|pascal_case }}Model
|
14
|
-
|
15
|
-
|
16
|
-
class {{ app_name|pascal_case }}Form(forms.ModelForm):
|
17
|
-
"""Form for {{ app_name }} model."""
|
18
|
-
|
19
|
-
class Meta:
|
20
|
-
model = {{ app_name|pascal_case }}Model
|
21
|
-
fields = [
|
22
|
-
'name',
|
23
|
-
'description',
|
24
|
-
{% if features.status_tracking %}'status',{% endif %}
|
25
|
-
]
|
26
|
-
widgets = {
|
27
|
-
'description': forms.Textarea(attrs={'rows': 4}),
|
28
|
-
{% if features.status_tracking %}
|
29
|
-
'status': forms.Select(attrs={'class': 'form-select'}),
|
30
|
-
{% endif %}
|
31
|
-
}
|
32
|
-
help_texts = {
|
33
|
-
'name': 'Enter a descriptive name for this {{ app_name|singular }}',
|
34
|
-
'description': 'Provide additional details (optional)',
|
35
|
-
}
|
36
|
-
|
37
|
-
{% if features.crispy_forms %}
|
38
|
-
def __init__(self, *args, **kwargs):
|
39
|
-
super().__init__(*args, **kwargs)
|
40
|
-
self.helper = FormHelper()
|
41
|
-
self.helper.layout = Layout(
|
42
|
-
Row(
|
43
|
-
Column('name', css_class='form-group col-md-8 mb-0'),
|
44
|
-
{% if features.status_tracking %}
|
45
|
-
Column('status', css_class='form-group col-md-4 mb-0'),
|
46
|
-
{% endif %}
|
47
|
-
css_class='form-row'
|
48
|
-
),
|
49
|
-
'description',
|
50
|
-
Submit('submit', 'Save {{ app_name|title_case }}', css_class='btn btn-primary')
|
51
|
-
)
|
52
|
-
{% endif %}
|
53
|
-
|
54
|
-
def clean_name(self):
|
55
|
-
"""Validate name field."""
|
56
|
-
name = self.cleaned_data.get('name')
|
57
|
-
if name:
|
58
|
-
# Check for duplicate names (case-insensitive)
|
59
|
-
existing = {{ app_name|pascal_case }}Model.objects.filter(
|
60
|
-
name__iexact=name
|
61
|
-
)
|
62
|
-
if self.instance.pk:
|
63
|
-
existing = existing.exclude(pk=self.instance.pk)
|
64
|
-
|
65
|
-
if existing.exists():
|
66
|
-
raise ValidationError(
|
67
|
-
f'A {{ app_name|singular }} with this name already exists.'
|
68
|
-
)
|
69
|
-
|
70
|
-
return name
|
71
|
-
|
72
|
-
def clean(self):
|
73
|
-
"""Additional form validation."""
|
74
|
-
cleaned_data = super().clean()
|
75
|
-
|
76
|
-
# Add any cross-field validation here
|
77
|
-
name = cleaned_data.get('name')
|
78
|
-
description = cleaned_data.get('description')
|
79
|
-
|
80
|
-
if name and description and name.lower() in description.lower():
|
81
|
-
self.add_error('description',
|
82
|
-
'Description should not just repeat the name.')
|
83
|
-
|
84
|
-
return cleaned_data
|
85
|
-
|
86
|
-
|
87
|
-
{% if features.search_forms %}
|
88
|
-
class {{ app_name|pascal_case }}SearchForm(forms.Form):
|
89
|
-
"""Search form for {{ app_name }}."""
|
90
|
-
|
91
|
-
query = forms.CharField(
|
92
|
-
max_length=100,
|
93
|
-
required=False,
|
94
|
-
widget=forms.TextInput(attrs={
|
95
|
-
'placeholder': 'Search {{ app_name|plural }}...',
|
96
|
-
'class': 'form-control'
|
97
|
-
})
|
98
|
-
)
|
99
|
-
|
100
|
-
{% if features.status_tracking %}
|
101
|
-
status = forms.ChoiceField(
|
102
|
-
choices=[('', 'All')] + {{ app_name|pascal_case }}Model.STATUS_CHOICES,
|
103
|
-
required=False,
|
104
|
-
widget=forms.Select(attrs={'class': 'form-select'})
|
105
|
-
)
|
106
|
-
{% endif %}
|
107
|
-
{% endif %}
|
@@ -1,139 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Models for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django.db import models
|
8
|
-
from django.urls import reverse
|
9
|
-
from django.core.validators import MinLengthValidator, MaxLengthValidator
|
10
|
-
{% if app_type == 'django_cfg' %}
|
11
|
-
from django_cfg.models import BaseCfgModel
|
12
|
-
{% endif %}
|
13
|
-
{% if features.user_relations %}
|
14
|
-
from django.contrib.auth.models import User
|
15
|
-
{% endif %}
|
16
|
-
{% if features.uuid_primary_keys %}
|
17
|
-
import uuid
|
18
|
-
{% endif %}
|
19
|
-
|
20
|
-
|
21
|
-
{% if app_type == 'django_cfg' %}
|
22
|
-
class {{ app_name|pascal_case }}Model(BaseCfgModel):
|
23
|
-
{% else %}
|
24
|
-
class {{ app_name|pascal_case }}Model(models.Model):
|
25
|
-
{% endif %}
|
26
|
-
"""Main model for {{ app_name }} application."""
|
27
|
-
|
28
|
-
{% if features.uuid_primary_keys %}
|
29
|
-
id = models.UUIDField(
|
30
|
-
primary_key=True,
|
31
|
-
default=uuid.uuid4,
|
32
|
-
editable=False,
|
33
|
-
help_text="Unique identifier"
|
34
|
-
)
|
35
|
-
{% endif %}
|
36
|
-
|
37
|
-
name = models.CharField(
|
38
|
-
max_length=100,
|
39
|
-
validators=[MinLengthValidator(2)],
|
40
|
-
help_text="Name of the {{ app_name|singular|title_case }}"
|
41
|
-
)
|
42
|
-
|
43
|
-
description = models.TextField(
|
44
|
-
blank=True,
|
45
|
-
help_text="Detailed description"
|
46
|
-
)
|
47
|
-
|
48
|
-
{% if features.status_tracking %}
|
49
|
-
STATUS_CHOICES = [
|
50
|
-
('draft', 'Draft'),
|
51
|
-
('published', 'Published'),
|
52
|
-
('archived', 'Archived'),
|
53
|
-
]
|
54
|
-
|
55
|
-
status = models.CharField(
|
56
|
-
max_length=20,
|
57
|
-
choices=STATUS_CHOICES,
|
58
|
-
default='draft',
|
59
|
-
help_text="Current status"
|
60
|
-
)
|
61
|
-
{% endif %}
|
62
|
-
|
63
|
-
{% if features.user_relations %}
|
64
|
-
owner = models.ForeignKey(
|
65
|
-
User,
|
66
|
-
on_delete=models.CASCADE,
|
67
|
-
related_name="{{ app_name }}_owned",
|
68
|
-
help_text="Owner of this {{ app_name|singular }}"
|
69
|
-
)
|
70
|
-
{% endif %}
|
71
|
-
|
72
|
-
{% if not app_type == 'django_cfg' %}
|
73
|
-
created_at = models.DateTimeField(auto_now_add=True)
|
74
|
-
updated_at = models.DateTimeField(auto_now=True)
|
75
|
-
{% endif %}
|
76
|
-
|
77
|
-
class Meta:
|
78
|
-
verbose_name = "{{ app_name|singular|title_case }}"
|
79
|
-
verbose_name_plural = "{{ app_name|plural|title_case }}"
|
80
|
-
ordering = ['-created_at']
|
81
|
-
{% if features.database_indexes %}
|
82
|
-
indexes = [
|
83
|
-
models.Index(fields=['name']),
|
84
|
-
models.Index(fields=['created_at']),
|
85
|
-
{% if features.status_tracking %}
|
86
|
-
models.Index(fields=['status']),
|
87
|
-
{% endif %}
|
88
|
-
]
|
89
|
-
{% endif %}
|
90
|
-
|
91
|
-
def __str__(self):
|
92
|
-
return self.name
|
93
|
-
|
94
|
-
def get_absolute_url(self):
|
95
|
-
return reverse('{{ app_name }}:detail', kwargs={'pk': self.pk})
|
96
|
-
|
97
|
-
{% if features.custom_methods %}
|
98
|
-
def is_published(self):
|
99
|
-
"""Check if the item is published."""
|
100
|
-
{% if features.status_tracking %}
|
101
|
-
return self.status == 'published'
|
102
|
-
{% else %}
|
103
|
-
return True
|
104
|
-
{% endif %}
|
105
|
-
|
106
|
-
def get_display_name(self):
|
107
|
-
"""Get formatted display name."""
|
108
|
-
return self.name.title()
|
109
|
-
{% endif %}
|
110
|
-
|
111
|
-
|
112
|
-
{% if features.related_models %}
|
113
|
-
class {{ app_name|pascal_case }}Category(models.Model):
|
114
|
-
"""Category model for {{ app_name }}."""
|
115
|
-
|
116
|
-
name = models.CharField(max_length=50, unique=True)
|
117
|
-
slug = models.SlugField(unique=True)
|
118
|
-
description = models.TextField(blank=True)
|
119
|
-
|
120
|
-
class Meta:
|
121
|
-
verbose_name_plural = "Categories"
|
122
|
-
ordering = ['name']
|
123
|
-
|
124
|
-
def __str__(self):
|
125
|
-
return self.name
|
126
|
-
|
127
|
-
|
128
|
-
class {{ app_name|pascal_case }}Tag(models.Model):
|
129
|
-
"""Tag model for {{ app_name }}."""
|
130
|
-
|
131
|
-
name = models.CharField(max_length=30, unique=True)
|
132
|
-
color = models.CharField(max_length=7, default='#007bff') # Hex color
|
133
|
-
|
134
|
-
class Meta:
|
135
|
-
ordering = ['name']
|
136
|
-
|
137
|
-
def __str__(self):
|
138
|
-
return self.name
|
139
|
-
{% endif %}
|
@@ -1,91 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
DRF Serializers for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from rest_framework import serializers
|
8
|
-
{% if features.nested_serializers %}
|
9
|
-
from rest_framework.fields import SerializerMethodField
|
10
|
-
{% endif %}
|
11
|
-
from .models import {{ app_name|pascal_case }}Model
|
12
|
-
{% if features.related_models %}
|
13
|
-
from .models import {{ app_name|pascal_case }}Category, {{ app_name|pascal_case }}Tag
|
14
|
-
{% endif %}
|
15
|
-
|
16
|
-
|
17
|
-
class {{ app_name|pascal_case }}Serializer(serializers.ModelSerializer):
|
18
|
-
"""Serializer for {{ app_name }} model."""
|
19
|
-
|
20
|
-
{% if features.computed_fields %}
|
21
|
-
display_name = serializers.SerializerMethodField()
|
22
|
-
is_published = serializers.SerializerMethodField()
|
23
|
-
{% endif %}
|
24
|
-
|
25
|
-
class Meta:
|
26
|
-
model = {{ app_name|pascal_case }}Model
|
27
|
-
fields = [
|
28
|
-
'id',
|
29
|
-
'name',
|
30
|
-
'description',
|
31
|
-
{% if features.status_tracking %}'status',{% endif %}
|
32
|
-
{% if features.user_relations %}'owner',{% endif %}
|
33
|
-
'created_at',
|
34
|
-
'updated_at',
|
35
|
-
{% if features.computed_fields %}
|
36
|
-
'display_name',
|
37
|
-
'is_published',
|
38
|
-
{% endif %}
|
39
|
-
]
|
40
|
-
read_only_fields = ['id', 'created_at', 'updated_at']
|
41
|
-
|
42
|
-
{% if features.computed_fields %}
|
43
|
-
def get_display_name(self, obj):
|
44
|
-
"""Get formatted display name."""
|
45
|
-
return obj.get_display_name()
|
46
|
-
|
47
|
-
def get_is_published(self, obj):
|
48
|
-
"""Check if item is published."""
|
49
|
-
return obj.is_published()
|
50
|
-
{% endif %}
|
51
|
-
|
52
|
-
def validate_name(self, value):
|
53
|
-
"""Validate name field."""
|
54
|
-
if len(value.strip()) < 2:
|
55
|
-
raise serializers.ValidationError(
|
56
|
-
"Name must be at least 2 characters long."
|
57
|
-
)
|
58
|
-
return value.strip()
|
59
|
-
|
60
|
-
|
61
|
-
{% if features.list_serializers %}
|
62
|
-
class {{ app_name|pascal_case }}ListSerializer(serializers.ModelSerializer):
|
63
|
-
"""Lightweight serializer for {{ app_name }} lists."""
|
64
|
-
|
65
|
-
class Meta:
|
66
|
-
model = {{ app_name|pascal_case }}Model
|
67
|
-
fields = [
|
68
|
-
'id',
|
69
|
-
'name',
|
70
|
-
{% if features.status_tracking %}'status',{% endif %}
|
71
|
-
'created_at'
|
72
|
-
]
|
73
|
-
{% endif %}
|
74
|
-
|
75
|
-
|
76
|
-
{% if features.related_models %}
|
77
|
-
class {{ app_name|pascal_case }}CategorySerializer(serializers.ModelSerializer):
|
78
|
-
"""Serializer for {{ app_name }} categories."""
|
79
|
-
|
80
|
-
class Meta:
|
81
|
-
model = {{ app_name|pascal_case }}Category
|
82
|
-
fields = ['id', 'name', 'slug', 'description']
|
83
|
-
|
84
|
-
|
85
|
-
class {{ app_name|pascal_case }}TagSerializer(serializers.ModelSerializer):
|
86
|
-
"""Serializer for {{ app_name }} tags."""
|
87
|
-
|
88
|
-
class Meta:
|
89
|
-
model = {{ app_name|pascal_case }}Tag
|
90
|
-
fields = ['id', 'name', 'color']
|
91
|
-
{% endif %}
|
@@ -1,195 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django.test import TestCase, Client
|
8
|
-
from django.urls import reverse
|
9
|
-
{% if features.user_relations %}
|
10
|
-
from django.contrib.auth.models import User
|
11
|
-
{% endif %}
|
12
|
-
{% if features.api_tests %}
|
13
|
-
from rest_framework.test import APITestCase
|
14
|
-
from rest_framework import status
|
15
|
-
{% endif %}
|
16
|
-
from .models import {{ app_name|pascal_case }}Model
|
17
|
-
|
18
|
-
|
19
|
-
class {{ app_name|pascal_case }}ModelTest(TestCase):
|
20
|
-
"""Test cases for {{ app_name }} model."""
|
21
|
-
|
22
|
-
def setUp(self):
|
23
|
-
"""Set up test data."""
|
24
|
-
{% if features.user_relations %}
|
25
|
-
self.user = User.objects.create_user(
|
26
|
-
username='testuser',
|
27
|
-
email='test@example.com',
|
28
|
-
password='testpass123'
|
29
|
-
)
|
30
|
-
{% endif %}
|
31
|
-
|
32
|
-
self.{{ app_name|snake_case }} = {{ app_name|pascal_case }}Model.objects.create(
|
33
|
-
name='Test {{ app_name|title_case }}',
|
34
|
-
description='Test description',
|
35
|
-
{% if features.status_tracking %}status='draft',{% endif %}
|
36
|
-
{% if features.user_relations %}owner=self.user{% endif %}
|
37
|
-
)
|
38
|
-
|
39
|
-
def test_string_representation(self):
|
40
|
-
"""Test string representation of model."""
|
41
|
-
self.assertEqual(str(self.{{ app_name|snake_case }}), 'Test {{ app_name|title_case }}')
|
42
|
-
|
43
|
-
def test_get_absolute_url(self):
|
44
|
-
"""Test get_absolute_url method."""
|
45
|
-
url = self.{{ app_name|snake_case }}.get_absolute_url()
|
46
|
-
expected_url = reverse('{{ app_name }}:detail', kwargs={'pk': self.{{ app_name|snake_case }}.pk})
|
47
|
-
self.assertEqual(url, expected_url)
|
48
|
-
|
49
|
-
{% if features.custom_methods %}
|
50
|
-
def test_is_published(self):
|
51
|
-
"""Test is_published method."""
|
52
|
-
{% if features.status_tracking %}
|
53
|
-
self.assertFalse(self.{{ app_name|snake_case }}.is_published())
|
54
|
-
|
55
|
-
self.{{ app_name|snake_case }}.status = 'published'
|
56
|
-
self.{{ app_name|snake_case }}.save()
|
57
|
-
self.assertTrue(self.{{ app_name|snake_case }}.is_published())
|
58
|
-
{% else %}
|
59
|
-
self.assertTrue(self.{{ app_name|snake_case }}.is_published())
|
60
|
-
{% endif %}
|
61
|
-
|
62
|
-
def test_get_display_name(self):
|
63
|
-
"""Test get_display_name method."""
|
64
|
-
display_name = self.{{ app_name|snake_case }}.get_display_name()
|
65
|
-
self.assertEqual(display_name, 'Test {{ app_name|title_case }}')
|
66
|
-
{% endif %}
|
67
|
-
|
68
|
-
|
69
|
-
{% if features.view_tests %}
|
70
|
-
class {{ app_name|pascal_case }}ViewTest(TestCase):
|
71
|
-
"""Test cases for {{ app_name }} views."""
|
72
|
-
|
73
|
-
def setUp(self):
|
74
|
-
"""Set up test data."""
|
75
|
-
self.client = Client()
|
76
|
-
{% if features.user_relations %}
|
77
|
-
self.user = User.objects.create_user(
|
78
|
-
username='testuser',
|
79
|
-
email='test@example.com',
|
80
|
-
password='testpass123'
|
81
|
-
)
|
82
|
-
{% endif %}
|
83
|
-
|
84
|
-
self.{{ app_name|snake_case }} = {{ app_name|pascal_case }}Model.objects.create(
|
85
|
-
name='Test {{ app_name|title_case }}',
|
86
|
-
description='Test description',
|
87
|
-
{% if features.status_tracking %}status='published',{% endif %}
|
88
|
-
{% if features.user_relations %}owner=self.user{% endif %}
|
89
|
-
)
|
90
|
-
|
91
|
-
{% if features.function_based_views %}
|
92
|
-
def test_index_view(self):
|
93
|
-
"""Test index view."""
|
94
|
-
{% if features.authentication %}
|
95
|
-
self.client.login(username='testuser', password='testpass123')
|
96
|
-
{% endif %}
|
97
|
-
|
98
|
-
url = reverse('{{ app_name }}:index')
|
99
|
-
response = self.client.get(url)
|
100
|
-
|
101
|
-
self.assertEqual(response.status_code, 200)
|
102
|
-
self.assertContains(response, 'Test {{ app_name|title_case }}')
|
103
|
-
|
104
|
-
def test_detail_view(self):
|
105
|
-
"""Test detail view."""
|
106
|
-
{% if features.authentication %}
|
107
|
-
self.client.login(username='testuser', password='testpass123')
|
108
|
-
{% endif %}
|
109
|
-
|
110
|
-
url = reverse('{{ app_name }}:detail', kwargs={'pk': self.{{ app_name|snake_case }}.pk})
|
111
|
-
response = self.client.get(url)
|
112
|
-
|
113
|
-
self.assertEqual(response.status_code, 200)
|
114
|
-
self.assertContains(response, self.{{ app_name|snake_case }}.name)
|
115
|
-
{% endif %}
|
116
|
-
|
117
|
-
{% if features.class_based_views %}
|
118
|
-
def test_list_view(self):
|
119
|
-
"""Test list view."""
|
120
|
-
{% if features.authentication %}
|
121
|
-
self.client.login(username='testuser', password='testpass123')
|
122
|
-
{% endif %}
|
123
|
-
|
124
|
-
url = reverse('{{ app_name }}:list')
|
125
|
-
response = self.client.get(url)
|
126
|
-
|
127
|
-
self.assertEqual(response.status_code, 200)
|
128
|
-
self.assertContains(response, self.{{ app_name|snake_case }}.name)
|
129
|
-
{% endif %}
|
130
|
-
|
131
|
-
{% if features.crud_views %}
|
132
|
-
def test_create_view(self):
|
133
|
-
"""Test create view."""
|
134
|
-
{% if features.authentication %}
|
135
|
-
self.client.login(username='testuser', password='testpass123')
|
136
|
-
{% endif %}
|
137
|
-
|
138
|
-
url = reverse('{{ app_name }}:create')
|
139
|
-
|
140
|
-
# Test GET request
|
141
|
-
response = self.client.get(url)
|
142
|
-
self.assertEqual(response.status_code, 200)
|
143
|
-
|
144
|
-
# Test POST request
|
145
|
-
data = {
|
146
|
-
'name': 'New {{ app_name|title_case }}',
|
147
|
-
'description': 'New description',
|
148
|
-
{% if features.status_tracking %}'status': 'draft'{% endif %}
|
149
|
-
}
|
150
|
-
response = self.client.post(url, data)
|
151
|
-
self.assertEqual(response.status_code, 302) # Redirect after success
|
152
|
-
|
153
|
-
# Verify object was created
|
154
|
-
self.assertTrue(
|
155
|
-
{{ app_name|pascal_case }}Model.objects.filter(name='New {{ app_name|title_case }}').exists()
|
156
|
-
)
|
157
|
-
{% endif %}
|
158
|
-
{% endif %}
|
159
|
-
|
160
|
-
|
161
|
-
{% if features.api_tests %}
|
162
|
-
class {{ app_name|pascal_case }}APITest(APITestCase):
|
163
|
-
"""Test cases for {{ app_name }} API."""
|
164
|
-
|
165
|
-
def setUp(self):
|
166
|
-
"""Set up test data."""
|
167
|
-
{% if features.user_relations %}
|
168
|
-
self.user = User.objects.create_user(
|
169
|
-
username='testuser',
|
170
|
-
email='test@example.com',
|
171
|
-
password='testpass123'
|
172
|
-
)
|
173
|
-
{% endif %}
|
174
|
-
|
175
|
-
self.{{ app_name|snake_case }} = {{ app_name|pascal_case }}Model.objects.create(
|
176
|
-
name='Test {{ app_name|title_case }}',
|
177
|
-
description='Test description',
|
178
|
-
{% if features.status_tracking %}status='published',{% endif %}
|
179
|
-
{% if features.user_relations %}owner=self.user{% endif %}
|
180
|
-
)
|
181
|
-
|
182
|
-
def test_api_view(self):
|
183
|
-
"""Test API view."""
|
184
|
-
{% if features.authentication %}
|
185
|
-
self.client.force_authenticate(user=self.user)
|
186
|
-
{% endif %}
|
187
|
-
|
188
|
-
url = reverse('{{ app_name }}:api')
|
189
|
-
response = self.client.get(url)
|
190
|
-
|
191
|
-
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
192
|
-
self.assertTrue(response.data['success'])
|
193
|
-
self.assertEqual(len(response.data['data']), 1)
|
194
|
-
self.assertEqual(response.data['data'][0]['name'], 'Test {{ app_name|title_case }}')
|
195
|
-
{% endif %}
|
@@ -1,35 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
URL configuration for {{ app_name }} application.
|
3
|
-
|
4
|
-
{{ description }}
|
5
|
-
"""
|
6
|
-
|
7
|
-
from django.urls import path, include
|
8
|
-
{% if features.api_views %}
|
9
|
-
from django.urls import re_path
|
10
|
-
{% endif %}
|
11
|
-
from . import views
|
12
|
-
|
13
|
-
app_name = '{{ app_name }}'
|
14
|
-
|
15
|
-
urlpatterns = [
|
16
|
-
{% if features.function_based_views %}
|
17
|
-
path('', views.{{ app_name }}_index, name='index'),
|
18
|
-
path('<int:pk>/', views.{{ app_name }}_detail, name='detail'),
|
19
|
-
{% endif %}
|
20
|
-
|
21
|
-
{% if features.class_based_views %}
|
22
|
-
path('list/', views.{{ app_name|pascal_case }}ListView.as_view(), name='list'),
|
23
|
-
path('detail/<int:pk>/', views.{{ app_name|pascal_case }}DetailView.as_view(), name='detail'),
|
24
|
-
|
25
|
-
{% if features.crud_views %}
|
26
|
-
path('create/', views.{{ app_name|pascal_case }}CreateView.as_view(), name='create'),
|
27
|
-
path('update/<int:pk>/', views.{{ app_name|pascal_case }}UpdateView.as_view(), name='update'),
|
28
|
-
path('delete/<int:pk>/', views.{{ app_name|pascal_case }}DeleteView.as_view(), name='delete'),
|
29
|
-
{% endif %}
|
30
|
-
{% endif %}
|
31
|
-
|
32
|
-
{% if features.api_views %}
|
33
|
-
path('api/', views.{{ app_name|pascal_case }}APIView.as_view(), name='api'),
|
34
|
-
{% endif %}
|
35
|
-
]
|