[food] Add calories per day
This commit is contained in:
@ -1,15 +1,18 @@
|
||||
import hashlib
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from urllib.parse import urlparse
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pendulum
|
||||
import pytz
|
||||
from django.apps import apps
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
from django.db.models.fields.json import KeyTextTransform
|
||||
from django.db.models.functions import Cast, TruncDate
|
||||
from django.utils import timezone
|
||||
from profiles.models import UserProfile
|
||||
from profiles.utils import now_user_timezone
|
||||
@ -371,3 +374,37 @@ def fix_playback_position_seconds(*scrobbles: "Scrobble", commit=True) -> list["
|
||||
scrobble.save(update_fields=["playback_position_seconds"])
|
||||
|
||||
return updated_scrobbles
|
||||
|
||||
|
||||
def base_scrobble_qs(user_id: int) -> models.QuerySet:
|
||||
"""Base queryset with calories extracted as integer and day annotated."""
|
||||
from scrobbles.models import Scrobble
|
||||
|
||||
return (
|
||||
Scrobble.objects
|
||||
.annotate(day=TruncDate("timestamp"))
|
||||
.annotate(calories_int=Cast(KeyTextTransform("calories", "log"), models.IntegerField()))
|
||||
.filter(calories_int__isnull=False, user_id=user_id)
|
||||
)
|
||||
|
||||
def get_daily_calories_for_user_by_day(user_id: int, date: date| str) -> int:
|
||||
"""Return total calories for a user on a specific day."""
|
||||
|
||||
if isinstance(date, str):
|
||||
date = pendulum.parse(date)
|
||||
|
||||
qs = base_scrobble_qs(user_id).filter(day=date)
|
||||
agg = qs.aggregate(total_calories=models.Sum("calories_int"))
|
||||
|
||||
return agg["total_calories"] or 0
|
||||
|
||||
def get_daily_calorie_dict_for_user(user_id: int) -> dict[date, int]:
|
||||
"""Return {day: total_calories} for all days with scrobbles, in one query."""
|
||||
qs = (
|
||||
base_scrobble_qs(user_id)
|
||||
.values("day")
|
||||
.annotate(total_calories=models.Sum("calories_int"))
|
||||
.order_by("day")
|
||||
)
|
||||
|
||||
return {entry["day"]: entry["total_calories"] for entry in qs}
|
||||
|
||||
@ -2,26 +2,27 @@ import calendar
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from django.shortcuts import redirect
|
||||
import pendulum
|
||||
import pytz
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.apps import apps
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Count, Q, Max
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||
from django.db.models import Count, Max, Q
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import FileResponse, HttpResponseRedirect, JsonResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import DetailView, FormView, TemplateView
|
||||
from django.views.generic.edit import CreateView
|
||||
from django.views.generic.list import ListView
|
||||
from moods.models import Mood
|
||||
from music.aggregators import live_charts, scrobble_counts, week_of_scrobbles
|
||||
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from pendulum.parsing.exceptions import ParserError
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import (
|
||||
api_view,
|
||||
@ -54,10 +55,10 @@ from scrobbles.tasks import (
|
||||
process_tsv_import,
|
||||
)
|
||||
from scrobbles.utils import (
|
||||
get_daily_calories_for_user_by_day,
|
||||
get_long_plays_completed,
|
||||
get_long_plays_in_progress,
|
||||
)
|
||||
from moods.models import Mood
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -146,7 +147,7 @@ class RecentScrobbleList(ListView):
|
||||
if date_str:
|
||||
try:
|
||||
date = pendulum.parse(date_str)
|
||||
except:
|
||||
except ParserError:
|
||||
pass
|
||||
if date_str:
|
||||
if date_str == "this_week" or "-W" in date_str:
|
||||
@ -230,6 +231,7 @@ class RecentScrobbleList(ListView):
|
||||
user=self.request.user,
|
||||
)
|
||||
data["counts"] = [] # scrobble_counts(user)
|
||||
data["daily_calories"] = get_daily_calories_for_user_by_day(self.request.user.id, date)
|
||||
else:
|
||||
data["weekly_data"] = week_of_scrobbles()
|
||||
data["counts"] = scrobble_counts()
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<div class="tab-pane fade show" id="latest-beers" role="tabpanel"
|
||||
aria-labelledby="latest-beers-tab">
|
||||
<div class="table-responsive">
|
||||
{{count}} scrobble {% if time %}| {{time|natural_duration}}{% endif %}
|
||||
{{count}} scrobble {% if time %}| {{time|natural_duration}}{% endif %}{% if daily_calories %}| {{daily_calories}} calories{% endif %}
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user