Skip to content

Allow multiple weight entries per day #1895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Developers
* Joshua Shelley - https://github.com/navyjosh
* Matt Harrison - https://github.com/Maralai
* Ali Rahbar - https://github.com/crypto-a
* Cam Cecil - https://github.com/scrapcode


Translators
Expand Down
19 changes: 10 additions & 9 deletions wger/core/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.utils.translation import gettext as _
from django.utils import timezone

# wger
from wger.core.models import DaysOfWeek
Expand Down Expand Up @@ -191,16 +192,16 @@ def create_demo_entries(user):
# (Body) weight entries
#
temp = []
existing_entries = [i.date for i in WeightEntry.objects.filter(user=user)]
for i in range(1, 20):
creation_date = datetime.date.today() - datetime.timedelta(days=i)
if creation_date not in existing_entries:
entry = WeightEntry(
user=user,
weight=80 + 0.5 * i + random.randint(1, 3),
date=creation_date,
)
temp.append(entry)
creation_date = timezone.now() - datetime.timedelta(days=i)

entry = WeightEntry(
user=user,
weight=80 + 0.5 * i + random.randint(1, 3),
date=creation_date,
)
temp.append(entry)

WeightEntry.objects.bulk_create(temp)

#
Expand Down
24 changes: 8 additions & 16 deletions wger/core/models/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
)
from django.db import models
from django.db.models import IntegerField
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

# wger
Expand Down Expand Up @@ -513,23 +514,14 @@ def calculate_activities(self):

def user_bodyweight(self, weight):
"""
Create a new weight entry as needed
Create a new weight entry and return it
"""
if not WeightEntry.objects.filter(user=self.user).exists() or (
datetime.date.today() - WeightEntry.objects.filter(user=self.user).latest().date
> datetime.timedelta(days=3)
):
entry = WeightEntry()
entry.weight = weight
entry.user = self.user
entry.date = datetime.date.today()
entry.save()

# Update the last entry
else:
entry = WeightEntry.objects.filter(user=self.user).latest()
entry.weight = weight
entry.save()
entry = WeightEntry()
entry.weight = weight
entry.user = self.user
entry.date = timezone.now()
entry.save()

return entry

def get_owner_object(self):
Expand Down
56 changes: 21 additions & 35 deletions wger/core/tests/test_preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# Django
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils import timezone

# wger
from wger.core.tests.base_testcase import WgerTestCase
Expand Down Expand Up @@ -146,7 +147,7 @@ def test_bodyweight_new(self):
entry = user.userprofile.user_bodyweight(80)
count_after = WeightEntry.objects.filter(user=user).count()
self.assertEqual(count_before, count_after - 1)
self.assertEqual(entry.date, datetime.date.today())
self.assertEqual(entry.date.date(), timezone.now().date())

