feat: Implement initial schema and add various API, service, and management command enhancements across the application.

This commit is contained in:
pacnpal
2026-01-01 15:13:01 -05:00
parent c95f99ca10
commit b243b17af7
413 changed files with 11164 additions and 17433 deletions

View File

@@ -53,9 +53,7 @@ class RideRankingService:
Dictionary with statistics about the ranking calculation
"""
start_time = timezone.now()
self.logger.info(
f"Starting ranking calculation for category: {category or 'ALL'}"
)
self.logger.info(f"Starting ranking calculation for category: {category or 'ALL'}")
try:
with transaction.atomic():
@@ -87,9 +85,7 @@ class RideRankingService:
self._cleanup_old_data()
duration = (timezone.now() - start_time).total_seconds()
self.logger.info(
f"Ranking calculation completed in {duration:.2f} seconds"
)
self.logger.info(f"Ranking calculation completed in {duration:.2f} seconds")
return {
"status": "success",
@@ -113,9 +109,7 @@ class RideRankingService:
"""
queryset = (
Ride.objects.filter(status="OPERATING", reviews__is_published=True)
.annotate(
review_count=Count("reviews", filter=Q(reviews__is_published=True))
)
.annotate(review_count=Count("reviews", filter=Q(reviews__is_published=True)))
.filter(review_count__gt=0)
)
@@ -124,9 +118,7 @@ class RideRankingService:
return list(queryset.distinct())
def _calculate_all_comparisons(
self, rides: list[Ride]
) -> dict[tuple[int, int], RidePairComparison]:
def _calculate_all_comparisons(self, rides: list[Ride]) -> dict[tuple[int, int], RidePairComparison]:
"""
Calculate pairwise comparisons for all ride pairs.
@@ -146,15 +138,11 @@ class RideRankingService:
processed += 1
if processed % 100 == 0:
self.logger.debug(
f"Processed {processed}/{total_pairs} comparisons"
)
self.logger.debug(f"Processed {processed}/{total_pairs} comparisons")
return comparisons
def _calculate_pairwise_comparison(
self, ride_a: Ride, ride_b: Ride
) -> RidePairComparison | None:
def _calculate_pairwise_comparison(self, ride_a: Ride, ride_b: Ride) -> RidePairComparison | None:
"""
Calculate the pairwise comparison between two rides.
@@ -163,15 +151,11 @@ class RideRankingService:
"""
# Get mutual riders (users who have rated both rides)
ride_a_reviewers = set(
RideReview.objects.filter(ride=ride_a, is_published=True).values_list(
"user_id", flat=True
)
RideReview.objects.filter(ride=ride_a, is_published=True).values_list("user_id", flat=True)
)
ride_b_reviewers = set(
RideReview.objects.filter(ride=ride_b, is_published=True).values_list(
"user_id", flat=True
)
RideReview.objects.filter(ride=ride_b, is_published=True).values_list("user_id", flat=True)
)
mutual_riders = ride_a_reviewers & ride_b_reviewers
@@ -183,16 +167,12 @@ class RideRankingService:
# Get ratings from mutual riders
ride_a_ratings = {
review.user_id: review.rating
for review in RideReview.objects.filter(
ride=ride_a, user_id__in=mutual_riders, is_published=True
)
for review in RideReview.objects.filter(ride=ride_a, user_id__in=mutual_riders, is_published=True)
}
ride_b_ratings = {
review.user_id: review.rating
for review in RideReview.objects.filter(
ride=ride_b, user_id__in=mutual_riders, is_published=True
)
for review in RideReview.objects.filter(ride=ride_b, user_id__in=mutual_riders, is_published=True)
}
# Count wins and ties
@@ -212,12 +192,8 @@ class RideRankingService:
ties += 1
# Calculate average ratings from mutual riders
ride_a_avg = (
sum(ride_a_ratings.values()) / len(ride_a_ratings) if ride_a_ratings else 0
)
ride_b_avg = (
sum(ride_b_ratings.values()) / len(ride_b_ratings) if ride_b_ratings else 0
)
ride_a_avg = sum(ride_a_ratings.values()) / len(ride_a_ratings) if ride_a_ratings else 0
ride_b_avg = sum(ride_b_ratings.values()) / len(ride_b_ratings) if ride_b_ratings else 0
# Create or update comparison record
comparison, created = RidePairComparison.objects.update_or_create(
@@ -228,16 +204,8 @@ class RideRankingService:
"ride_b_wins": ride_b_wins if ride_a.id < ride_b.id else ride_a_wins,
"ties": ties,
"mutual_riders_count": len(mutual_riders),
"ride_a_avg_rating": (
Decimal(str(ride_a_avg))
if ride_a.id < ride_b.id
else Decimal(str(ride_b_avg))
),
"ride_b_avg_rating": (
Decimal(str(ride_b_avg))
if ride_a.id < ride_b.id
else Decimal(str(ride_a_avg))
),
"ride_a_avg_rating": (Decimal(str(ride_a_avg)) if ride_a.id < ride_b.id else Decimal(str(ride_b_avg))),
"ride_b_avg_rating": (Decimal(str(ride_b_avg)) if ride_a.id < ride_b.id else Decimal(str(ride_a_avg))),
},
)
@@ -294,16 +262,12 @@ class RideRankingService:
# Calculate winning percentage (ties count as 0.5)
total_comparisons = wins + losses + ties
if total_comparisons > 0:
winning_percentage = Decimal(
str((wins + 0.5 * ties) / total_comparisons)
)
winning_percentage = Decimal(str((wins + 0.5 * ties) / total_comparisons))
else:
winning_percentage = Decimal("0.5")
# Get average rating and reviewer count
ride_stats = RideReview.objects.filter(
ride=ride, is_published=True
).aggregate(
ride_stats = RideReview.objects.filter(ride=ride, is_published=True).aggregate(
avg_rating=Avg("rating"), reviewer_count=Count("user", distinct=True)
)
@@ -356,11 +320,7 @@ class RideRankingService:
tied_group = [rankings[i]]
j = i + 1
while (
j < len(rankings)
and rankings[j]["winning_percentage"]
== rankings[i]["winning_percentage"]
):
while j < len(rankings) and rankings[j]["winning_percentage"] == rankings[i]["winning_percentage"]:
tied_group.append(rankings[j])
j += 1
@@ -462,9 +422,7 @@ class RideRankingService:
cutoff_date = timezone.now() - timezone.timedelta(days=days_to_keep)
# Delete old snapshots
deleted_snapshots = RankingSnapshot.objects.filter(
snapshot_date__lt=cutoff_date.date()
).delete()
deleted_snapshots = RankingSnapshot.objects.filter(snapshot_date__lt=cutoff_date.date()).delete()
if deleted_snapshots[0] > 0:
self.logger.info(f"Deleted {deleted_snapshots[0]} old ranking snapshots")
@@ -486,9 +444,7 @@ class RideRankingService:
)
# Get ranking history
history = RankingSnapshot.objects.filter(ride=ride).order_by(
"-snapshot_date"
)[:30]
history = RankingSnapshot.objects.filter(ride=ride).order_by("-snapshot_date")[:30]
return {
"current_rank": ranking.rank,
@@ -501,32 +457,18 @@ class RideRankingService:
"last_calculated": ranking.last_calculated,
"head_to_head": [
{
"opponent": (
comp.ride_b if comp.ride_a_id == ride.id else comp.ride_a
),
"opponent": (comp.ride_b if comp.ride_a_id == ride.id else comp.ride_a),
"result": (
"win"
if (
(
comp.ride_a_id == ride.id
and comp.ride_a_wins > comp.ride_b_wins
)
or (
comp.ride_b_id == ride.id
and comp.ride_b_wins > comp.ride_a_wins
)
(comp.ride_a_id == ride.id and comp.ride_a_wins > comp.ride_b_wins)
or (comp.ride_b_id == ride.id and comp.ride_b_wins > comp.ride_a_wins)
)
else (
"loss"
if (
(
comp.ride_a_id == ride.id
and comp.ride_a_wins < comp.ride_b_wins
)
or (
comp.ride_b_id == ride.id
and comp.ride_b_wins < comp.ride_a_wins
)
(comp.ride_a_id == ride.id and comp.ride_a_wins < comp.ride_b_wins)
or (comp.ride_b_id == ride.id and comp.ride_b_wins < comp.ride_a_wins)
)
else "tie"
)