Home > Enterprise >  Using CreateView with 2 Models at the same time
Using CreateView with 2 Models at the same time

Time:03-03

I am learning django. I am attempting to create a website that logs a user's workout. The user will be able to make premade workouts.

For each workout routine, there will be a workout name and it will consist of different exercises and the number of sets per exercise. In order to achieve this, I have created a custom through model so I can associate a number of sets to each exercise for that premade workout routine.

The trouble I am having is that in order to create a workout routine I need to use the WorkoutRoutine model in order to create a WorkoutRoutine object. Then I also need to use SetAmount in order to assign an exercise associated with a number of sets to the WorkoutRoutine.

Here is my models.py:

from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import MaxValueValidator, MinValueValidator

class WorkoutRoutine(models.Model):
    title = models.CharField(max_length=25)
    owner = models.ForeignKey(
            get_user_model(),
            on_delete=models.CASCADE,
            )
    exercise = models.ManyToManyField(
            'Exercise',
            through='SetAmount',
            related_name='workoutRoutines'
            )

    def __str__(self):
        return self.title


class Exercise(models.Model):
    name = models.CharField(max_length=25)

    def __str__(self):
        return self.name


class SetAmount(models.Model):
    workout_routine = models.ForeignKey(
            'WorkoutRoutine', 
            related_name='set_amounts',
            on_delete=models.CASCADE, null=True
            )
    exercise = models.ForeignKey(
            'Exercise', 
            related_name='set_amounts', 
            on_delete=models.SET_NULL, 
            null=True, 
            blank=True
            )
    set_amount = models.IntegerField(
            default=0,
            validators=[
                MaxValueValidator(100),
                MinValueValidator(0),
                ]
            )

    def __str__(self):
        return str(self.set_amount)

Here is my views.py:

from django.shortcuts import render
from django.views.generic import ListView, CreateView
from .models import WorkoutRoutine

class WorkoutRoutineListView(ListView):
    model = WorkoutRoutine 
    template_name = 'workout_routines.html'

class WorkoutCreateView(CreateView):
    model = WorkoutRoutine
    template_name = 'workout_creation.html'
    fields = ('title','exercise',)

Is there a way I can edit WorkoutCreateView(CreateView) in order to allow what I am trying to do? Or should I be building a function to achieve what I am trying to do?

CodePudding user response:

You should override the form_valid() method of CreateView. This is called if, well, your form is valid. Then you can create your SetAmount instance there.

def form_valid(self, form):
    # Easy way to obtain the through model (aka SetAmount)
    SetAmount = WorkoutRoutine.exercise.through
    # Assuming the exercise is selected in the form
    exercise = form.cleaned_data['exercise']
    # Create a SetAmount instance with the correct workout_routine and exercise from the form
    SetAmount.objects.create(
        workout_routine=form.instance,
        exercise=exercise,
        set_amount=100 # Swole
    )
    return super().form_valid(form)
  • Related