def create(request, day_pk): """ Creates a new set. This view handles both the set form and the corresponding settings formsets """ day = get_object_or_404(Day, pk=day_pk) if day.get_owner_object().user != request.user: return HttpResponseForbidden() context = {} formsets = [] form = SetForm(initial={'sets': Set.DEFAULT_SETS}) # If the form and all formsets validate, save them if request.method == "POST": form = SetForm(request.POST) if form.is_valid(): for exercise in form.cleaned_data['exercises']: formset = SettingFormset(request.POST, queryset=Setting.objects.none(), prefix='exercise{0}'.format( exercise.id)) formsets.append({'exercise': exercise, 'formset': formset}) all_valid = True for formset in formsets: if not formset['formset'].is_valid(): all_valid = False if form.is_valid() and all_valid: # Manually take care of the order, TODO: better move this to the model max_order = day.set_set.select_related().aggregate( models.Max('order')) form.instance.order = (max_order['order__max'] or 0) + 1 form.instance.exerciseday = day set_obj = form.save() order = 1 for formset in formsets: instances = formset['formset'].save(commit=False) for instance in instances: instance.set = set_obj instance.order = order instance.exercise = formset['exercise'] instance.save() order += 1 return HttpResponseRedirect( reverse('manager:workout:view', kwargs={'pk': day.get_owner_object().id})) else: logger.debug(form.errors) # Other context we need context['form'] = form context['day'] = day context['max_sets'] = Set.MAX_SETS context['formsets'] = formsets context['helper'] = WorkoutLogFormHelper() return render(request, 'set/add.html', context)
def edit(request, pk): """ Edit a set (its settings actually) """ set_obj = get_object_or_404(Set, pk=pk) if set_obj.get_owner_object().user != request.user: return HttpResponseForbidden() formsets = [] for exercise in set_obj.exercises: queryset = Setting.objects.filter(set=set_obj, exercise=exercise) formset = SettingFormset(queryset=queryset, prefix='exercise{0}'.format(exercise.id)) formsets.append({'exercise': exercise, 'formset': formset}) if request.method == "POST": formsets = [] for exercise in set_obj.exercises: formset = SettingFormset(request.POST, prefix='exercise{0}'.format(exercise.id)) formsets.append({'exercise': exercise, 'formset': formset}) # If all formsets validate, save them all_valid = True for formset in formsets: if not formset['formset'].is_valid(): all_valid = False if all_valid: for formset in formsets: instances = formset['formset'].save(commit=False) for instance in instances: # If the setting has already a set, we are editing... try: instance.set # Check that we are allowed to do this if instance.get_owner_object().user != request.user: return HttpResponseForbidden() instance.save() # ...if not, create a new setting except ObjectDoesNotExist: instance.set = set_obj instance.order = 1 instance.exercise = formset['exercise'] instance.save() return HttpResponseRedirect( reverse('manager:workout:view', kwargs={'pk': set_obj.get_owner_object().id})) # Other context we need context = {} context['formsets'] = formsets context['helper'] = WorkoutLogFormHelper() return render(request, 'set/edit.html', context)
def edit(request, pk): """ Edit a set (its settings actually) """ set_obj = get_object_or_404(Set, pk=pk) if set_obj.get_owner_object().user != request.user: return HttpResponseForbidden() SettingFormsetEdit = modelformset_factory(Setting, form=SettingForm, fields=SETTING_FORMSET_FIELDS + ('id', ), can_delete=False, can_order=True, extra=0) formsets = [] for exercise in set_obj.exercises: queryset = Setting.objects.filter(set=set_obj, exercise=exercise) formset = SettingFormsetEdit(queryset=queryset, prefix='exercise{0}'.format(exercise.id)) formsets.append({'exercise': exercise, 'formset': formset}) if request.method == "POST": formsets = [] for exercise in set_obj.exercises: formset = SettingFormsetEdit(request.POST, prefix='exercise{0}'.format( exercise.id)) formsets.append({'exercise': exercise, 'formset': formset}) # If all formsets validate, save them all_valid = True for formset in formsets: if not formset['formset'].is_valid(): all_valid = False if all_valid: for formset in formsets: instances = formset['formset'].save(commit=False) for instance in instances: # Double check that we are allowed to edit the set if instance.get_owner_object().user != request.user: return HttpResponseForbidden() instance.save() return HttpResponseRedirect( reverse('manager:workout:view', kwargs={'pk': set_obj.get_owner_object().id})) # Other context we need context = {'formsets': formsets, 'helper': WorkoutLogFormHelper()} return render(request, 'set/edit.html', context)
def get_formset(request, exercise_pk, reps=Set.DEFAULT_SETS): """ Returns a formset. This is then rendered inside the new set template """ exercise = Exercise.objects.get(pk=exercise_pk) SettingFormSet = inlineformset_factory(Set, Setting, can_delete=False, extra=int(reps), fields=SETTING_FORMSET_FIELDS) formset = SettingFormSet(queryset=Setting.objects.none(), prefix='exercise{0}'.format(exercise_pk)) context = { 'formset': formset, 'helper': WorkoutLogFormHelper(), 'exercise': exercise } return render(request, "set/formset.html", context)
def add(request, pk): """ Add a new workout log """ # NOTE: This function is waaaay too complex and convoluted. While updating # to crispy forms, the template logic could be reduced a lot, but # there is still a lot optimisations that could happen here. # Load the day and check ownership day = get_object_or_404(Day, pk=pk) if day.get_owner_object().user != request.user: return HttpResponseForbidden() # We need several lists here because we need to assign specific form to each # exercise: the entries for weight and repetitions have no indicator to which # exercise they belong besides the form-ID, from Django's formset counter = 0 total_sets = 0 exercise_list = {} form_to_exercise = {} for exercise_set in day.set_set.all(): for exercise in exercise_set.exercises.all(): # Maximum possible values total_sets += int(exercise_set.sets) counter_before = counter counter = counter + int(exercise_set.sets) - 1 form_id_range = range(counter_before, counter + 1) # Add to list exercise_list[exercise.id] = { 'obj': exercise, 'sets': int(exercise_set.sets), 'form_ids': form_id_range } counter += 1 # Helper mapping form-ID <--> Exercise for id in form_id_range: form_to_exercise[id] = exercise # Define the formset here because now we know the value to pass to 'extra' WorkoutLogFormSet = modelformset_factory(WorkoutLog, form=WorkoutLogForm, exclude=('date', 'workout'), extra=total_sets) # Process the request if request.method == 'POST': # Make a copy of the POST data and go through it. The reason for this is # that the form expects a value for the exercise which is not present in # the form (for space and usability reasons) post_copy = request.POST.copy() for form_id in form_to_exercise: if post_copy.get('form-%s-weight' % form_id) or post_copy.get( 'form-%s-reps' % form_id): post_copy['form-%s-exercise' % form_id] = form_to_exercise[form_id].id # Pass the new data to the forms formset = WorkoutLogFormSet(data=post_copy) session_form = HelperWorkoutSessionForm(data=post_copy) # If all the data is valid, save and redirect to log overview page if session_form.is_valid() and formset.is_valid(): log_date = session_form.cleaned_data['date'] if WorkoutSession.objects.filter(user=request.user, date=log_date).exists(): session = WorkoutSession.objects.get(user=request.user, date=log_date) session_form = HelperWorkoutSessionForm(data=post_copy, instance=session) # Save the Workout Session only if there is not already one for this date instance = session_form.save(commit=False) if not WorkoutSession.objects.filter(user=request.user, date=log_date).exists(): instance.date = log_date instance.user = request.user instance.workout = day.training else: session = WorkoutSession.objects.get(user=request.user, date=log_date) instance.instance = session instance.save() # Log entries (only the ones with actual content) instances = [i for i in formset.save(commit=False) if i.reps] for instance in instances: if not instance.weight: instance.weight = 0 instance.user = request.user instance.workout = day.training instance.date = log_date instance.save() return HttpResponseRedirect( reverse('manager:log:log', kwargs={'pk': day.training_id})) else: # Initialise the formset with a queryset that won't return any objects # (we only add new logs here and that seems to be the fastest way) user_weight_unit = 1 if request.user.userprofile.use_metric else 2 formset = WorkoutLogFormSet(queryset=WorkoutLog.objects.none(), initial=[{ 'weight_unit': user_weight_unit, 'repetition_unit': 1 } for x in range(0, total_sets)]) # Depending on whether there is already a workout session for today, update # the current one or create a new one (this will be the most usual case) if WorkoutSession.objects.filter(user=request.user, date=datetime.date.today()).exists(): session = WorkoutSession.objects.get(user=request.user, date=datetime.date.today()) session_form = HelperWorkoutSessionForm(instance=session) else: session_form = HelperWorkoutSessionForm() # Pass the correct forms to the exercise list for exercise in exercise_list: form_id_from = min(exercise_list[exercise]['form_ids']) form_id_to = max(exercise_list[exercise]['form_ids']) exercise_list[exercise]['forms'] = formset[form_id_from:form_id_to + 1] context = {} context['day'] = day context['exercises'] = exercise_list context['formset'] = formset context['helper'] = WorkoutLogFormHelper() context['session_form'] = session_form context['form'] = session_form context['extend_template'] = 'base.html' context['form_action'] = request.path return render(request, 'log/add.html', context)