def test_bodyweight_new_2(self):
"""
Expand All @@ -155,60 +156,41 @@ def test_bodyweight_new_2(self):
user = User.objects.get(pk=2)
count_before = WeightEntry.objects.filter(user=user).count()
last_entry = WeightEntry.objects.filter(user=user).latest()
last_entry.date = datetime.date.today() - datetime.timedelta(weeks=1)
last_entry.date = timezone.now() - datetime.timedelta(weeks=1)
last_entry.save()

entry = user.userprofile.user_bodyweight(80)
count_after = WeightEntry.objects.filter(user=user).count()
self.assertEqual(count_before, count_after - 1)
self.assertEqual(entry.date, datetime.date.today())
self.assertEqual(entry.date.date(), timezone.now().date())

def test_bodyweight_no_entries(self):
def test_bodyweight_new_3(self):
"""
Tests that a new weight entry is created if there are no weight entries
Tests that a new weight entry is created even if others exist today
"""
user = User.objects.get(pk=2)
WeightEntry.objects.filter(user=user).delete()

count_before = WeightEntry.objects.filter(user=user).count()
entry = user.userprofile.user_bodyweight(80)
count_after = WeightEntry.objects.filter(user=user).count()
self.assertEqual(count_before, count_after - 1)
self.assertEqual(entry.date, datetime.date.today())

def test_bodyweight_edit(self):
"""
Tests that the last weight entry is edited
"""
user = User.objects.get(pk=2)
last_entry = WeightEntry.objects.filter(user=user).latest()
last_entry.date = datetime.date.today() - datetime.timedelta(days=3)
last_entry.date = timezone.now() - datetime.timedelta(hours=1)
last_entry.save()

count_before = WeightEntry.objects.filter(user=user).count()
entry = user.userprofile.user_bodyweight(100)
entry = user.userprofile.user_bodyweight(80)
count_after = WeightEntry.objects.filter(user=user).count()
self.assertEqual(count_before, count_after)
self.assertEqual(entry.pk, last_entry.pk)
self.assertEqual(entry.date, last_entry.date)
self.assertEqual(entry.weight, 100)
self.assertEqual(count_before, count_after - 1)
self.assertEqual(entry.date.date(), timezone.now().date())

def test_bodyweight_edit_2(self):
def test_bodyweight_no_entries(self):
"""
Tests that the last weight entry is edited
Tests that a new weight entry is created if there are no weight entries
"""
user = User.objects.get(pk=2)
last_entry = WeightEntry.objects.filter(user=user).latest()
last_entry.date = datetime.date.today()
last_entry.save()
WeightEntry.objects.filter(user=user).delete()

count_before = WeightEntry.objects.filter(user=user).count()
entry = user.userprofile.user_bodyweight(100)
entry = user.userprofile.user_bodyweight(80)
count_after = WeightEntry.objects.filter(user=user).count()
self.assertEqual(count_before, count_after)
self.assertEqual(entry.pk, last_entry.pk)
self.assertEqual(entry.date, last_entry.date)
self.assertEqual(entry.weight, 100)
self.assertEqual(count_before, count_after - 1)
self.assertEqual(entry.date.date(), timezone.now().date())


class PreferencesCalculationsTestCase(WgerTestCase):
Expand All @@ -223,7 +205,7 @@ def test_last_weight_entry(self):
self.user_login('test')
user = User.objects.get(pk=2)
entry = WeightEntry()
entry.date = datetime.datetime.today()
entry.date = timezone.now()
entry.user = user
entry.weight = 100
entry.save()
Expand Down Expand Up @@ -263,6 +245,10 @@ def test_basal_metabolic_rate(self):

self.user_login('test')

# Test User (pk=2)
# 180 cm, 20 years
# Last weight entry is 83 kg

# Male
user = User.objects.get(pk=2)
bmr = user.userprofile.calculate_basal_metabolic_rate()
Expand Down
7 changes: 4 additions & 3 deletions wger/core/tests/test_temporary_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from django.core.management import call_command
from django.http import HttpRequest
from django.urls import reverse
from django.utils import timezone

# wger
from wger.core.demo import (
Expand Down Expand Up @@ -105,7 +106,7 @@ def test_demo_data_guest_account(self):

def test_demo_data_body_weight(self):
"""
Tests that the helper function that creates demo data filters out
Tests that the helper function that creates demo data does not filter out
existing dates for the weight entries
"""
self.client.get(reverse('core:dashboard'))
Expand All @@ -114,7 +115,7 @@ def test_demo_data_body_weight(self):

temp = []
for i in range(1, 5):
creation_date = datetime.date.today() - datetime.timedelta(days=i)
creation_date = timezone.now() - datetime.timedelta(days=i)
entry = WeightEntry(
user=user,
weight=80 + 0.5 * i + random.randint(1, 3),
Expand All @@ -125,7 +126,7 @@ def test_demo_data_body_weight(self):
create_demo_entries(user)

# Body weight
self.assertEqual(WeightEntry.objects.filter(user=user).count(), 19)
self.assertEqual(WeightEntry.objects.filter(user=user).count(), 23)

def test_demo_user(self):
"""
Expand Down
53 changes: 53 additions & 0 deletions wger/exercises/migrations/0031_WeightDateTime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 4.2.16 on 2025-02-22 04:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('exercises', '0030_increase_author_field_length'),
]

