GNXSOFT.COM
This commit is contained in:
0
gnx-react/backend/services/__init__.py
Normal file
0
gnx-react/backend/services/__init__.py
Normal file
BIN
gnx-react/backend/services/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
gnx-react/backend/services/__pycache__/admin.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/admin.cpython-312.pyc
Normal file
Binary file not shown.
BIN
gnx-react/backend/services/__pycache__/apps.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/apps.cpython-312.pyc
Normal file
Binary file not shown.
BIN
gnx-react/backend/services/__pycache__/models.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
gnx-react/backend/services/__pycache__/urls.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/urls.cpython-312.pyc
Normal file
Binary file not shown.
BIN
gnx-react/backend/services/__pycache__/views.cpython-312.pyc
Normal file
BIN
gnx-react/backend/services/__pycache__/views.cpython-312.pyc
Normal file
Binary file not shown.
114
gnx-react/backend/services/admin.py
Normal file
114
gnx-react/backend/services/admin.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from .models import Service, ServiceFeature, ServiceExpertise, ServiceCategory
|
||||
|
||||
|
||||
class ServiceFeatureInline(admin.TabularInline):
|
||||
model = ServiceFeature
|
||||
extra = 0
|
||||
fields = ['title', 'description', 'icon', 'display_order']
|
||||
ordering = ['display_order']
|
||||
|
||||
|
||||
class ServiceExpertiseInline(admin.TabularInline):
|
||||
model = ServiceExpertise
|
||||
extra = 0
|
||||
fields = ['title', 'description', 'icon', 'display_order']
|
||||
ordering = ['display_order']
|
||||
|
||||
|
||||
@admin.register(Service)
|
||||
class ServiceAdmin(admin.ModelAdmin):
|
||||
list_display = ['title', 'slug', 'category', 'price', 'duration', 'deliverables_preview', 'featured', 'display_order', 'is_active', 'created_at']
|
||||
list_filter = ['featured', 'is_active', 'category', 'created_at']
|
||||
search_fields = ['title', 'description', 'slug', 'short_description', 'technologies', 'deliverables']
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
ordering = ['display_order', 'title']
|
||||
inlines = [ServiceFeatureInline, ServiceExpertiseInline]
|
||||
actions = ['mark_as_featured', 'mark_as_not_featured']
|
||||
|
||||
fieldsets = (
|
||||
('Basic Information', {
|
||||
'fields': ('title', 'slug', 'description', 'short_description', 'icon', 'image', 'image_url')
|
||||
}),
|
||||
('Category & Classification', {
|
||||
'fields': ('category', 'featured', 'display_order', 'is_active')
|
||||
}),
|
||||
('Project Details', {
|
||||
'fields': ('duration', 'deliverables', 'technologies', 'process_steps'),
|
||||
'description': 'Define what the client will receive and the project timeline'
|
||||
}),
|
||||
('Section Descriptions', {
|
||||
'fields': ('features_description', 'deliverables_description', 'process_description', 'why_choose_description', 'expertise_description'),
|
||||
'description': 'Customize descriptions for each section on the service detail page',
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
('Pricing', {
|
||||
'fields': ('price',)
|
||||
}),
|
||||
('Timestamps', {
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
form = super().get_form(request, obj, **kwargs)
|
||||
# Make deliverables field more prominent
|
||||
if 'deliverables' in form.base_fields:
|
||||
form.base_fields['deliverables'].widget.attrs.update({
|
||||
'rows': 4,
|
||||
'cols': 80,
|
||||
'placeholder': 'Enter what the client will receive (e.g., Complete web application, Admin dashboard, Documentation, Testing, Deployment)'
|
||||
})
|
||||
return form
|
||||
|
||||
def deliverables_preview(self, obj):
|
||||
"""Display a preview of deliverables in the list view"""
|
||||
if obj.deliverables:
|
||||
# Show first 50 characters of deliverables
|
||||
preview = obj.deliverables[:50]
|
||||
if len(obj.deliverables) > 50:
|
||||
preview += "..."
|
||||
return format_html('<span title="{}">{}</span>', obj.deliverables, preview)
|
||||
return format_html('<span style="color: #999;">No deliverables defined</span>')
|
||||
deliverables_preview.short_description = 'Deliverables Preview'
|
||||
|
||||
def mark_as_featured(self, request, queryset):
|
||||
"""Admin action to mark services as featured"""
|
||||
updated = queryset.update(featured=True)
|
||||
self.message_user(request, f'{updated} service(s) marked as featured.')
|
||||
mark_as_featured.short_description = "Mark selected services as featured"
|
||||
|
||||
def mark_as_not_featured(self, request, queryset):
|
||||
"""Admin action to mark services as not featured"""
|
||||
updated = queryset.update(featured=False)
|
||||
self.message_user(request, f'{updated} service(s) marked as not featured.')
|
||||
mark_as_not_featured.short_description = "Mark selected services as not featured"
|
||||
|
||||
|
||||
@admin.register(ServiceFeature)
|
||||
class ServiceFeatureAdmin(admin.ModelAdmin):
|
||||
list_display = ['title', 'service', 'display_order']
|
||||
list_filter = ['service', 'display_order']
|
||||
search_fields = ['title', 'description', 'service__title']
|
||||
ordering = ['service', 'display_order']
|
||||
|
||||
|
||||
@admin.register(ServiceExpertise)
|
||||
class ServiceExpertiseAdmin(admin.ModelAdmin):
|
||||
list_display = ['title', 'service', 'display_order']
|
||||
list_filter = ['service', 'display_order']
|
||||
search_fields = ['title', 'description', 'service__title']
|
||||
ordering = ['service', 'display_order']
|
||||
|
||||
|
||||
@admin.register(ServiceCategory)
|
||||
class ServiceCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'slug', 'display_order', 'is_active']
|
||||
list_filter = ['is_active', 'display_order']
|
||||
search_fields = ['name', 'description', 'slug']
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
ordering = ['display_order', 'name']
|
||||
7
gnx-react/backend/services/apps.py
Normal file
7
gnx-react/backend/services/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ServicesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'services'
|
||||
verbose_name = 'Services'
|
||||
0
gnx-react/backend/services/management/__init__.py
Normal file
0
gnx-react/backend/services/management/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,230 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from services.models import Service, ServiceCategory, ServiceFeature
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Import completely fresh service data'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
# Clear existing data
|
||||
ServiceFeature.objects.all().delete()
|
||||
Service.objects.all().delete()
|
||||
ServiceCategory.objects.all().delete()
|
||||
|
||||
self.stdout.write(self.style.WARNING('Cleared existing service data'))
|
||||
|
||||
# Create fresh categories
|
||||
categories = {
|
||||
'web-development': {
|
||||
'name': 'Web Development',
|
||||
'description': 'Custom web applications and modern websites',
|
||||
'display_order': 1
|
||||
},
|
||||
'mobile-development': {
|
||||
'name': 'Mobile Development',
|
||||
'description': 'Native and cross-platform mobile applications',
|
||||
'display_order': 2
|
||||
},
|
||||
'api-development': {
|
||||
'name': 'API Development',
|
||||
'description': 'RESTful APIs and microservices architecture',
|
||||
'display_order': 3
|
||||
},
|
||||
'cloud-services': {
|
||||
'name': 'Cloud Services',
|
||||
'description': 'Cloud migration and infrastructure management',
|
||||
'display_order': 4
|
||||
},
|
||||
'ai-ml': {
|
||||
'name': 'AI & Machine Learning',
|
||||
'description': 'Artificial intelligence and machine learning solutions',
|
||||
'display_order': 5
|
||||
}
|
||||
}
|
||||
|
||||
created_categories = {}
|
||||
for slug, data in categories.items():
|
||||
category, created = ServiceCategory.objects.get_or_create(
|
||||
slug=slug,
|
||||
defaults={
|
||||
'name': data['name'],
|
||||
'description': data['description'],
|
||||
'display_order': data['display_order'],
|
||||
'is_active': True
|
||||
}
|
||||
)
|
||||
created_categories[slug] = category
|
||||
self.stdout.write(f'Created category: {category.name}')
|
||||
|
||||
# Create fresh services with detailed data
|
||||
services_data = [
|
||||
{
|
||||
'title': 'Enterprise Web Application',
|
||||
'description': 'Build powerful, scalable web applications tailored to your business needs. Our expert developers use modern frameworks and technologies to create solutions that drive growth and efficiency.',
|
||||
'short_description': 'Custom enterprise web applications with modern architecture and scalable infrastructure.',
|
||||
'slug': 'enterprise-web-application',
|
||||
'icon': 'code',
|
||||
'price': '25000.00',
|
||||
'category_slug': 'web-development',
|
||||
'duration': '8-12 weeks',
|
||||
'deliverables': 'Complete Web Application, Admin Dashboard, User Authentication System, Database Design, API Integration, Responsive Design, Security Implementation, Testing Suite, Deployment Setup, Documentation, Training Materials, 3 Months Support',
|
||||
'technologies': 'React, Next.js, TypeScript, Node.js, PostgreSQL, Redis, AWS, Docker, Kubernetes, Jest, Cypress',
|
||||
'process_steps': 'Discovery & Requirements, UI/UX Design, Architecture Planning, Backend Development, Frontend Development, API Development, Database Setup, Security Implementation, Testing & QA, Deployment, Training, Launch Support',
|
||||
'featured': True,
|
||||
'display_order': 1,
|
||||
'features': [
|
||||
{'title': 'Scalable Architecture', 'description': 'Built with microservices and cloud-native architecture', 'icon': 'cloud'},
|
||||
{'title': 'Advanced Security', 'description': 'Enterprise-grade security with authentication and authorization', 'icon': 'shield'},
|
||||
{'title': 'Real-time Features', 'description': 'WebSocket integration for real-time updates and notifications', 'icon': 'bolt'},
|
||||
{'title': 'Mobile Responsive', 'description': 'Fully responsive design that works on all devices', 'icon': 'mobile'},
|
||||
{'title': 'Performance Optimized', 'description': 'Optimized for speed and performance with caching strategies', 'icon': 'gauge'},
|
||||
{'title': 'Analytics Integration', 'description': 'Built-in analytics and reporting capabilities', 'icon': 'chart-bar'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title': 'Cross-Platform Mobile App',
|
||||
'description': 'Create stunning mobile applications for iOS and Android platforms. We deliver native and cross-platform solutions that provide exceptional user experiences and drive engagement.',
|
||||
'short_description': 'Native and cross-platform mobile applications with modern UI/UX design.',
|
||||
'slug': 'cross-platform-mobile-app',
|
||||
'icon': 'mobile',
|
||||
'price': '35000.00',
|
||||
'category_slug': 'mobile-development',
|
||||
'duration': '12-16 weeks',
|
||||
'deliverables': 'iOS Mobile App, Android Mobile App, Admin Panel, Backend API, Push Notifications, Offline Support, App Store Submission, Google Play Submission, User Documentation, Admin Guide, Testing Suite, 6 Months Support',
|
||||
'technologies': 'React Native, TypeScript, Node.js, MongoDB, Firebase, AWS, App Store Connect, Google Play Console, Jest, Detox',
|
||||
'process_steps': 'Market Research, UI/UX Design, Prototyping, Backend Development, Mobile App Development, API Integration, Testing, App Store Optimization, Submission Process, Launch Strategy, Post-launch Support',
|
||||
'featured': True,
|
||||
'display_order': 2,
|
||||
'features': [
|
||||
{'title': 'Cross-Platform', 'description': 'Single codebase for both iOS and Android platforms', 'icon': 'mobile'},
|
||||
{'title': 'Native Performance', 'description': 'Optimized performance using native components and modules', 'icon': 'gauge'},
|
||||
{'title': 'Offline Support', 'description': 'Full offline functionality with data synchronization', 'icon': 'wifi'},
|
||||
{'title': 'Push Notifications', 'description': 'Real-time push notifications for user engagement', 'icon': 'bell'},
|
||||
{'title': 'App Store Ready', 'description': 'Complete app store submission and approval process', 'icon': 'store'},
|
||||
{'title': 'Analytics Dashboard', 'description': 'Comprehensive analytics and user behavior tracking', 'icon': 'chart-line'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title': 'RESTful API Development',
|
||||
'description': 'Build robust, scalable APIs that power your applications and enable seamless integration with third-party services. Our APIs are designed for performance, security, and maintainability.',
|
||||
'short_description': 'Enterprise-grade RESTful APIs with comprehensive documentation and security.',
|
||||
'slug': 'restful-api-development',
|
||||
'icon': 'api',
|
||||
'price': '15000.00',
|
||||
'category_slug': 'api-development',
|
||||
'duration': '4-6 weeks',
|
||||
'deliverables': 'RESTful API, API Documentation, Authentication System, Rate Limiting, API Testing Suite, Postman Collection, SDK Development, Integration Examples, Performance Monitoring, Security Audit, Deployment Guide, 3 Months Support',
|
||||
'technologies': 'Node.js, Express, TypeScript, PostgreSQL, Redis, JWT, Swagger, Postman, Jest, AWS API Gateway, Docker',
|
||||
'process_steps': 'API Planning, Database Design, Authentication Setup, Endpoint Development, Documentation, Testing, Security Review, Performance Optimization, Deployment, Integration Testing, Monitoring Setup',
|
||||
'featured': False,
|
||||
'display_order': 3,
|
||||
'features': [
|
||||
{'title': 'RESTful Design', 'description': 'Clean, intuitive API design following REST principles', 'icon': 'code'},
|
||||
{'title': 'Comprehensive Documentation', 'description': 'Interactive API documentation with examples', 'icon': 'book'},
|
||||
{'title': 'Authentication & Security', 'description': 'JWT-based authentication with rate limiting', 'icon': 'shield'},
|
||||
{'title': 'Performance Optimized', 'description': 'Caching and optimization for high performance', 'icon': 'gauge'},
|
||||
{'title': 'SDK Support', 'description': 'Client SDKs for easy integration', 'icon': 'puzzle-piece'},
|
||||
{'title': 'Monitoring & Analytics', 'description': 'Built-in monitoring and usage analytics', 'icon': 'chart-bar'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title': 'Cloud Migration & DevOps',
|
||||
'description': 'Migrate your existing infrastructure to the cloud with minimal downtime. We help you leverage cloud technologies for improved scalability, security, and cost efficiency.',
|
||||
'short_description': 'Complete cloud migration with DevOps automation and monitoring.',
|
||||
'slug': 'cloud-migration-devops',
|
||||
'icon': 'cloud',
|
||||
'price': '45000.00',
|
||||
'category_slug': 'cloud-services',
|
||||
'duration': '16-20 weeks',
|
||||
'deliverables': 'Cloud Infrastructure Setup, Application Migration, CI/CD Pipeline, Monitoring Setup, Security Configuration, Backup Strategy, Disaster Recovery Plan, Cost Optimization, Performance Tuning, Documentation, Training, 6 Months Support',
|
||||
'technologies': 'AWS, Azure, Google Cloud, Docker, Kubernetes, Terraform, Jenkins, GitLab CI, Prometheus, Grafana, ELK Stack',
|
||||
'process_steps': 'Infrastructure Assessment, Migration Planning, Security Audit, Infrastructure Setup, Application Migration, CI/CD Implementation, Monitoring Setup, Testing, Go-live, Optimization, Documentation, Training',
|
||||
'featured': True,
|
||||
'display_order': 4,
|
||||
'features': [
|
||||
{'title': 'Zero Downtime Migration', 'description': 'Seamless migration with minimal service interruption', 'icon': 'clock'},
|
||||
{'title': 'Cost Optimization', 'description': 'Optimized cloud resources for maximum cost efficiency', 'icon': 'dollar-sign'},
|
||||
{'title': 'Security First', 'description': 'Enhanced security with cloud-native security features', 'icon': 'shield'},
|
||||
{'title': 'Automated DevOps', 'description': 'Complete CI/CD pipeline with automated deployments', 'icon': 'cogs'},
|
||||
{'title': 'Monitoring & Alerting', 'description': 'Comprehensive monitoring and alerting system', 'icon': 'bell'},
|
||||
{'title': 'Scalability', 'description': 'Auto-scaling infrastructure for handling traffic spikes', 'icon': 'expand'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title': 'AI-Powered Business Intelligence',
|
||||
'description': 'Transform your business data into actionable insights with AI-powered analytics and machine learning solutions. Make data-driven decisions with advanced predictive analytics.',
|
||||
'short_description': 'AI-powered business intelligence and predictive analytics platform.',
|
||||
'slug': 'ai-powered-business-intelligence',
|
||||
'icon': 'brain',
|
||||
'price': '55000.00',
|
||||
'category_slug': 'ai-ml',
|
||||
'duration': '20-24 weeks',
|
||||
'deliverables': 'AI Analytics Platform, Machine Learning Models, Data Pipeline, Dashboard Development, Predictive Analytics, Report Generation, API Integration, Data Visualization, Model Training, Performance Monitoring, Documentation, 12 Months Support',
|
||||
'technologies': 'Python, TensorFlow, PyTorch, Pandas, NumPy, Scikit-learn, React, D3.js, PostgreSQL, Redis, AWS SageMaker, Docker',
|
||||
'process_steps': 'Data Analysis, Model Selection, Data Pipeline Development, Model Training, Dashboard Development, API Development, Testing, Deployment, Performance Monitoring, Optimization, Documentation, Training',
|
||||
'featured': True,
|
||||
'display_order': 5,
|
||||
'features': [
|
||||
{'title': 'Predictive Analytics', 'description': 'Advanced ML models for business forecasting', 'icon': 'chart-line'},
|
||||
{'title': 'Real-time Insights', 'description': 'Live data processing and real-time analytics', 'icon': 'bolt'},
|
||||
{'title': 'Interactive Dashboards', 'description': 'Beautiful, interactive data visualization', 'icon': 'chart-bar'},
|
||||
{'title': 'Automated Reports', 'description': 'Automated report generation and distribution', 'icon': 'file-alt'},
|
||||
{'title': 'Data Integration', 'description': 'Seamless integration with existing data sources', 'icon': 'plug'},
|
||||
{'title': 'Scalable Architecture', 'description': 'Cloud-native architecture for handling big data', 'icon': 'cloud'}
|
||||
]
|
||||
},
|
||||
{
|
||||
'title': 'E-commerce Platform',
|
||||
'description': 'Build a complete e-commerce solution with modern features, secure payment processing, and advanced analytics. Create an online store that converts visitors into customers.',
|
||||
'short_description': 'Complete e-commerce platform with payment processing and analytics.',
|
||||
'slug': 'ecommerce-platform',
|
||||
'icon': 'shopping-cart',
|
||||
'price': '30000.00',
|
||||
'category_slug': 'web-development',
|
||||
'duration': '10-14 weeks',
|
||||
'deliverables': 'E-commerce Website, Admin Dashboard, Payment Integration, Inventory Management, Order Management, Customer Portal, Analytics Dashboard, SEO Optimization, Mobile App, Testing Suite, Documentation, 6 Months Support',
|
||||
'technologies': 'React, Next.js, Node.js, PostgreSQL, Stripe, PayPal, AWS, Redis, Elasticsearch, Jest, Cypress',
|
||||
'process_steps': 'Requirements Analysis, UI/UX Design, Database Design, Backend Development, Frontend Development, Payment Integration, Testing, SEO Optimization, Performance Tuning, Launch, Marketing Setup, Support',
|
||||
'featured': False,
|
||||
'display_order': 6,
|
||||
'features': [
|
||||
{'title': 'Secure Payments', 'description': 'Multiple payment gateways with PCI compliance', 'icon': 'credit-card'},
|
||||
{'title': 'Inventory Management', 'description': 'Advanced inventory tracking and management', 'icon': 'box'},
|
||||
{'title': 'Customer Analytics', 'description': 'Detailed customer behavior and sales analytics', 'icon': 'chart-bar'},
|
||||
{'title': 'Mobile Optimized', 'description': 'Fully responsive design for mobile shopping', 'icon': 'mobile'},
|
||||
{'title': 'SEO Ready', 'description': 'Built-in SEO optimization for better visibility', 'icon': 'search'},
|
||||
{'title': 'Multi-vendor Support', 'description': 'Support for multiple vendors and marketplace', 'icon': 'store'}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
for service_data in services_data:
|
||||
# Extract features before creating service
|
||||
features = service_data.pop('features', [])
|
||||
category_slug = service_data.pop('category_slug')
|
||||
|
||||
# Create service
|
||||
service = Service.objects.create(
|
||||
category=created_categories[category_slug],
|
||||
**service_data
|
||||
)
|
||||
|
||||
self.stdout.write(f'Created service: {service.title}')
|
||||
|
||||
# Create features for the service
|
||||
for feature_data in features:
|
||||
ServiceFeature.objects.create(
|
||||
service=service,
|
||||
**feature_data
|
||||
)
|
||||
|
||||
self.stdout.write(f' Added {len(features)} features')
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Successfully imported fresh service data!')
|
||||
)
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f'Created {Service.objects.count()} services with {ServiceFeature.objects.count()} features')
|
||||
)
|
||||
@@ -0,0 +1,158 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from services.models import Service, ServiceExpertise
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Populate expertise items for existing services'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
# Expertise data for each service
|
||||
expertise_data = {
|
||||
'enterprise-web-application': [
|
||||
{
|
||||
'title': 'Expert Development Team',
|
||||
'description': 'Our experienced team specializes in enterprise web applications with years of industry expertise. We bring deep knowledge and proven methodologies to every project.',
|
||||
'icon': 'users',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Modern Technology Stack',
|
||||
'description': 'We use cutting-edge technologies and frameworks to deliver scalable, secure, and future-proof web applications.',
|
||||
'icon': 'code',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Proven Track Record',
|
||||
'description': 'We have successfully delivered enterprise web applications to numerous clients, helping them achieve their business goals and drive growth.',
|
||||
'icon': 'chart-line',
|
||||
'display_order': 3
|
||||
}
|
||||
],
|
||||
'cross-platform-mobile-app': [
|
||||
{
|
||||
'title': 'Mobile Development Experts',
|
||||
'description': 'Our specialized mobile development team has extensive experience in both native and cross-platform app development.',
|
||||
'icon': 'mobile',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Cross-Platform Mastery',
|
||||
'description': 'We excel in React Native and Flutter development, delivering high-performance apps for both iOS and Android platforms.',
|
||||
'icon': 'layer-group',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'App Store Success',
|
||||
'description': 'We have successfully launched numerous apps in both Apple App Store and Google Play Store with excellent ratings.',
|
||||
'icon': 'store',
|
||||
'display_order': 3
|
||||
}
|
||||
],
|
||||
'restful-api-development': [
|
||||
{
|
||||
'title': 'API Architecture Experts',
|
||||
'description': 'Our team specializes in designing and building robust, scalable APIs that power modern applications.',
|
||||
'icon': 'network-wired',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Performance Optimization',
|
||||
'description': 'We create high-performance APIs with caching, rate limiting, and optimization techniques for maximum efficiency.',
|
||||
'icon': 'gauge',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Comprehensive Documentation',
|
||||
'description': 'We provide detailed API documentation with interactive examples and SDKs for easy integration.',
|
||||
'icon': 'book',
|
||||
'display_order': 3
|
||||
}
|
||||
],
|
||||
'cloud-migration-devops': [
|
||||
{
|
||||
'title': 'Cloud Migration Specialists',
|
||||
'description': 'Our certified cloud engineers have extensive experience in migrating complex infrastructures with minimal downtime.',
|
||||
'icon': 'cloud',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'DevOps Automation',
|
||||
'description': 'We implement complete CI/CD pipelines and automation workflows to streamline your development process.',
|
||||
'icon': 'cogs',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Cost Optimization',
|
||||
'description': 'We help optimize your cloud costs while maintaining performance and reliability standards.',
|
||||
'icon': 'dollar-sign',
|
||||
'display_order': 3
|
||||
}
|
||||
],
|
||||
'ai-powered-business-intelligence': [
|
||||
{
|
||||
'title': 'AI & ML Specialists',
|
||||
'description': 'Our data scientists and AI engineers have deep expertise in machine learning and business intelligence solutions.',
|
||||
'icon': 'brain',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Advanced Analytics',
|
||||
'description': 'We create sophisticated analytics platforms that transform raw data into actionable business insights.',
|
||||
'icon': 'chart-bar',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Predictive Modeling',
|
||||
'description': 'Our team builds advanced predictive models that help businesses make data-driven decisions.',
|
||||
'icon': 'crystal-ball',
|
||||
'display_order': 3
|
||||
}
|
||||
],
|
||||
'ecommerce-platform': [
|
||||
{
|
||||
'title': 'E-commerce Specialists',
|
||||
'description': 'Our team has extensive experience in building high-converting e-commerce platforms for various industries.',
|
||||
'icon': 'shopping-cart',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Payment Integration',
|
||||
'description': 'We integrate secure payment gateways and ensure PCI compliance for safe transactions.',
|
||||
'icon': 'credit-card',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'SEO & Performance',
|
||||
'description': 'We optimize e-commerce sites for search engines and performance to maximize conversions.',
|
||||
'icon': 'search',
|
||||
'display_order': 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
for service_slug, expertise_items in expertise_data.items():
|
||||
try:
|
||||
service = Service.objects.get(slug=service_slug)
|
||||
|
||||
# Clear existing expertise items
|
||||
ServiceExpertise.objects.filter(service=service).delete()
|
||||
|
||||
# Create new expertise items
|
||||
for expertise_data in expertise_items:
|
||||
ServiceExpertise.objects.create(
|
||||
service=service,
|
||||
**expertise_data
|
||||
)
|
||||
|
||||
self.stdout.write(f'Added expertise items for: {service.title}')
|
||||
|
||||
except Service.DoesNotExist:
|
||||
self.stdout.write(
|
||||
self.style.WARNING(f'Service with slug "{service_slug}" not found')
|
||||
)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Successfully populated expertise items!')
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from services.models import Service
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Populate section descriptions for existing services'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
# Section descriptions for each service
|
||||
descriptions_data = {
|
||||
'enterprise-web-application': {
|
||||
'features_description': 'Our enterprise web applications are built with cutting-edge technologies and industry best practices to deliver exceptional performance and user experience.',
|
||||
'deliverables_description': 'Get a complete enterprise-grade web application with advanced features, comprehensive documentation, and ongoing support.',
|
||||
'process_description': 'We follow a structured 8-step development process that ensures quality, efficiency, and timely delivery of your enterprise web application.',
|
||||
'why_choose_description': 'Why choose our Enterprise Web Application service?',
|
||||
'expertise_description': 'Our team brings years of experience in enterprise web development, combining technical expertise with business understanding.'
|
||||
},
|
||||
'cross-platform-mobile-app': {
|
||||
'features_description': 'Our cross-platform mobile apps deliver native-like performance while reducing development time and costs significantly.',
|
||||
'deliverables_description': 'Receive a fully functional mobile app for both iOS and Android platforms, complete with app store deployment support.',
|
||||
'process_description': 'Our proven mobile development methodology ensures your app meets all platform requirements and user expectations.',
|
||||
'why_choose_description': 'Why choose our Cross-Platform Mobile App service?',
|
||||
'expertise_description': 'We specialize in React Native and Flutter development, delivering high-performance apps that work seamlessly across platforms.'
|
||||
},
|
||||
'restful-api-development': {
|
||||
'features_description': 'Our RESTful APIs are designed for scalability, security, and ease of integration with comprehensive documentation.',
|
||||
'deliverables_description': 'Get a robust, well-documented API with SDKs, testing tools, and comprehensive integration support.',
|
||||
'process_description': 'We follow API-first development principles to ensure your API is reliable, scalable, and developer-friendly.',
|
||||
'why_choose_description': 'Why choose our RESTful API Development service?',
|
||||
'expertise_description': 'Our API specialists have extensive experience in designing and building enterprise-grade APIs for various industries.'
|
||||
},
|
||||
'cloud-migration-devops': {
|
||||
'features_description': 'Our cloud migration and DevOps services ensure seamless transition to the cloud with zero downtime and improved performance.',
|
||||
'deliverables_description': 'Complete cloud migration with automated CI/CD pipelines, monitoring, and cost optimization strategies.',
|
||||
'process_description': 'Our systematic approach to cloud migration minimizes risks while maximizing the benefits of cloud infrastructure.',
|
||||
'why_choose_description': 'Why choose our Cloud Migration & DevOps service?',
|
||||
'expertise_description': 'We are certified cloud architects with proven experience in migrating complex infrastructures and implementing DevOps practices.'
|
||||
},
|
||||
'ai-powered-business-intelligence': {
|
||||
'features_description': 'Transform your data into actionable insights with our AI-powered business intelligence solutions.',
|
||||
'deliverables_description': 'Get a complete BI platform with AI-powered analytics, predictive models, and interactive dashboards.',
|
||||
'process_description': 'Our data science methodology ensures your BI solution provides accurate insights and drives informed decision-making.',
|
||||
'why_choose_description': 'Why choose our AI-Powered Business Intelligence service?',
|
||||
'expertise_description': 'Our data scientists and AI engineers specialize in creating intelligent solutions that turn data into competitive advantage.'
|
||||
},
|
||||
'ecommerce-platform': {
|
||||
'features_description': 'Build a high-converting e-commerce platform with advanced features, secure payments, and mobile optimization.',
|
||||
'deliverables_description': 'Get a complete e-commerce solution with payment integration, inventory management, and marketing tools.',
|
||||
'process_description': 'We follow e-commerce best practices to ensure your platform drives sales and provides excellent customer experience.',
|
||||
'why_choose_description': 'Why choose our E-commerce Platform service?',
|
||||
'expertise_description': 'Our e-commerce specialists have built successful online stores for businesses across various industries and sizes.'
|
||||
}
|
||||
}
|
||||
|
||||
for service_slug, descriptions in descriptions_data.items():
|
||||
try:
|
||||
service = Service.objects.get(slug=service_slug)
|
||||
|
||||
# Update service with new descriptions
|
||||
for field, value in descriptions.items():
|
||||
setattr(service, field, value)
|
||||
|
||||
service.save()
|
||||
self.stdout.write(f'Updated section descriptions for: {service.title}')
|
||||
|
||||
except Service.DoesNotExist:
|
||||
self.stdout.write(
|
||||
self.style.WARNING(f'Service with slug "{service_slug}" not found')
|
||||
)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Successfully populated section descriptions!')
|
||||
)
|
||||
@@ -0,0 +1,221 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from services.models import Service, ServiceCategory, ServiceFeature
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Populate the database with sample services'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
with transaction.atomic():
|
||||
# Create categories
|
||||
web_dev_category, created = ServiceCategory.objects.get_or_create(
|
||||
slug='web-development',
|
||||
defaults={
|
||||
'name': 'Web Development',
|
||||
'description': 'Custom web applications and websites',
|
||||
'display_order': 1,
|
||||
'is_active': True
|
||||
}
|
||||
)
|
||||
|
||||
mobile_category, created = ServiceCategory.objects.get_or_create(
|
||||
slug='mobile-development',
|
||||
defaults={
|
||||
'name': 'Mobile Development',
|
||||
'description': 'Native and cross-platform mobile apps',
|
||||
'display_order': 2,
|
||||
'is_active': True
|
||||
}
|
||||
)
|
||||
|
||||
api_category, created = ServiceCategory.objects.get_or_create(
|
||||
slug='api-development',
|
||||
defaults={
|
||||
'name': 'API Development',
|
||||
'description': 'RESTful APIs and microservices',
|
||||
'display_order': 3,
|
||||
'is_active': True
|
||||
}
|
||||
)
|
||||
|
||||
# Create services
|
||||
services_data = [
|
||||
{
|
||||
'title': 'Custom Web Application Development',
|
||||
'description': 'Build powerful, scalable web applications tailored to your business needs. Our expert developers use modern frameworks and technologies to create solutions that drive growth and efficiency.',
|
||||
'short_description': 'Custom web applications built with modern technologies for optimal performance and scalability.',
|
||||
'slug': 'custom-web-application-development',
|
||||
'icon': 'code',
|
||||
'price': '5000.00',
|
||||
'category': web_dev_category,
|
||||
'duration': '4-8 weeks',
|
||||
'deliverables': 'Responsive Web Application, Admin Dashboard, User Authentication, Database Design, API Integration, Testing & Deployment',
|
||||
'technologies': 'React, Next.js, Node.js, PostgreSQL, AWS, Docker',
|
||||
'process_steps': 'Requirements Analysis, System Design, Development, Testing, Deployment, Training',
|
||||
'featured': True,
|
||||
'display_order': 1,
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'title': 'Mobile App Development',
|
||||
'description': 'Create stunning mobile applications for iOS and Android platforms. We deliver native and cross-platform solutions that provide exceptional user experiences and drive engagement.',
|
||||
'short_description': 'Native and cross-platform mobile applications for iOS and Android.',
|
||||
'slug': 'mobile-app-development',
|
||||
'icon': 'mobile',
|
||||
'price': '8000.00',
|
||||
'category': mobile_category,
|
||||
'duration': '6-12 weeks',
|
||||
'deliverables': 'Native Mobile App, Cross-platform App, App Store Deployment, Push Notifications, Offline Support, Analytics Integration',
|
||||
'technologies': 'React Native, Flutter, Swift, Kotlin, Firebase, App Store Connect',
|
||||
'process_steps': 'UI/UX Design, Development, Testing, App Store Submission, Launch Support',
|
||||
'featured': True,
|
||||
'display_order': 2,
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'title': 'API Development & Integration',
|
||||
'description': 'Build robust, scalable APIs that power your applications and enable seamless integration with third-party services. Our APIs are designed for performance, security, and maintainability.',
|
||||
'short_description': 'RESTful APIs and microservices for seamless system integration.',
|
||||
'slug': 'api-development-integration',
|
||||
'icon': 'api',
|
||||
'price': '3000.00',
|
||||
'category': api_category,
|
||||
'duration': '2-4 weeks',
|
||||
'deliverables': 'RESTful API, API Documentation, Authentication System, Rate Limiting, Monitoring, Integration Support',
|
||||
'technologies': 'Node.js, Python, FastAPI, PostgreSQL, Redis, AWS API Gateway',
|
||||
'process_steps': 'API Planning, Development, Documentation, Testing, Deployment, Integration',
|
||||
'featured': False,
|
||||
'display_order': 3,
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'title': 'Cloud Migration Services',
|
||||
'description': 'Migrate your existing infrastructure to the cloud with minimal downtime. We help you leverage cloud technologies for improved scalability, security, and cost efficiency.',
|
||||
'short_description': 'Seamless migration to cloud platforms with enhanced security and scalability.',
|
||||
'slug': 'cloud-migration-services',
|
||||
'icon': 'cloud',
|
||||
'price': '10000.00',
|
||||
'category': web_dev_category,
|
||||
'duration': '8-16 weeks',
|
||||
'deliverables': 'Cloud Infrastructure Setup, Data Migration, Security Configuration, Monitoring Setup, Training, Ongoing Support',
|
||||
'technologies': 'AWS, Azure, Google Cloud, Docker, Kubernetes, Terraform',
|
||||
'process_steps': 'Assessment, Migration Planning, Implementation, Testing, Optimization, Support',
|
||||
'featured': True,
|
||||
'display_order': 4,
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
for service_data in services_data:
|
||||
service, created = Service.objects.get_or_create(
|
||||
slug=service_data['slug'],
|
||||
defaults=service_data
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f'Created service: {service.title}')
|
||||
)
|
||||
|
||||
# Add features for each service
|
||||
if service.slug == 'custom-web-application-development':
|
||||
features = [
|
||||
{
|
||||
'title': 'Responsive Design',
|
||||
'description': 'Mobile-first design that works perfectly on all devices',
|
||||
'icon': 'mobile',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Performance Optimization',
|
||||
'description': 'Fast loading times and optimized user experience',
|
||||
'icon': 'bolt',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Security Features',
|
||||
'description': 'Built-in security measures to protect your data',
|
||||
'icon': 'shield',
|
||||
'display_order': 3
|
||||
}
|
||||
]
|
||||
elif service.slug == 'mobile-app-development':
|
||||
features = [
|
||||
{
|
||||
'title': 'Cross-Platform',
|
||||
'description': 'Single codebase for both iOS and Android',
|
||||
'icon': 'mobile',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Native Performance',
|
||||
'description': 'Optimized performance using native components',
|
||||
'icon': 'gauge',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'App Store Ready',
|
||||
'description': 'Complete app store submission and approval process',
|
||||
'icon': 'store',
|
||||
'display_order': 3
|
||||
}
|
||||
]
|
||||
elif service.slug == 'api-development-integration':
|
||||
features = [
|
||||
{
|
||||
'title': 'RESTful Design',
|
||||
'description': 'Clean, intuitive API design following REST principles',
|
||||
'icon': 'code',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Comprehensive Documentation',
|
||||
'description': 'Detailed API documentation with examples',
|
||||
'icon': 'book',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Rate Limiting',
|
||||
'description': 'Built-in rate limiting and security measures',
|
||||
'icon': 'shield',
|
||||
'display_order': 3
|
||||
}
|
||||
]
|
||||
elif service.slug == 'cloud-migration-services':
|
||||
features = [
|
||||
{
|
||||
'title': 'Zero Downtime',
|
||||
'description': 'Seamless migration with minimal service interruption',
|
||||
'icon': 'clock',
|
||||
'display_order': 1
|
||||
},
|
||||
{
|
||||
'title': 'Cost Optimization',
|
||||
'description': 'Optimized cloud resources for maximum cost efficiency',
|
||||
'icon': 'dollar-sign',
|
||||
'display_order': 2
|
||||
},
|
||||
{
|
||||
'title': 'Security First',
|
||||
'description': 'Enhanced security with cloud-native security features',
|
||||
'icon': 'shield',
|
||||
'display_order': 3
|
||||
}
|
||||
]
|
||||
else:
|
||||
features = []
|
||||
|
||||
for feature_data in features:
|
||||
ServiceFeature.objects.create(
|
||||
service=service,
|
||||
**feature_data
|
||||
)
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.WARNING(f'Service already exists: {service.title}')
|
||||
)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('Successfully populated services database')
|
||||
)
|
||||
70
gnx-react/backend/services/migrations/0001_initial.py
Normal file
70
gnx-react/backend/services/migrations/0001_initial.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 07:54
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Service',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(help_text='Service title', max_length=200)),
|
||||
('description', models.TextField(help_text='Service description')),
|
||||
('slug', models.SlugField(help_text='URL-friendly version of the title', max_length=200, unique=True)),
|
||||
('icon', models.CharField(help_text="Icon name (e.g., 'code', 'api', 'cloud')", max_length=50)),
|
||||
('image', models.CharField(help_text='Path to service image', max_length=500)),
|
||||
('price', models.DecimalField(decimal_places=2, help_text='Service price', max_digits=10, validators=[django.core.validators.MinValueValidator(0)])),
|
||||
('featured', models.BooleanField(default=False, help_text='Whether this service is featured')),
|
||||
('display_order', models.PositiveIntegerField(default=0, help_text='Order for displaying services')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Whether this service is active')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Service',
|
||||
'verbose_name_plural': 'Services',
|
||||
'ordering': ['display_order', 'created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ServiceCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, unique=True)),
|
||||
('slug', models.SlugField(max_length=100, unique=True)),
|
||||
('description', models.TextField(blank=True)),
|
||||
('display_order', models.PositiveIntegerField(default=0)),
|
||||
('is_active', models.BooleanField(default=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Service Category',
|
||||
'verbose_name_plural': 'Service Categories',
|
||||
'ordering': ['display_order', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ServiceFeature',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(help_text='Feature title', max_length=200)),
|
||||
('description', models.TextField(blank=True, help_text='Feature description')),
|
||||
('icon', models.CharField(blank=True, help_text='Feature icon', max_length=50)),
|
||||
('display_order', models.PositiveIntegerField(default=0, help_text='Order for displaying features')),
|
||||
('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='features', to='services.service')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Service Feature',
|
||||
'verbose_name_plural': 'Service Features',
|
||||
'ordering': ['display_order', 'title'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 08:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import services.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='image_url',
|
||||
field=models.CharField(blank=True, help_text='External image URL (alternative to uploaded image)', max_length=500),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='service',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, help_text='Service image', null=True, upload_to=services.models.service_image_upload_path),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 08:24
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0002_service_image_url_alter_service_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='category',
|
||||
field=models.ForeignKey(blank=True, help_text='Service category', null=True, on_delete=django.db.models.deletion.SET_NULL, to='services.servicecategory'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='deliverables',
|
||||
field=models.TextField(blank=True, help_text='What you get with this service'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='duration',
|
||||
field=models.CharField(blank=True, help_text="Project duration (e.g., '2-4 weeks', '3-6 months')", max_length=100),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='short_description',
|
||||
field=models.CharField(blank=True, help_text='Short description for cards and previews', max_length=300),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='technologies',
|
||||
field=models.TextField(blank=True, help_text='Technologies and tools used'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 08:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0003_service_category_service_deliverables_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='process_steps',
|
||||
field=models.TextField(blank=True, help_text='Process steps in JSON format or comma-separated'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 11:41
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0004_service_process_steps'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ServiceExpertise',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(help_text='Expertise title', max_length=200)),
|
||||
('description', models.TextField(help_text='Expertise description')),
|
||||
('icon', models.CharField(blank=True, help_text='Expertise icon', max_length=50)),
|
||||
('display_order', models.PositiveIntegerField(default=0, help_text='Order for displaying expertise items')),
|
||||
('service', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='expertise_items', to='services.service')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Service Expertise',
|
||||
'verbose_name_plural': 'Service Expertise Items',
|
||||
'ordering': ['display_order', 'title'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
# Generated by Django 4.2.7 on 2025-09-25 11:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0005_serviceexpertise'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='deliverables_description',
|
||||
field=models.TextField(blank=True, help_text='Description for the What You Get section'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='expertise_description',
|
||||
field=models.TextField(blank=True, help_text='Description for the Our Expertise section'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='features_description',
|
||||
field=models.TextField(blank=True, help_text='Description for the Key Features section'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='process_description',
|
||||
field=models.TextField(blank=True, help_text='Description for the Our Process section'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='service',
|
||||
name='why_choose_description',
|
||||
field=models.TextField(blank=True, help_text='Description for the Why Choose Our Service section'),
|
||||
),
|
||||
]
|
||||
0
gnx-react/backend/services/migrations/__init__.py
Normal file
0
gnx-react/backend/services/migrations/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
186
gnx-react/backend/services/models.py
Normal file
186
gnx-react/backend/services/models.py
Normal file
@@ -0,0 +1,186 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.utils.text import slugify
|
||||
import os
|
||||
|
||||
|
||||
def service_image_upload_path(instance, filename):
|
||||
"""
|
||||
Generate upload path for service images
|
||||
"""
|
||||
# Get file extension
|
||||
ext = filename.split('.')[-1]
|
||||
# Create filename with service slug
|
||||
filename = f"{instance.slug}.{ext}"
|
||||
return os.path.join('services', 'images', filename)
|
||||
|
||||
|
||||
class Service(models.Model):
|
||||
"""
|
||||
Service model for the services page
|
||||
"""
|
||||
title = models.CharField(max_length=200, help_text="Service title")
|
||||
description = models.TextField(help_text="Service description")
|
||||
slug = models.SlugField(max_length=200, unique=True, help_text="URL-friendly version of the title")
|
||||
icon = models.CharField(max_length=50, help_text="Icon name (e.g., 'code', 'api', 'cloud')")
|
||||
image = models.ImageField(
|
||||
upload_to=service_image_upload_path,
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text="Service image"
|
||||
)
|
||||
image_url = models.CharField(
|
||||
max_length=500,
|
||||
blank=True,
|
||||
help_text="External image URL (alternative to uploaded image)"
|
||||
)
|
||||
price = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
validators=[MinValueValidator(0)],
|
||||
help_text="Service price"
|
||||
)
|
||||
category = models.ForeignKey(
|
||||
'ServiceCategory',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Service category"
|
||||
)
|
||||
short_description = models.CharField(
|
||||
max_length=300,
|
||||
blank=True,
|
||||
help_text="Short description for cards and previews"
|
||||
)
|
||||
duration = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
help_text="Project duration (e.g., '2-4 weeks', '3-6 months')"
|
||||
)
|
||||
deliverables = models.TextField(
|
||||
blank=True,
|
||||
help_text="What you get with this service"
|
||||
)
|
||||
technologies = models.TextField(
|
||||
blank=True,
|
||||
help_text="Technologies and tools used"
|
||||
)
|
||||
process_steps = models.TextField(
|
||||
blank=True,
|
||||
help_text="Process steps in JSON format or comma-separated"
|
||||
)
|
||||
features_description = models.TextField(
|
||||
blank=True,
|
||||
help_text="Description for the Key Features section"
|
||||
)
|
||||
deliverables_description = models.TextField(
|
||||
blank=True,
|
||||
help_text="Description for the What You Get section"
|
||||
)
|
||||
process_description = models.TextField(
|
||||
blank=True,
|
||||
help_text="Description for the Our Process section"
|
||||
)
|
||||
why_choose_description = models.TextField(
|
||||
blank=True,
|
||||
help_text="Description for the Why Choose Our Service section"
|
||||
)
|
||||
expertise_description = models.TextField(
|
||||
blank=True,
|
||||
help_text="Description for the Our Expertise section"
|
||||
)
|
||||
featured = models.BooleanField(default=False, help_text="Whether this service is featured")
|
||||
display_order = models.PositiveIntegerField(default=0, help_text="Order for displaying services")
|
||||
is_active = models.BooleanField(default=True, help_text="Whether this service is active")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['display_order', 'created_at']
|
||||
verbose_name = "Service"
|
||||
verbose_name_plural = "Services"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.title)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def formatted_price(self):
|
||||
"""Return formatted price as string"""
|
||||
return f"${self.price:,.2f}"
|
||||
|
||||
@property
|
||||
def get_image_url(self):
|
||||
"""Return the image URL (uploaded image or external URL)"""
|
||||
if self.image and hasattr(self.image, 'url'):
|
||||
return self.image.url
|
||||
elif self.image_url:
|
||||
return self.image_url
|
||||
return None
|
||||
|
||||
|
||||
class ServiceFeature(models.Model):
|
||||
"""
|
||||
Additional features for services
|
||||
"""
|
||||
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='features')
|
||||
title = models.CharField(max_length=200, help_text="Feature title")
|
||||
description = models.TextField(blank=True, help_text="Feature description")
|
||||
icon = models.CharField(max_length=50, blank=True, help_text="Feature icon")
|
||||
display_order = models.PositiveIntegerField(default=0, help_text="Order for displaying features")
|
||||
|
||||
class Meta:
|
||||
ordering = ['display_order', 'title']
|
||||
verbose_name = "Service Feature"
|
||||
verbose_name_plural = "Service Features"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.service.title} - {self.title}"
|
||||
|
||||
|
||||
class ServiceExpertise(models.Model):
|
||||
"""
|
||||
Expertise items for the "Our Expertise" section
|
||||
"""
|
||||
service = models.ForeignKey(Service, on_delete=models.CASCADE, related_name='expertise_items')
|
||||
title = models.CharField(max_length=200, help_text="Expertise title")
|
||||
description = models.TextField(help_text="Expertise description")
|
||||
icon = models.CharField(max_length=50, blank=True, help_text="Expertise icon")
|
||||
display_order = models.PositiveIntegerField(default=0, help_text="Order for displaying expertise items")
|
||||
|
||||
class Meta:
|
||||
ordering = ['display_order', 'title']
|
||||
verbose_name = "Service Expertise"
|
||||
verbose_name_plural = "Service Expertise Items"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.service.title} - {self.title}"
|
||||
|
||||
|
||||
class ServiceCategory(models.Model):
|
||||
"""
|
||||
Categories for services
|
||||
"""
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
slug = models.SlugField(max_length=100, unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
display_order = models.PositiveIntegerField(default=0)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['display_order', 'name']
|
||||
verbose_name = "Service Category"
|
||||
verbose_name_plural = "Service Categories"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
super().save(*args, **kwargs)
|
||||
127
gnx-react/backend/services/serializers.py
Normal file
127
gnx-react/backend/services/serializers.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from rest_framework import serializers
|
||||
from .models import Service, ServiceFeature, ServiceExpertise, ServiceCategory
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
|
||||
|
||||
class ServiceFeatureSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializer for ServiceFeature model
|
||||
"""
|
||||
class Meta:
|
||||
model = ServiceFeature
|
||||
fields = ['id', 'title', 'description', 'icon', 'display_order']
|
||||
|
||||
|
||||
class ServiceExpertiseSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializer for ServiceExpertise model
|
||||
"""
|
||||
class Meta:
|
||||
model = ServiceExpertise
|
||||
fields = ['id', 'title', 'description', 'icon', 'display_order']
|
||||
|
||||
|
||||
class ServiceCategorySerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializer for ServiceCategory model
|
||||
"""
|
||||
class Meta:
|
||||
model = ServiceCategory
|
||||
fields = ['id', 'name', 'slug', 'description', 'display_order']
|
||||
|
||||
|
||||
class ServiceSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializer for Service model
|
||||
"""
|
||||
features = ServiceFeatureSerializer(many=True, read_only=True)
|
||||
expertise_items = ServiceExpertiseSerializer(many=True, read_only=True)
|
||||
category = ServiceCategorySerializer(read_only=True)
|
||||
formatted_price = serializers.ReadOnlyField()
|
||||
image_url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = [
|
||||
'id', 'title', 'description', 'short_description', 'slug', 'icon', 'image', 'image_url',
|
||||
'price', 'formatted_price', 'category', 'duration', 'deliverables', 'technologies', 'process_steps',
|
||||
'features_description', 'deliverables_description', 'process_description', 'why_choose_description', 'expertise_description',
|
||||
'featured', 'display_order', 'is_active', 'created_at', 'updated_at', 'features', 'expertise_items'
|
||||
]
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'slug']
|
||||
|
||||
def get_image_url(self, obj):
|
||||
"""Return the image URL"""
|
||||
return obj.get_image_url
|
||||
|
||||
|
||||
class ServiceListSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Simplified serializer for service lists
|
||||
"""
|
||||
formatted_price = serializers.ReadOnlyField()
|
||||
image_url = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = [
|
||||
'id', 'title', 'description', 'short_description', 'slug', 'icon', 'image', 'image_url',
|
||||
'price', 'formatted_price', 'category', 'duration', 'deliverables', 'technologies',
|
||||
'process_steps', 'featured', 'display_order'
|
||||
]
|
||||
|
||||
def get_image_url(self, obj):
|
||||
"""Return the image URL"""
|
||||
return obj.get_image_url
|
||||
|
||||
|
||||
class ServiceCreateUpdateSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializer for creating and updating services
|
||||
"""
|
||||
class Meta:
|
||||
model = Service
|
||||
fields = [
|
||||
'title', 'description', 'short_description', 'icon', 'image', 'image_url', 'price',
|
||||
'category', 'duration', 'deliverables', 'technologies', 'process_steps', 'featured', 'display_order', 'is_active'
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
# Generate slug from title if not provided
|
||||
if 'slug' not in validated_data:
|
||||
validated_data['slug'] = self.generate_unique_slug(validated_data['title'])
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
# If image is being updated, delete the old image
|
||||
if 'image' in validated_data and instance.image:
|
||||
instance.image.delete(save=False)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def generate_unique_slug(self, title):
|
||||
"""Generate a unique slug from title"""
|
||||
from django.utils.text import slugify
|
||||
base_slug = slugify(title)
|
||||
slug = base_slug
|
||||
counter = 1
|
||||
|
||||
while Service.objects.filter(slug=slug).exists():
|
||||
slug = f"{base_slug}-{counter}"
|
||||
counter += 1
|
||||
|
||||
return slug
|
||||
|
||||
def validate(self, data):
|
||||
"""Validate service data"""
|
||||
# Make image_url optional for existing services
|
||||
# Only require image or image_url for new services
|
||||
if self.instance is None: # Creating new service
|
||||
image = data.get('image')
|
||||
image_url = data.get('image_url')
|
||||
|
||||
if not image and not image_url:
|
||||
raise serializers.ValidationError(
|
||||
"Either an image file or image URL must be provided for new services."
|
||||
)
|
||||
|
||||
return data
|
||||
3
gnx-react/backend/services/tests.py
Normal file
3
gnx-react/backend/services/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
30
gnx-react/backend/services/urls.py
Normal file
30
gnx-react/backend/services/urls.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from . import views
|
||||
|
||||
# Create a router for ViewSets (if we add any later)
|
||||
router = DefaultRouter()
|
||||
|
||||
app_name = 'services_api'
|
||||
|
||||
urlpatterns = [
|
||||
# Service URLs
|
||||
path('', views.ServiceListView.as_view(), name='service-list'),
|
||||
path('featured/', views.FeaturedServicesView.as_view(), name='featured-services'),
|
||||
path('search/', views.service_search, name='service-search'),
|
||||
path('stats/', views.service_stats, name='service-stats'),
|
||||
path('<slug:slug>/', views.ServiceDetailView.as_view(), name='service-detail'),
|
||||
|
||||
# Admin URLs (require authentication)
|
||||
path('admin/create/', views.ServiceCreateView.as_view(), name='service-create'),
|
||||
path('admin/<slug:slug>/update/', views.ServiceUpdateView.as_view(), name='service-update'),
|
||||
path('admin/<slug:slug>/delete/', views.ServiceDeleteView.as_view(), name='service-delete'),
|
||||
path('admin/<slug:slug>/upload-image/', views.upload_service_image, name='service-upload-image'),
|
||||
|
||||
# Category URLs
|
||||
path('categories/', views.ServiceCategoryListView.as_view(), name='category-list'),
|
||||
path('categories/<slug:slug>/', views.ServiceCategoryDetailView.as_view(), name='category-detail'),
|
||||
|
||||
# Include router URLs
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
213
gnx-react/backend/services/views.py
Normal file
213
gnx-react/backend/services/views.py
Normal file
@@ -0,0 +1,213 @@
|
||||
from rest_framework import generics, status, filters
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.db.models import Q, Avg
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
from .models import Service, ServiceFeature, ServiceCategory
|
||||
from .serializers import (
|
||||
ServiceSerializer,
|
||||
ServiceListSerializer,
|
||||
ServiceCreateUpdateSerializer,
|
||||
ServiceFeatureSerializer,
|
||||
ServiceCategorySerializer
|
||||
)
|
||||
|
||||
|
||||
class ServiceListView(generics.ListAPIView):
|
||||
"""
|
||||
List all active services with optional filtering
|
||||
"""
|
||||
queryset = Service.objects.filter(is_active=True)
|
||||
serializer_class = ServiceListSerializer
|
||||
permission_classes = [AllowAny]
|
||||
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
||||
filterset_fields = ['featured', 'display_order']
|
||||
search_fields = ['title', 'description']
|
||||
ordering_fields = ['display_order', 'created_at', 'title', 'price']
|
||||
ordering = ['display_order', 'created_at']
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Filter by category if provided
|
||||
category_slug = self.request.query_params.get('category', None)
|
||||
if category_slug:
|
||||
queryset = queryset.filter(category__slug=category_slug)
|
||||
|
||||
# Filter by price range if provided
|
||||
min_price = self.request.query_params.get('min_price', None)
|
||||
max_price = self.request.query_params.get('max_price', None)
|
||||
|
||||
if min_price:
|
||||
queryset = queryset.filter(price__gte=min_price)
|
||||
if max_price:
|
||||
queryset = queryset.filter(price__lte=max_price)
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
class ServiceDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single service by slug
|
||||
"""
|
||||
queryset = Service.objects.filter(is_active=True)
|
||||
serializer_class = ServiceSerializer
|
||||
permission_classes = [AllowAny]
|
||||
lookup_field = 'slug'
|
||||
|
||||
|
||||
class ServiceCreateView(generics.CreateAPIView):
|
||||
"""
|
||||
Create a new service (admin only)
|
||||
"""
|
||||
queryset = Service.objects.all()
|
||||
serializer_class = ServiceCreateUpdateSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
||||
|
||||
|
||||
class ServiceUpdateView(generics.UpdateAPIView):
|
||||
"""
|
||||
Update an existing service (admin only)
|
||||
"""
|
||||
queryset = Service.objects.all()
|
||||
serializer_class = ServiceCreateUpdateSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
lookup_field = 'slug'
|
||||
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
||||
|
||||
|
||||
class ServiceDeleteView(generics.DestroyAPIView):
|
||||
"""
|
||||
Delete a service (admin only)
|
||||
"""
|
||||
queryset = Service.objects.all()
|
||||
permission_classes = [IsAuthenticated]
|
||||
lookup_field = 'slug'
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
# Delete the image file if it exists
|
||||
if instance.image:
|
||||
instance.image.delete(save=False)
|
||||
instance.delete()
|
||||
|
||||
|
||||
class FeaturedServicesView(generics.ListAPIView):
|
||||
"""
|
||||
List all featured services
|
||||
"""
|
||||
queryset = Service.objects.filter(is_active=True, featured=True)
|
||||
serializer_class = ServiceListSerializer
|
||||
permission_classes = [AllowAny]
|
||||
ordering = ['display_order', 'created_at']
|
||||
|
||||
|
||||
class ServiceCategoryListView(generics.ListAPIView):
|
||||
"""
|
||||
List all active service categories
|
||||
"""
|
||||
queryset = ServiceCategory.objects.filter(is_active=True)
|
||||
serializer_class = ServiceCategorySerializer
|
||||
permission_classes = [AllowAny]
|
||||
ordering = ['display_order', 'name']
|
||||
|
||||
|
||||
class ServiceCategoryDetailView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Retrieve a single service category by slug
|
||||
"""
|
||||
queryset = ServiceCategory.objects.filter(is_active=True)
|
||||
serializer_class = ServiceCategorySerializer
|
||||
permission_classes = [AllowAny]
|
||||
lookup_field = 'slug'
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([AllowAny])
|
||||
def service_search(request):
|
||||
"""
|
||||
Search services by query string
|
||||
"""
|
||||
query = request.GET.get('q', '')
|
||||
if not query:
|
||||
return Response({'error': 'Query parameter "q" is required'},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
services = Service.objects.filter(
|
||||
Q(is_active=True) & (
|
||||
Q(title__icontains=query) |
|
||||
Q(description__icontains=query) |
|
||||
Q(slug__icontains=query)
|
||||
)
|
||||
).order_by('display_order', 'created_at')
|
||||
|
||||
serializer = ServiceListSerializer(services, many=True)
|
||||
return Response({
|
||||
'query': query,
|
||||
'count': services.count(),
|
||||
'results': serializer.data
|
||||
})
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([AllowAny])
|
||||
def service_stats(request):
|
||||
"""
|
||||
Get service statistics
|
||||
"""
|
||||
total_services = Service.objects.filter(is_active=True).count()
|
||||
featured_services = Service.objects.filter(is_active=True, featured=True).count()
|
||||
categories = ServiceCategory.objects.filter(is_active=True).count()
|
||||
|
||||
# Average price
|
||||
services_with_price = Service.objects.filter(is_active=True, price__gt=0)
|
||||
avg_price = services_with_price.aggregate(avg_price=Avg('price'))['avg_price'] or 0
|
||||
|
||||
return Response({
|
||||
'total_services': total_services,
|
||||
'featured_services': featured_services,
|
||||
'categories': categories,
|
||||
'average_price': float(avg_price)
|
||||
})
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def upload_service_image(request, slug):
|
||||
"""
|
||||
Upload an image for a specific service (admin only)
|
||||
"""
|
||||
try:
|
||||
service = get_object_or_404(Service, slug=slug)
|
||||
|
||||
if 'image' not in request.FILES:
|
||||
return Response(
|
||||
{'error': 'No image file provided'},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Delete old image if it exists
|
||||
if service.image:
|
||||
service.image.delete(save=False)
|
||||
|
||||
# Save new image
|
||||
service.image = request.FILES['image']
|
||||
service.save()
|
||||
|
||||
serializer = ServiceSerializer(service)
|
||||
return Response({
|
||||
'message': 'Image uploaded successfully',
|
||||
'service': serializer.data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{'error': f'Failed to upload image: {str(e)}'},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
Reference in New Issue
Block a user