Skip to content

Commit

Permalink
HB2-88 allow excluding activities from training model
Browse files Browse the repository at this point in the history
This still needs some UX love.
  • Loading branch information
sephii committed Nov 20, 2020
1 parent f2495da commit 3d2441c
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 134 deletions.
3 changes: 2 additions & 1 deletion assets/stylesheets/homebytwo.scss
Expand Up @@ -52,6 +52,7 @@
@import '../../node_modules/kanbasu/src/scss/helpers/display';
@import '../../node_modules/kanbasu/src/scss/helpers/align';
@import '../../node_modules/kanbasu/src/scss/helpers/align-responsive';
@import '../../node_modules/kanbasu/src/scss/helpers/flex';


/**
Expand Down Expand Up @@ -90,4 +91,4 @@
@import 'components/map';
@import 'components/masterhead';
@import 'components/nav';
@import 'components/routes';
@import 'components/routes';
18 changes: 18 additions & 0 deletions homebytwo/routes/migrations/0055_activity_use_for_training.py
@@ -0,0 +1,18 @@
# Generated by Django 2.2.17 on 2020-11-20 20:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('routes', '0054_fix_django_doctor_field_issues_'),
]

operations = [
migrations.AddField(
model_name='activity',
name='use_for_training',
field=models.BooleanField(default=True),
),
]
2 changes: 2 additions & 0 deletions homebytwo/routes/models/activity.py
Expand Up @@ -200,6 +200,8 @@ class Activity(TimeStampedModel):
related_name="activities",
)

use_for_training = models.BooleanField(default=True)

class Meta:
ordering = ["-start_date"]
verbose_name_plural = "activities"
Expand Down
3 changes: 2 additions & 1 deletion homebytwo/routes/tasks.py
Expand Up @@ -103,7 +103,8 @@ def train_prediction_models_task(athlete_id):

athlete = Athlete.objects.get(id=athlete_id)
activities = athlete.activities.filter(
activity_type__name__in=ActivityType.SUPPORTED_ACTIVITY_TYPES
activity_type__name__in=ActivityType.SUPPORTED_ACTIVITY_TYPES,
use_for_training=True,
)
activities = activities.order_by("activity_type")
activities = activities.distinct("activity_type")
Expand Down
36 changes: 35 additions & 1 deletion homebytwo/routes/views.py
Expand Up @@ -5,9 +5,10 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import BooleanField, Case, F, Value, When
from django.http import FileResponse, Http404, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.urls import reverse, reverse_lazy
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_safe
Expand Down Expand Up @@ -259,6 +260,39 @@ class ActivityList(ListView):
def get_queryset(self):
return Activity.objects.for_user(self.request.user)

def post(self, request):
self.object_list = self.get_queryset()
context_data = self.get_context_data()
page_activity_ids = context_data[
self.get_context_object_name(self.object_list)
].values_list("pk", flat=True)

use_for_training_ids = request.POST.getlist("use_for_training")
Activity.objects.for_user(self.request.user).filter(
pk__in=page_activity_ids
).annotate(
new_use_for_training=Case(
When(id__in=use_for_training_ids, then=True),
default=Value(False),
output_field=BooleanField(),
)
).update(
use_for_training=F("new_use_for_training")
)

train_prediction_models_task.delay(request.user.athlete.id)

activities_url = reverse("routes:activities")
page_number = context_data["page_obj"].number

redirect_url = (
activities_url
if page_number == 1
else activities_url + f"?page={page_number}"
)

return redirect(redirect_url)


@login_required
@strava_required # only the superuser can be logged-in without a Strava account
Expand Down
66 changes: 40 additions & 26 deletions homebytwo/templates/routes/activity_list.html
@@ -1,37 +1,51 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% load humanize duration %}

{% block title %}Home by Two - Strava Activities{% endblock %}

{% block content %}
<h1>Strava Activities</h1>
<ul class="list-stacked list-stacked--tight mrgb">
{% for activity in strava_activities %}
<li class="mrgb-">
<div>
<a class="strava" href="{{ activity.get_strava_url }}">
{{ activity.activity_type }}: {{ activity.name }}
</a>
</div>
<div>
{{ activity.start_date|naturalday }}
{% if activity.distance %}
- {{ activity.get_distance.km|floatformat:"01"|intcomma }}km
{% endif %}
{% if activity.total_elevation_gain %}
- {{ activity.get_total_elevation_gain.m|floatformat:"0"|intcomma }}m+
{% endif %}

{% if activity.moving_time %}
- {{ activity.moving_time|duration }}
{% endif %}
<div>
</li>
{% empty %}
<li>No activities yet.</li>
{% endfor %}
</ul>

<form method="post">
{% csrf_token %}
<ul class="list-stacked list-stacked--tight mrgb">
{% for activity in strava_activities %}
<li class="mrgb-">
<div class="flex">
<div class="flex-shrink mrgr-">
<input name="use_for_training" type="checkbox" value="{{ activity.pk }}"{% if activity.use_for_training %} checked{% endif %}>
</div>
<div class="flex-grow">
<div>
<a class="strava" href="{{ activity.get_strava_url }}">
{{ activity.activity_type }}: {{ activity.name }}
</a>
</div>
<div>
{{ activity.start_date|naturalday }}
{% if activity.distance %}
- {{ activity.get_distance.km|floatformat:"01"|intcomma }}km
{% endif %}
{% if activity.total_elevation_gain %}
- {{ activity.get_total_elevation_gain.m|floatformat:"0"|intcomma }}m+
{% endif %}

{% if activity.moving_time %}
- {{ activity.moving_time|duration }}
{% endif %}
</div>
</div>
</div>
</li>
{% empty %}
<li>No activities yet.</li>
{% endfor %}
</ul>

<button class="btn btn--primary">{% trans "Include (checked) / exclude (unchecked) activities from training model" %}</button>
</form>

<div class="pagination">
<span class="step-links">
Expand Down

0 comments on commit 3d2441c

Please sign in to comment.