0

In my Django appliations, I have four models, Exercise, Workout, Target, and TargetExerciseSet. Here are the models below along with my current Workout View and patch request function. The patch request is only done when a workout is completed. I have created a new model, Log (also shown below), to store each instance of a workout. My current problem here is that Object { error: "Object of type ImageFieldFile is not JSON serializable" } workout.component.ts:359:16. I have tried to workout with ChatGPT, and they are suggesting to create new tables for completed workouts, but this wont work because the database is only so big. So my question, each time a workout is completed, what would be the best way to save this data?

I have tried just trying to save the exercise name and image in a json, but by time I try to view the data on my frontend application, the image url is expired. I know I can just save the exercise id, then do a request to get the exercises by ID, but I don't want to keep calling to the backend. (I know I can do one request with all the exercises). Any help will be appreciated.

class Exercise(models.Model):
    BODYPART_CHOICES = (
        ('Abs', 'Abs'), ('Ankle', 'Ankle'),
        ('Back', 'Back'), ('Biceps', 'Biceps'),
        ('Cervical', 'Cervical'), ('Chest', 'Chest'), ('Combo', 'Combo'),
        ('Forearms', 'Forearms'), ('Full Body', 'Full Body'),
        ('Hip', 'Hip'),
        ('Knee', 'Knee'),
        ('Legs', 'Legs'), ('Lower Back', 'Lower Back'), ('Lumbar', 'Lumbar'),
        ('Neck', 'Neck'),
        ('Shoulders', 'Shoulders'),
        ('Thoracic', 'Thoracic'), ('Triceps', 'Triceps'),
        ('Wrist', 'Wrist'),
    )

    CATEGORY_CHOICES = (
        ('Cardio', 'Cardio'),
        ('Stability', 'Stability'),
        ('Flexibility', 'Flexibility'),
        ('Hotel', 'Hotel'),
        ('Pilates', 'Pilates'), ('Power', 'Power'),
        ('Strength', 'Strength'),
        ('Yoga', 'Yoga'),
        ('Goals & More', 'Goals & More'),
        ('Activities', 'Activities'),
        ('Rehabilitation', 'Rehabilitation'),
        ('Myofascial', 'Myofascial')
    )

    EQUIPMENT_CHOICES = (
        ('Airex', 'Airex'),
        ('BOSU', 'BOSU'), ('Barbell', 'Barbell'), ('Battle Rope', 'BattleRope'), ('Bodyweight', 'Bodyweight'),('Bands', 'Bands'),
        ('Cables', 'Cables'), ('Cones', 'Cones'),
        ('Dumbbells', 'Dumbbells'), ('Dyna Disk', 'Dyna Disk'),
        ('Foam Roller', 'Foam Roller'),
        ('Kettlebells', 'Kettlebells'),
        ('Leg Weights', 'Leg Weights'),
        ('Machine', 'Machine'), ('Medicine Ball', 'Medicine Ball'),
        ('Plate', 'Plate'), ('Power Wheel', 'Power Wheel'),
        ('Ring', 'Ring'),
        ('Sandbag', 'Sandbag'), ('Stick', 'Stick'), ('Strap', 'Strap'), ('Suspension', 'Suspension'), ('Swiss Ball', 'Swiss Ball'),
        ('Theraball', 'Theraball'), ('Towel', 'Towel'), ('Tubbing', 'Tubbing'),
        ('Wobble Board', 'Wobble Board'),
    )

    name = models.CharField(max_length=200)
    photograph = models.ImageField(null=True, upload_to=exercise_image_file_path)
    body_part = models.CharField(max_length=50, choices=BODYPART_CHOICES)
    equipment = models.CharField(max_length=200, choices=EQUIPMENT_CHOICES)
    equipment_two = models.CharField(max_length=200, choices=EQUIPMENT_CHOICES, blank=True, null=True)
    category = models.CharField(max_length=100, choices=CATEGORY_CHOICES)
    workout_tip = models.TextField(max_length=3000, blank=True)
    cmf_url = models.URLField(max_length=400, blank=True)
    vimeo_exercise_id = models.CharField(max_length=25, blank=True)
    # exercise_id =  models.UUIDField(default=uuid.uuid4, unique=True,primary_key=True, editable=False)

    def __str__(self):
        return self.name
    
    def to_list(self):
        return {
            "name": self.name if self.name else '',
            "photograph": self.photograph if self.photograph else '',
            "body_part": self.body_part if self.body_part else '',
            "equipment": self.equipment if self.equipment else '',
            "equipment_two": self.equipment_two if self.equipment_two else '',
            "category": self.category if self.category else '',
            "workout_tip": self.workout_tip if self.workout_tip else '',
            "cmf_url": self.cmf_url if self.cmf_url else '',
            "vimeo_exercise_id": self.vimeo_exercise_id if self.vimeo_exercise_id else '',
        }

