I have these model relationships
class ExerciseCategory(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, blank=True, null=True)
name = models.CharField(max_length=100)
class UserExercises(models.Model): #Through table for the many-to-many relationship between User and Exercise
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name="user")
exercise = models.ForeignKey('Exercise', on_delete=models.CASCADE)
class Exercise(models.Model):
category= models.ManyToManyField(ExerciseCategory, through='CategoryExercisesThrough',blank=True, null=True)
assignee = models.ManyToManyField(get_user_model(), blank=True, null=True, through=UserExercises, related_name="assignee", through_fields=('exercise', 'user'))
class CategoryExercisesThrough(models.Model): #Through table for the many-to-many relationship between ExerciseCategory and Exercise
category= models.ForeignKey(ExerciseCollections, on_delete=models.CASCADE)
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE)
I want to get all the UserExercises of a given user and then display them in my template grouped by category, so if I have: {Ex1: {category: ["C1", "C2"]}, Ex2: {category: "C2"}}
, I want them reordered like this: {"C1": ["Ex1"], "C2": ["Ex2", "Ex1"]}
I suggest to just post-process this manually, so:
from itertools import groupby
from operator import attrgetter
qs = (
UserExercises.objects.filter(user=request.user)
.annotate(category_id=F('exercise__category__pk'))
.order_by('category_id')
)
result = {k: list(vs) for k, vs in groupby(qs, attrgetter('category_id'))}
this will map the primary key of the ExerciseCategory
on to the list of UserExercises
s, you can further post-process it by fetching the categories as well:
categories = {ec.pk: ec for ec in ExerciseCategory.objects.filter(pk__in=result)}
result = {categories[k]: v for k, v in result.items()}
Note: normally a Django model is given a singular name, so
UserExercise
instead of.UserExercises
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.