operations = [
migrations.AlterField(
model_name='exercise',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='exercisebase',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='exerciseimage',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='exercisevideo',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='historicalexercise',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='historicalexercisebase',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='historicalexerciseimage',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
migrations.AlterField(
model_name='historicalexercisevideo',
name='license_author',
field=models.TextField(blank=True, help_text='If you are not the author, enter the name or source here.', max_length=3500, null=True, verbose_name='Author(s)'),
),
]
18 changes: 18 additions & 0 deletions wger/nutrition/migrations/0025_WeightDateTime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.16 on 2025-02-22 04:14

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('nutrition', '0024_remove_ingredient_status'),
]

operations = [
migrations.RenameIndex(
model_name='ingredient',
new_name='nutrition_i_name_8f538f_gin',
old_name='nutrition_i_search__f274b7_gin',
),
]
2 changes: 1 addition & 1 deletion wger/nutrition/models/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def get_closest_weight_entry(self):
)
if closest_entry_gte is None or closest_entry_lte is None:
return closest_entry_gte or closest_entry_lte
if abs(closest_entry_gte.date - target) < abs(closest_entry_lte.date - target):
if abs(closest_entry_gte.date.date() - target) < abs(closest_entry_lte.date.date() - target):
return closest_entry_gte
else:
return closest_entry_lte
Expand Down
17 changes: 3 additions & 14 deletions wger/nutrition/tests/test_calories_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# Django
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils import timezone

# wger
from wger.core.tests.base_testcase import WgerTestCase
Expand Down Expand Up @@ -90,7 +91,7 @@ def test_automatic_weight_entry_bmr(self):
self.user_login('test')
user = User.objects.get(username=self.current_user)

# Existing weight entry is old, a new one is created
# A new weight entry is always created
entry1 = WeightEntry.objects.filter(user=user).latest()
response = self.client.post(
reverse('nutrition:calories:bmr'), {'age': 30, 'height': 180, 'gender': 1, 'weight': 80}
Expand All @@ -100,18 +101,6 @@ def test_automatic_weight_entry_bmr(self):
self.assertEqual(entry1.weight, 83)
self.assertEqual(entry2.weight, 80)

# Existing weight entry is from today, is updated
entry2.delete()
entry1.date = datetime.date.today()
entry1.save()
response = self.client.post(
reverse('nutrition:calories:bmr'), {'age': 30, 'height': 180, 'gender': 1, 'weight': 80}
)
self.assertEqual(response.status_code, 200)
entry2 = WeightEntry.objects.filter(user=user).latest()
self.assertEqual(entry1.pk, entry2.pk)
self.assertEqual(entry2.weight, 80)

# No existing entries
WeightEntry.objects.filter(user=user).delete()
response = self.client.post(
Expand All @@ -120,4 +109,4 @@ def test_automatic_weight_entry_bmr(self):
self.assertEqual(response.status_code, 200)
entry = WeightEntry.objects.filter(user=user).latest()
self.assertEqual(entry.weight, 80)
self.assertEqual(entry.date, datetime.date.today())
self.assertEqual(entry.date.date(), timezone.now().date())
14 changes: 14 additions & 0 deletions wger/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@
'%Y-%m-%d', # '2012-10-25'
]

# Valid datetime formats
DATETIME_FORMATS = [
'%d.%m.%Y %H:%M:%S', # '25.10.2012 14:30:00'
'%d.%m.%Y %H:%M', # '25.10.2012 14:30'
'%d.%m.%y %H:%M:%S', # '25.10.12 14:30:00'
'%d.%m.%y %H:%M', # '25.10.12 14:30'
'%m/%d/%Y %H:%M:%S', # '10/25/2012 14:30:00'
'%m/%d/%Y %H:%M', # '10/25/2012 14:30'
'%m/%d/%y %H:%M:%S', # '10/25/12 14:30:00'
'%m/%d/%y %H:%M', # '10/25/12 14:30'
'%Y-%m-%d %H:%M:%S', # '2012-10-25 14:30:00'
'%Y-%m-%d %H:%M', # '2012-10-25 14:30'
]

# Allowed tags, attributes and styles allowed in textareas edited with a JS
# editor. Everything not in these whitelists is stripped.
HTML_TAG_WHITELIST = {'b', 'i', 'strong', 'em', 'ul', 'ol', 'li', 'p'}
Expand Down
Loading