I'm trying to figure out the best / most efficient way to get the 'progress' of a Summary
object. A Summary
object has X Grade
objects - a Grade
object is_complete
when it has a Level
chosen and has 1 or more related Evidence
objects.
I am trying to tie that Summary
'progress' to a Person
.
The models.py
look like this:
class Summary(models.Model):
id = models.BigAutoField(primary_key=True)
person = models.ForeignKey(
Person, on_delete=models.PROTECT, related_name="summaries"
)
finalized = models.BooleanField(default=False)
class Meta:
verbose_name = "Summary"
verbose_name_plural = "Summaries"
def progress(self):
"""Return the progress of the summary."""
grades = self.grades.all()
finished_grades = (
Grade.complete.all().filter(summary=self).count()
)
try:
progress = (finished_grades / grades.count()) * 100
class Grade(models.Model):
id = models.BigAutoField(primary_key=True)
summary = models.ForeignKey(
Summary, on_delete=models.PROTECT, related_name="%(class)ss"
)
level = models.ForeignKey(
Level,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="%(class)ss",
)
class Meta:
verbose_name = "Grade"
verbose_name_plural = "Grades"
@property
def is_complete(self):
if 0 < self.evidences.count() and self.level:
return True
return False
class Evidence(models.Model):
id = models.BigAutoField(primary_key=True)
grade = models.ForeignKey(
Grade, on_delete=models.PROTECT, related_name="%(class)ss"
)
comment = models.TextField()
My views.py
looks like this:
class PersonListView(ListView):
model = Person
template_name = "app/person_list.html"
context_object_name = "person_list"
def get_queryset(self):
people = Person.objects.all().prefetch_related("summaries", "summaries__grades", "summaries__grades__evidences")
# There should only be one non-finalized summary
# or there will be None
first_summary = Summary.objects.filter(
person__id=OuterRef("id"), finalized=False
)
return people.annotate(
summary_progress=Subquery(first_summary[:1].progress()),
)
I'm trying to do this in as few queries as possible (I think with prefetch maybe 3-4 queries would be possible in total?)
In my template I'm trying to make it simple to get that so I can do something simple as I'm looping through the list of people:
<div class="progress">
{{ student.summary_progress }}
</div>
The code above doesn't work because I'm trying to annotate that .progress()
method onto the People
queryset. I can't seem to figure out the best way to accomplish it.