class Workout(models.Model):
    GOALS_CHOICES = (
        ('None', 'None'),
        ('Abs', 'Abs'), ('Arms', 'Arms'),
        ('Cardio', 'Cardio'), ('Core', 'Core'),
        ('Endurance', 'Endurance'),
        ('Flexibility', 'Flexibility'), ('Full Body', 'Full Body'),
        ('Legs', 'Legs'), ('Lower Body', 'Lower Body'),
        ('Power', 'Power'),
        ('Shoulders', 'Shoulders'), ('Sport Conditioning', 'Sport Conditioning'), ('Stability', 'Stability'), ('Strength', 'Strength'),
        ('Toning', 'Toning'),
        ('Upper Body', 'Upper Body'),
        ('Weight Loss', 'Weight Loss')
    )

    exercises = models.ManyToManyField(Exercise, through='Targets')
    name = models.CharField(max_length=200, blank=True)
    profile = models.ForeignKey(Profile, on_delete=SET_NULL,null=True, blank=True, related_name='workouts')
    description = models.TextField(max_length=3000, blank=True)
    goals = models.CharField(max_length=25, choices=GOALS_CHOICES, default='None')
    workout_time = models.CharField(max_length=200, blank=True)
    difficulty = models.CharField(max_length=10,blank=True)
    status = models.CharField(max_length=15, default='Created')
    created = models.DateField(auto_now_add=timezone.now())
    assigned = models.DateField(blank=True, null=True)
    completed = models.DateField(blank=True, null=True)
    time = models.CharField(max_length=100, blank=True, null=True)
    rating = models.IntegerField(default=0, blank=True, null=True,
                                    validators=[MaxValueValidator(5),
                                    MinValueValidator(0)])
    overall_note = models.CharField(max_length=200, blank=True, null=True)
    favorite = models.BooleanField(default=False)

    def __str__(self):
        return self.name
class Targets(models.Model):
    EXERCISE_SET_CHOICES = (
        ('Set', 'Set'),
        ('Superset', 'Superset'),
        ('Triple Set', 'Triple Set'),
        ('Quad Set', 'Quad Set'),
        ('Dropset', 'Dropset'),
        ('Circuit', 'Circuit'),
        ('Pyramid', 'Pyramid'),
        ('Interval', 'Interval'),
        ('Tabata', 'Tabata'),
    )
    WEIGHT_CHOICES = (
        ('Bodyweight', 'Bodyweight'),
        ('Pounds', 'Pounds'),
    )
    REPS_CHOICES = (
        ('Reps', 'Reps'), ('Secs','Secs')
    )

    workout = models.ForeignKey(Workout, on_delete=models.CASCADE, null=False, related_name='targets')
    exercises = models.ForeignKey(Exercise, on_delete=models.CASCADE, null=False)
    sets = models.CharField(max_length=20,blank=True)
    exercise_set = models.CharField(max_length=20, choices=EXERCISE_SET_CHOICES, default='Set')
    reps = models.CharField(max_length=20, blank=True)
    reps_choice = models.CharField(max_length=10, default='Reps', choices=REPS_CHOICES)
    rest = models.CharField(max_length=20, blank=True)
    exercise_notes = models.TextField(max_length=3000,blank=True )
    weight = models.CharField(max_length=20,blank=True)
    weight_measurements = models.CharField(max_length=20, choices=WEIGHT_CHOICES, default='Bodyweight')
    client_notes = models.TextField(max_length=3000, blank=True)
    # target_exercise_set = models.One(TargetExerciseSet, on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return '{} {}'.format(self.workout.name, self.exercises.name)
    
class TargetExerciseSet(models.Model):
    REPS_CHOICES = (
        ('Reps', 'Reps'), ('Secs','Secs')
    )
    reps = models.CharField(max_length=5, blank=True)
    reps_choice = models.CharField(max_length=10, default='Reps', choices=REPS_CHOICES)
    rest = models.CharField(max_length=20, blank=True)
    trainer_note = models.TextField(max_length=150,blank=True)
    weight = models.CharField(max_length=5,blank=True)
    target = models.ForeignKey(Targets, on_delete=models.CASCADE, null=True, blank=True)

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

Here is my workout view with my current patch request:

class WorkoutRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Workout.objects.all().order_by('-id')
    serializer_class = WorkoutSerializer
    authentication_classes = [authentication.TokenAuthentication]
    permission_classes = [permissions.IsAuthenticated]
    lookup_field = 'pk'
    depth=2

    def patch(self, request, pk):
        """Overriding the patch request when a workout is completed."""
        try: 
            weights_data = []
            updated_targets = request.data.pop('targets')
            updated_workout = request.data
            workout_instance = Workout.objects.get(id=pk)
            workoutSerializer = WorkoutSerializer(workout_instance, updated_workout, partial=True)
            workoutSerializer.is_valid(raise_exception=True)
            updated_workout_instance = workoutSerializer.save()
            
            for updated_target in updated_targets:
                updated_sets = updated_target.pop('targetexerciseset_set')
                target = Targets.objects.get(id=updated_target['id'])
                targetSerializer = TargetSerializer(target, updated_target, partial=True)
                targetSerializer.is_valid(raise_exception=True)
                target_instance = targetSerializer.save(workout=workout_instance)

                weights_data.append({
                    "exercise": target_instance.exercises.to_list(),
                    "weights": [
                        updated_set.get('weight', '' ) for updated_set in updated_sets
                    ],
                    "rest": [
                        updated_set.get('rest', '') for updated_set in updated_sets
                    ]
                })

                for updated_set in updated_sets:
                    set_instance = TargetExerciseSet.objects.get(id=updated_set['id']) if 'id' in updated_set else None
                    serializer = SetSerializer(set_instance, data=updated_set, partial=True)
                    serializer.is_valid(raise_exception=True)
                    serializer.save(target=target_instance)
                
            # Create Logs
            
            log_instance = Log.objects.create(
                date_completed = updated_workout_instance.completed,
                client_note = updated_workout_instance.overall_note,
                time = updated_workout_instance.time,
            )

            log_instance.save_weights_data(weights_data=weights_data)
            log_instance.workout = Workout.objects.get(id=updated_workout_instance.id)
            log_instance.save()
            
            return Response(status=status.HTTP_200_OK)
        
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)

0