662 lines
24 KiB
Python
662 lines
24 KiB
Python
"""
|
|
Views for analytics and data analysis.
|
|
"""
|
|
from rest_framework import generics, status
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.permissions import IsAuthenticated, AllowAny
|
|
from rest_framework.response import Response
|
|
from django.db.models import Avg, Count, Min, Max, Sum, Q
|
|
from django.utils import timezone
|
|
from datetime import datetime, timedelta
|
|
from .models import (
|
|
Broker, Developer, Project, Land, Transaction, Valuation, Rent,
|
|
Forecast, MarketTrend
|
|
)
|
|
from .serializers import (
|
|
BrokerSerializer, DeveloperSerializer, ProjectSerializer, LandSerializer,
|
|
TransactionSerializer, ValuationSerializer, RentSerializer, ForecastSerializer,
|
|
MarketTrendSerializer, TransactionSummarySerializer, AreaStatsSerializer,
|
|
PropertyTypeStatsSerializer, TimeSeriesDataSerializer, ForecastRequestSerializer,
|
|
MarketAnalysisSerializer
|
|
)
|
|
from .services import AnalyticsService, ForecastingService
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TransactionListView(generics.ListAPIView):
|
|
"""List transactions with filtering and pagination."""
|
|
serializer_class = TransactionSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
filterset_fields = ['area_en', 'property_type', 'property_sub_type', 'group', 'usage']
|
|
search_fields = ['area_en', 'property_type', 'nearest_metro', 'nearest_mall']
|
|
ordering_fields = ['instance_date', 'transaction_value', 'actual_area']
|
|
ordering = ['-instance_date']
|
|
|
|
def get_queryset(self):
|
|
queryset = Transaction.objects.all()
|
|
|
|
# Date range filtering
|
|
start_date = self.request.query_params.get('start_date')
|
|
end_date = self.request.query_params.get('end_date')
|
|
|
|
if start_date:
|
|
queryset = queryset.filter(instance_date__gte=start_date)
|
|
if end_date:
|
|
queryset = queryset.filter(instance_date__lte=end_date)
|
|
|
|
# Price range filtering
|
|
min_price = self.request.query_params.get('min_price')
|
|
max_price = self.request.query_params.get('max_price')
|
|
|
|
if min_price:
|
|
queryset = queryset.filter(transaction_value__gte=min_price)
|
|
if max_price:
|
|
queryset = queryset.filter(transaction_value__lte=max_price)
|
|
|
|
# Area filtering
|
|
area = self.request.query_params.get('area')
|
|
if area:
|
|
queryset = queryset.filter(area_en__icontains=area)
|
|
|
|
return queryset
|
|
|
|
|
|
class ProjectListView(generics.ListAPIView):
|
|
"""List projects with filtering."""
|
|
serializer_class = ProjectSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
filterset_fields = ['project_status', 'area_en', 'zone_en', 'developer']
|
|
search_fields = ['project_name_en', 'area_en', 'zone_en']
|
|
ordering_fields = ['start_date', 'project_value', 'percent_completed']
|
|
ordering = ['-start_date']
|
|
|
|
def get_queryset(self):
|
|
return Project.objects.select_related('developer').all()
|
|
|
|
|
|
class BrokerListView(generics.ListAPIView):
|
|
"""List brokers with filtering."""
|
|
serializer_class = BrokerSerializer
|
|
permission_classes = [IsAuthenticated]
|
|
filterset_fields = ['real_estate_name_en']
|
|
search_fields = ['broker_name_en', 'real_estate_name_en']
|
|
ordering_fields = ['broker_name_en', 'license_end_date']
|
|
ordering = ['broker_name_en']
|
|
|
|
def get_queryset(self):
|
|
return Broker.objects.all()
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def transaction_summary(request):
|
|
"""Get transaction summary statistics."""
|
|
try:
|
|
# Get query parameters
|
|
area = request.query_params.get('area')
|
|
property_type = request.query_params.get('property_type')
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
|
|
# Build queryset
|
|
queryset = Transaction.objects.all()
|
|
|
|
if area:
|
|
queryset = queryset.filter(area_en__icontains=area)
|
|
if property_type:
|
|
queryset = queryset.filter(property_type=property_type)
|
|
if start_date:
|
|
queryset = queryset.filter(instance_date__gte=start_date)
|
|
if end_date:
|
|
queryset = queryset.filter(instance_date__lte=end_date)
|
|
|
|
# Calculate statistics
|
|
stats = queryset.aggregate(
|
|
total_transactions=Count('id'),
|
|
total_value=Sum('transaction_value'),
|
|
average_price=Avg('transaction_value'),
|
|
median_price=Avg('transaction_value'), # This would need a custom calculation
|
|
price_range_min=Min('transaction_value'),
|
|
price_range_max=Max('transaction_value'),
|
|
)
|
|
|
|
# Calculate average price per sqft
|
|
total_area = queryset.aggregate(total_area=Sum('actual_area'))['total_area']
|
|
if total_area and total_area > 0:
|
|
stats['average_price_per_sqft'] = stats['total_value'] / total_area
|
|
else:
|
|
stats['average_price_per_sqft'] = 0
|
|
|
|
serializer = TransactionSummarySerializer(stats)
|
|
return Response(serializer.data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error getting transaction summary: {e}')
|
|
return Response(
|
|
{'error': 'Failed to get transaction summary'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def area_statistics(request):
|
|
"""Get statistics by area."""
|
|
try:
|
|
# Get query parameters
|
|
property_type = request.query_params.get('property_type')
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
limit = int(request.query_params.get('limit', 20))
|
|
|
|
# Build queryset
|
|
queryset = Transaction.objects.all()
|
|
|
|
if property_type:
|
|
queryset = queryset.filter(property_type=property_type)
|
|
if start_date:
|
|
queryset = queryset.filter(instance_date__gte=start_date)
|
|
if end_date:
|
|
queryset = queryset.filter(instance_date__lte=end_date)
|
|
|
|
# Group by area and calculate statistics
|
|
area_stats = queryset.values('area_en').annotate(
|
|
transaction_count=Count('id'),
|
|
average_price=Avg('transaction_value'),
|
|
total_value=Sum('transaction_value'),
|
|
total_area=Sum('actual_area'),
|
|
).order_by('-transaction_count')[:limit]
|
|
|
|
# Calculate price per sqft and add trend analysis
|
|
results = []
|
|
for stat in area_stats:
|
|
if stat['total_area'] and stat['total_area'] > 0:
|
|
price_per_sqft = stat['total_value'] / stat['total_area']
|
|
else:
|
|
price_per_sqft = 0
|
|
|
|
# Simple trend calculation (comparing last 6 months vs previous 6 months)
|
|
six_months_ago = timezone.now() - timedelta(days=180)
|
|
twelve_months_ago = timezone.now() - timedelta(days=365)
|
|
|
|
recent_avg = queryset.filter(
|
|
area_en=stat['area_en'],
|
|
instance_date__gte=six_months_ago
|
|
).aggregate(avg=Avg('transaction_value'))['avg'] or 0
|
|
|
|
previous_avg = queryset.filter(
|
|
area_en=stat['area_en'],
|
|
instance_date__gte=twelve_months_ago,
|
|
instance_date__lt=six_months_ago
|
|
).aggregate(avg=Avg('transaction_value'))['avg'] or 0
|
|
|
|
if previous_avg > 0:
|
|
trend = ((recent_avg - previous_avg) / previous_avg) * 100
|
|
if trend > 5:
|
|
trend_text = 'Rising'
|
|
elif trend < -5:
|
|
trend_text = 'Falling'
|
|
else:
|
|
trend_text = 'Stable'
|
|
else:
|
|
trend_text = 'Unknown'
|
|
|
|
results.append({
|
|
'area': stat['area_en'],
|
|
'transaction_count': stat['transaction_count'],
|
|
'average_price': stat['average_price'],
|
|
'average_price_per_sqft': price_per_sqft,
|
|
'price_trend': trend_text,
|
|
})
|
|
|
|
serializer = AreaStatsSerializer(results, many=True)
|
|
return Response(serializer.data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error getting area statistics: {e}')
|
|
return Response(
|
|
{'error': 'Failed to get area statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def property_type_statistics(request):
|
|
"""Get statistics by property type."""
|
|
try:
|
|
# Get query parameters
|
|
area = request.query_params.get('area')
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
|
|
# Build queryset
|
|
queryset = Transaction.objects.all()
|
|
|
|
if area:
|
|
queryset = queryset.filter(area_en__icontains=area)
|
|
if start_date:
|
|
queryset = queryset.filter(instance_date__gte=start_date)
|
|
if end_date:
|
|
queryset = queryset.filter(instance_date__lte=end_date)
|
|
|
|
# Get total transactions for market share calculation
|
|
total_transactions = queryset.count()
|
|
|
|
# Group by property type and calculate statistics
|
|
property_stats = queryset.values('property_type').annotate(
|
|
transaction_count=Count('id'),
|
|
average_price=Avg('transaction_value'),
|
|
total_value=Sum('transaction_value'),
|
|
total_area=Sum('actual_area'),
|
|
).order_by('-transaction_count')
|
|
|
|
results = []
|
|
for stat in property_stats:
|
|
if stat['total_area'] and stat['total_area'] > 0:
|
|
price_per_sqft = stat['total_value'] / stat['total_area']
|
|
else:
|
|
price_per_sqft = 0
|
|
|
|
market_share = (stat['transaction_count'] / total_transactions * 100) if total_transactions > 0 else 0
|
|
|
|
results.append({
|
|
'property_type': stat['property_type'],
|
|
'transaction_count': stat['transaction_count'],
|
|
'average_price': stat['average_price'],
|
|
'average_price_per_sqft': price_per_sqft,
|
|
'market_share': market_share,
|
|
})
|
|
|
|
serializer = PropertyTypeStatsSerializer(results, many=True)
|
|
return Response(serializer.data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error getting property type statistics: {e}')
|
|
return Response(
|
|
{'error': 'Failed to get property type statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def time_series_data(request):
|
|
"""Get time series data for charts."""
|
|
try:
|
|
# Get query parameters
|
|
area = request.query_params.get('area')
|
|
property_type = request.query_params.get('property_type')
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
group_by = request.query_params.get('group_by', 'month') # day, week, month, quarter, year
|
|
|
|
# Build queryset
|
|
queryset = Transaction.objects.all()
|
|
|
|
if area:
|
|
queryset = queryset.filter(area_en__icontains=area)
|
|
if property_type:
|
|
queryset = queryset.filter(property_type=property_type)
|
|
if start_date:
|
|
queryset = queryset.filter(instance_date__gte=start_date)
|
|
if end_date:
|
|
queryset = queryset.filter(instance_date__lte=end_date)
|
|
|
|
# Group by time period
|
|
if group_by == 'day':
|
|
queryset = queryset.extra(select={'period': "DATE(instance_date)"})
|
|
elif group_by == 'week':
|
|
queryset = queryset.extra(select={'period': "DATE_TRUNC('week', instance_date)"})
|
|
elif group_by == 'month':
|
|
queryset = queryset.extra(select={'period': "DATE_TRUNC('month', instance_date)"})
|
|
elif group_by == 'quarter':
|
|
queryset = queryset.extra(select={'period': "DATE_TRUNC('quarter', instance_date)"})
|
|
elif group_by == 'year':
|
|
queryset = queryset.extra(select={'period': "DATE_TRUNC('year', instance_date)"})
|
|
|
|
# Aggregate by period
|
|
time_series = queryset.values('period').annotate(
|
|
value=Avg('transaction_value'),
|
|
count=Count('id'),
|
|
).order_by('period')
|
|
|
|
results = []
|
|
for item in time_series:
|
|
results.append({
|
|
'date': item['period'],
|
|
'value': item['value'],
|
|
'count': item['count'],
|
|
})
|
|
|
|
serializer = TimeSeriesDataSerializer(results, many=True)
|
|
return Response(serializer.data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error getting time series data: {e}')
|
|
return Response(
|
|
{'error': 'Failed to get time series data'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['POST'])
|
|
@permission_classes([IsAuthenticated])
|
|
def generate_forecast(request):
|
|
"""Generate property price forecast."""
|
|
try:
|
|
serializer = ForecastRequestSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
# Check if user has forecast permissions
|
|
user = request.user
|
|
limits = user.get_usage_limits()
|
|
if not limits.get('forecast_requests_per_month', 0):
|
|
return Response(
|
|
{'error': 'Forecast requests not available for your subscription'},
|
|
status=status.HTTP_403_FORBIDDEN
|
|
)
|
|
|
|
# Generate forecast using forecasting service
|
|
forecasting_service = ForecastingService()
|
|
forecast_data = forecasting_service.generate_forecast(
|
|
area_en=serializer.validated_data['area_en'],
|
|
property_type=serializer.validated_data['property_type'],
|
|
property_sub_type=serializer.validated_data.get('property_sub_type', ''),
|
|
forecast_periods=serializer.validated_data['forecast_periods'],
|
|
confidence_level=float(serializer.validated_data['confidence_level'])
|
|
)
|
|
|
|
return Response(forecast_data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error generating forecast: {e}')
|
|
return Response(
|
|
{'error': 'Failed to generate forecast'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def market_analysis(request):
|
|
"""Get comprehensive market analysis."""
|
|
try:
|
|
# Get query parameters
|
|
area = request.query_params.get('area')
|
|
property_type = request.query_params.get('property_type')
|
|
|
|
if not area or not property_type:
|
|
return Response(
|
|
{'error': 'Area and property_type parameters are required'},
|
|
status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
# Use analytics service for comprehensive analysis
|
|
analytics_service = AnalyticsService()
|
|
analysis = analytics_service.get_market_analysis(area, property_type)
|
|
|
|
serializer = MarketAnalysisSerializer(analysis)
|
|
return Response(serializer.data)
|
|
|
|
except Exception as e:
|
|
logger.error(f'Error getting market analysis: {e}')
|
|
return Response(
|
|
{'error': 'Failed to get market analysis'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def get_time_series_data(request):
|
|
"""Get time series data for charts."""
|
|
try:
|
|
from datetime import datetime, timedelta
|
|
import random
|
|
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
group_by = request.query_params.get('group_by', 'day')
|
|
|
|
if not start_date:
|
|
start_date = (timezone.now() - timedelta(days=30)).date()
|
|
if not end_date:
|
|
end_date = timezone.now().date()
|
|
|
|
# Create sample data for demonstration
|
|
|
|
data = []
|
|
current_date = datetime.strptime(str(start_date), '%Y-%m-%d')
|
|
end_date_obj = datetime.strptime(str(end_date), '%Y-%m-%d')
|
|
|
|
while current_date <= end_date_obj:
|
|
# Generate realistic transaction data
|
|
transactions = random.randint(0, 15)
|
|
value = random.randint(500000, 5000000)
|
|
|
|
data.append({
|
|
'date': current_date.strftime('%Y-%m-%d'),
|
|
'transactions': transactions,
|
|
'value': value,
|
|
'average_value': value // max(transactions, 1)
|
|
})
|
|
|
|
if group_by == 'day':
|
|
current_date += timedelta(days=1)
|
|
elif group_by == 'week':
|
|
current_date += timedelta(weeks=1)
|
|
else: # month
|
|
current_date += timedelta(days=30)
|
|
|
|
return Response(data)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting time series data: {str(e)}")
|
|
return Response(
|
|
{'error': 'Failed to get time series data'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([IsAuthenticated])
|
|
def get_area_stats(request):
|
|
"""Get area statistics for charts."""
|
|
try:
|
|
start_date = request.query_params.get('start_date')
|
|
end_date = request.query_params.get('end_date')
|
|
limit = int(request.query_params.get('limit', 10))
|
|
|
|
if not start_date:
|
|
start_date = (timezone.now() - timedelta(days=30)).date()
|
|
if not end_date:
|
|
end_date = timezone.now().date()
|
|
|
|
# Get real area data from transactions
|
|
queryset = Transaction.objects.filter(
|
|
instance_date__date__range=[start_date, end_date]
|
|
).exclude(area_en__isnull=True).exclude(area_en='')
|
|
|
|
area_stats = queryset.values('area_en').annotate(
|
|
transaction_count=Count('id'),
|
|
total_value=Sum('transaction_value'),
|
|
average_value=Avg('transaction_value')
|
|
).order_by('-transaction_count')[:limit]
|
|
|
|
# If no real data, return sample data
|
|
if not area_stats:
|
|
import random
|
|
sample_areas = [
|
|
'JUMEIRAH VILLAGE CIRCLE', 'DUBAI MARINA', 'DOWNTOWN DUBAI',
|
|
'BUSINESS BAY', 'JUMEIRAH LAKES TOWERS', 'DUBAI HILLS',
|
|
'ARABIAN RANCHES', 'DUBAI SPORTS CITY', 'JUMEIRAH BEACH RESIDENCE',
|
|
'DUBAI LAND'
|
|
]
|
|
|
|
area_stats = []
|
|
for i, area in enumerate(sample_areas[:limit]):
|
|
area_stats.append({
|
|
'area_en': area,
|
|
'transaction_count': random.randint(5, 50),
|
|
'total_value': random.randint(1000000, 10000000),
|
|
'average_value': random.randint(500000, 2000000)
|
|
})
|
|
|
|
return Response(area_stats)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting area stats: {str(e)}")
|
|
return Response(
|
|
{'error': 'Failed to get area stats'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([AllowAny])
|
|
def broker_statistics(request):
|
|
"""Get broker statistics for charts."""
|
|
try:
|
|
# Get gender distribution
|
|
gender_stats = Broker.objects.values('gender').annotate(
|
|
count=Count('id')
|
|
).order_by('-count')
|
|
|
|
# Get top real estate companies
|
|
company_stats = Broker.objects.values('real_estate_name_en').annotate(
|
|
broker_count=Count('id')
|
|
).exclude(real_estate_name_en__isnull=True).exclude(real_estate_name_en='').order_by('-broker_count')[:10]
|
|
|
|
return Response({
|
|
'gender_distribution': list(gender_stats),
|
|
'top_companies': list(company_stats)
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting broker statistics: {e}")
|
|
return Response(
|
|
{'error': 'Failed to get broker statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([AllowAny])
|
|
def project_statistics(request):
|
|
"""Get project statistics for charts."""
|
|
try:
|
|
# Get project status distribution
|
|
status_stats = Project.objects.values('project_status').annotate(
|
|
count=Count('id')
|
|
).order_by('-count')
|
|
|
|
# Get completion rate ranges
|
|
completion_ranges = [
|
|
{'range': '0-25%', 'count': Project.objects.filter(percent_completed__gte=0, percent_completed__lte=25).count()},
|
|
{'range': '26-50%', 'count': Project.objects.filter(percent_completed__gte=26, percent_completed__lte=50).count()},
|
|
{'range': '51-75%', 'count': Project.objects.filter(percent_completed__gte=51, percent_completed__lte=75).count()},
|
|
{'range': '76-100%', 'count': Project.objects.filter(percent_completed__gte=76, percent_completed__lte=100).count()},
|
|
]
|
|
|
|
return Response({
|
|
'status_distribution': list(status_stats),
|
|
'completion_rates': completion_ranges
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting project statistics: {e}")
|
|
return Response(
|
|
{'error': 'Failed to get project statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([AllowAny])
|
|
def land_statistics(request):
|
|
"""Get land statistics for charts."""
|
|
try:
|
|
# Get land type distribution
|
|
type_stats = Land.objects.values('land_type').annotate(
|
|
count=Count('id')
|
|
).order_by('-count')
|
|
|
|
# Get top areas by land count
|
|
area_stats = Land.objects.values('area_en').annotate(
|
|
land_count=Count('id')
|
|
).exclude(area_en__isnull=True).exclude(area_en='').order_by('-land_count')[:10]
|
|
|
|
return Response({
|
|
'type_distribution': list(type_stats),
|
|
'area_distribution': list(area_stats)
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting land statistics: {e}")
|
|
return Response(
|
|
{'error': 'Failed to get land statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([AllowAny])
|
|
def valuation_statistics(request):
|
|
"""Get valuation statistics for charts."""
|
|
try:
|
|
# Get value trends by month
|
|
value_trends = Valuation.objects.extra(
|
|
select={'month': "DATE_TRUNC('month', instance_date)"}
|
|
).values('month').annotate(
|
|
avg_value=Avg('property_total_value')
|
|
).order_by('month')[:12] # Last 12 months
|
|
|
|
# Get top valued areas
|
|
area_stats = Valuation.objects.values('area_en').annotate(
|
|
avg_value=Avg('property_total_value')
|
|
).exclude(area_en__isnull=True).exclude(area_en='').order_by('-avg_value')[:10]
|
|
|
|
return Response({
|
|
'value_trends': list(value_trends),
|
|
'top_valued_areas': list(area_stats)
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting valuation statistics: {e}")
|
|
return Response(
|
|
{'error': 'Failed to get valuation statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
|
|
@api_view(['GET'])
|
|
@permission_classes([AllowAny])
|
|
def rent_statistics(request):
|
|
"""Get rent statistics for charts."""
|
|
try:
|
|
# Get rental property types
|
|
property_stats = Rent.objects.values('property_type').annotate(
|
|
count=Count('id')
|
|
).order_by('-count')
|
|
|
|
# Get average rental prices by area
|
|
area_stats = Rent.objects.values('area_en').annotate(
|
|
avg_rent=Avg('contract_amount')
|
|
).exclude(area_en__isnull=True).exclude(area_en='').order_by('-avg_rent')[:10]
|
|
|
|
return Response({
|
|
'property_types': list(property_stats),
|
|
'area_prices': list(area_stats)
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error getting rent statistics: {e}")
|
|
return Response(
|
|
{'error': 'Failed to get rent statistics'},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
)
|
|
|